802.11 patch
Andrew Atrens
atrens at nortel.com
Thu Nov 24 10:22:07 PST 2005
brings in new 802.11 stack from FreeBSD-current
diff -N -u -r src.preview/sbin/ifconfig/Makefile src/sbin/ifconfig/Makefile
--- src.preview/sbin/ifconfig/Makefile 2005-03-03 21:29:19.000000000 -0500
+++ src/sbin/ifconfig/Makefile 2005-09-27 15:02:10.000000000 -0400
@@ -1,25 +1,31 @@
# From: @(#)Makefile 8.1 (Berkeley) 6/5/93
-# $FreeBSD: src/sbin/ifconfig/Makefile,v 1.14.2.7 2002/02/15 03:58:37 luigi Exp $
-# $DragonFly: src/sbin/ifconfig/Makefile,v 1.3 2005/03/04 02:29:19 cpressey Exp $
+# $FreeBSD$
PROG= ifconfig
WARNS?= 6
-SRCS= ifconfig.c
-
-#comment out to exclude SIOC[GS]IFMEDIA support
-SRCS+= ifmedia.c
-CFLAGS+=-DUSE_IF_MEDIA
-CFLAGS+=-DINET6
-
-#comment out to exclude SIOC[GS]ETVLAN support
-SRCS+= ifvlan.c
-CFLAGS+=-DUSE_VLANS
-
-#comment out to exclude SIOC[GS]IEEE80211 support
-SRCS+= ifieee80211.c
-CFLAGS+=-DUSE_IEEE80211
+SRCS= ifconfig.c # base support
MAN= ifconfig.8
+#
+# NB: The order here defines the order in which the constructors
+# are called. This in turn defines the default order in which
+# status is displayed. Probably should add a priority mechanism
+# to the registration process so we don't depend on this aspect
+# of the toolchain.
+#
+SRCS+= af_link.c # LLC support
+SRCS+= af_inet.c # IPv4 support
+SRCS+= af_inet6.c # IPv6 support
+SRCS+= af_atalk.c # AppleTalk support
+
+SRCS+= ifclone.c # clone device support
+# SRCS+= ifmac.c # MAC support
+SRCS+= ifmedia.c # SIOC[GS]IFMEDIA support
+SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
+SRCS+= ifieee80211.c # SIOC[GS]IEEE80211 support
+
+#SRCS+= ifcarp.c # SIOC[GS]VH support
+#SRCS+= ifpfsync.c # pfsync(4) support
.if defined(RELEASE_CRUNCH)
CFLAGS+=-DNO_IPX
diff -N -u -r src.preview/sbin/ifconfig/af_atalk.c src/sbin/ifconfig/af_atalk.c
--- src.preview/sbin/ifconfig/af_atalk.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_atalk.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h> /* for RTX_IFA */
+
+#include <netatalk/at.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include "ifconfig.h"
+
+static struct netrange at_nr; /* AppleTalk net range */
+static struct ifaliasreq at_addreq;
+
+/* XXX FIXME -- should use strtoul for better parsing. */
+static void
+setatrange(const char *range, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ u_int first = 123, last = 123;
+
+ if (sscanf(range, "%u-%u", &first, &last) != 2
+ || first == 0 || first > 0xffff
+ || last == 0 || last > 0xffff || first > last)
+ errx(1, "%s: illegal net range: %u-%u", range, first, last);
+ at_nr.nr_firstnet = htons(first);
+ at_nr.nr_lastnet = htons(last);
+}
+
+static void
+setatphase(const char *phase, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (!strcmp(phase, "1"))
+ at_nr.nr_phase = 1;
+ else if (!strcmp(phase, "2"))
+ at_nr.nr_phase = 2;
+ else
+ errx(1, "%s: illegal phase", phase);
+}
+
+static void
+at_status(int s __unused, const struct rt_addrinfo * info)
+{
+ struct sockaddr_at *sat, null_sat;
+ struct netrange *nr;
+
+ memset(&null_sat, 0, sizeof(null_sat));
+
+ sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
+ if (sat == NULL)
+ return;
+ nr = &sat->sat_range.r_netrange;
+ printf("\tatalk %d.%d range %d-%d phase %d",
+ ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
+ ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
+ if (flags & IFF_POINTOPOINT) {
+ /* note RTAX_BRD overlap with IFF_BROADCAST */
+ sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
+ if (!sat)
+ sat = &null_sat;
+ printf("--> %d.%d",
+ ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
+ }
+ if (flags & IFF_BROADCAST) {
+ /* note RTAX_BRD overlap with IFF_POINTOPOINT */
+ sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
+ if (sat)
+ printf(" broadcast %d.%d",
+ ntohs(sat->sat_addr.s_net),
+ sat->sat_addr.s_node);
+ }
+
+ putchar('\n');
+}
+
+static void
+at_getaddr(const char *addr, int which)
+{
+ struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
+ u_int net, node;
+
+ sat->sat_family = AF_APPLETALK;
+ sat->sat_len = sizeof(*sat);
+ if (which == MASK)
+ errx(1, "AppleTalk does not use netmasks");
+ if (sscanf(addr, "%u.%u", &net, &node) != 2
+ || net > 0xffff || node > 0xfe)
+ errx(1, "%s: illegal address", addr);
+ sat->sat_addr.s_net = htons(net);
+ sat->sat_addr.s_node = node;
+}
+
+static void
+at_postproc(int s, const struct afswtch *afp)
+{
+ struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
+
+ if (at_nr.nr_phase == 0)
+ at_nr.nr_phase = 2; /* Default phase 2 */
+ if (at_nr.nr_firstnet == 0)
+ at_nr.nr_firstnet = /* Default range of one */
+ at_nr.nr_lastnet = sat->sat_addr.s_net;
+ printf("\tatalk %d.%d range %d-%d phase %d\n",
+ ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
+ ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet),
+ at_nr.nr_phase);
+ if ((u_short) ntohs(at_nr.nr_firstnet) >
+ (u_short) ntohs(sat->sat_addr.s_net)
+ || (u_short) ntohs(at_nr.nr_lastnet) <
+ (u_short) ntohs(sat->sat_addr.s_net))
+ errx(1, "AppleTalk address is not in range");
+ sat->sat_range.r_netrange = at_nr;
+}
+
+static struct cmd atalk_cmds[] = {
+ DEF_CMD_ARG("range", setatrange),
+ DEF_CMD_ARG("phase", setatphase),
+};
+
+static struct afswtch af_atalk = {
+ .af_name = "atalk",
+ .af_af = AF_APPLETALK,
+ .af_status = at_status,
+ .af_getaddr = at_getaddr,
+ .af_postproc = at_postproc,
+ .af_difaddr = SIOCDIFADDR,
+ .af_aifaddr = SIOCAIFADDR,
+ .af_ridreq = &at_addreq,
+ .af_addreq = &at_addreq,
+};
+
+static __constructor void
+atalk_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(atalk_cmds); i++)
+ cmd_register(&atalk_cmds[i]);
+ af_register(&af_atalk);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/af_inet.c src/sbin/ifconfig/af_inet.c
--- src.preview/sbin/ifconfig/af_inet.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_inet.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h> /* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h> /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq in_addreq;
+static struct ifreq in_ridreq;
+
+static void
+in_status(int s __unused, const struct rt_addrinfo * info)
+{
+ struct sockaddr_in *sin, null_sin;
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
+ if (sin == NULL)
+ return;
+
+ printf("\tinet %s ", inet_ntoa(sin->sin_addr));
+
+ if (flags & IFF_POINTOPOINT) {
+ /* note RTAX_BRD overlap with IFF_BROADCAST */
+ sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
+ if (!sin)
+ sin = &null_sin;
+ printf("--> %s ", inet_ntoa(sin->sin_addr));
+ }
+
+ sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
+ if (!sin)
+ sin = &null_sin;
+ printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
+
+ if (flags & IFF_BROADCAST) {
+ /* note RTAX_BRD overlap with IFF_POINTOPOINT */
+ sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
+ if (sin && sin->sin_addr.s_addr != 0)
+ printf("broadcast %s", inet_ntoa(sin->sin_addr));
+ }
+ putchar('\n');
+}
+
+#define SIN(x) ((struct sockaddr_in *) &(x))
+static struct sockaddr_in *sintab[] = {
+ SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
+ SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
+};
+
+static void
+in_getaddr(const char *s, int which)
+{
+#define MIN(a,b) ((a)<(b)?(a):(b))
+ struct sockaddr_in *sin = sintab[which];
+ struct hostent *hp;
+ struct netent *np;
+
+ sin->sin_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin_family = AF_INET;
+
+ if (which == ADDR) {
+ char *p = NULL;
+
+ if((p = strrchr(s, '/')) != NULL) {
+ /* address is `name/masklen' */
+ int masklen;
+ int ret;
+ struct sockaddr_in *min = sintab[MASK];
+ *p = '\0';
+ ret = sscanf(p+1, "%u", &masklen);
+ if(ret != 1 || (masklen < 0 || masklen > 32)) {
+ *p = '/';
+ errx(1, "%s: bad value", s);
+ }
+ min->sin_len = sizeof(*min);
+ min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) &
+ 0xffffffff);
+ }
+ }
+
+ if (inet_aton(s, &sin->sin_addr))
+ return;
+ if ((hp = gethostbyname(s)) != 0)
+ bcopy(hp->h_addr, (char *)&sin->sin_addr,
+ MIN(hp->h_length, sizeof(sin->sin_addr)));
+ else if ((np = getnetbyname(s)) != 0)
+ sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
+ else
+ errx(1, "%s: bad value", s);
+#undef MIN
+}
+
+static void
+in_status_tunnel(int s)
+{
+ char src[NI_MAXHOST];
+ char dst[NI_MAXHOST];
+ struct ifreq ifr;
+ const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+ if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
+ return;
+ if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0)
+ src[0] = '\0';
+
+ if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0)
+ return;
+ if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0)
+ dst[0] = '\0';
+
+ printf("\ttunnel inet %s --> %s\n", src, dst);
+}
+
+static void
+in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+ struct ifaliasreq addreq;
+
+ memset(&addreq, 0, sizeof(addreq));
+ strncpy(addreq.ifra_name, name, IFNAMSIZ);
+ memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+ memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
+
+ if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0)
+ warn("SIOCSIFPHYADDR");
+}
+
+static struct afswtch af_inet = {
+ .af_name = "inet",
+ .af_af = AF_INET,
+ .af_status = in_status,
+ .af_getaddr = in_getaddr,
+ .af_status_tunnel = in_status_tunnel,
+ .af_settunnel = in_set_tunnel,
+ .af_difaddr = SIOCDIFADDR,
+ .af_aifaddr = SIOCAIFADDR,
+ .af_ridreq = &in_ridreq,
+ .af_addreq = &in_addreq,
+};
+
+static __constructor void
+inet_ctor(void)
+{
+ af_register(&af_inet);
+}
diff -N -u -r src.preview/sbin/ifconfig/af_inet6.c src/sbin/ifconfig/af_inet6.c
--- src.preview/sbin/ifconfig/af_inet6.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_inet6.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h> /* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h> /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
+
+#include "ifconfig.h"
+
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
+static struct in6_ifreq in6_ridreq;
+static struct in6_aliasreq in6_addreq =
+ { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ 0,
+ { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
+static int ip6lifetime;
+
+static void in6_fillscopeid(struct sockaddr_in6 *sin6);
+static int prefix(void *, int);
+static char *sec2str(time_t);
+static int explicit_prefix = 0;
+
+static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
+
+static void
+setifprefixlen(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getprefix != NULL)
+ afp->af_getprefix(addr, MASK);
+ explicit_prefix = 1;
+}
+
+static void
+setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
+ const struct afswtch *afp)
+{
+ if (afp->af_af != AF_INET6)
+ err(1, "address flags can be set only for inet6 addresses");
+
+ if (flag < 0)
+ in6_addreq.ifra_flags &= ~(-flag);
+ else
+ in6_addreq.ifra_flags |= flag;
+}
+
+static void
+setip6lifetime(const char *cmd, const char *val, int s,
+ const struct afswtch *afp)
+{
+ time_t newval, t;
+ char *ep;
+
+ t = time(NULL);
+ newval = (time_t)strtoul(val, &ep, 0);
+ if (val == ep)
+ errx(1, "invalid %s", cmd);
+ if (afp->af_af != AF_INET6)
+ errx(1, "%s not allowed for the AF", cmd);
+ if (strcmp(cmd, "vltime") == 0) {
+ in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_vltime = newval;
+ } else if (strcmp(cmd, "pltime") == 0) {
+ in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+ }
+}
+
+static void
+setip6pltime(const char *seconds, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ setip6lifetime("pltime", seconds, s, afp);
+}
+
+static void
+setip6vltime(const char *seconds, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ setip6lifetime("vltime", seconds, s, afp);
+}
+
+static void
+setip6eui64(const char *cmd, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ struct ifaddrs *ifap, *ifa;
+ const struct sockaddr_in6 *sin6 = NULL;
+ const struct in6_addr *lladdr = NULL;
+ struct in6_addr *in6;
+
+ if (afp->af_af != AF_INET6)
+ errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
+ in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
+ if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
+ errx(EXIT_FAILURE, "interface index is already filled");
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ strcmp(ifa->ifa_name, name) == 0) {
+ sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ lladdr = &sin6->sin6_addr;
+ break;
+ }
+ }
+ }
+ if (!lladdr)
+ errx(EXIT_FAILURE, "could not determine link local address");
+
+ memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
+
+ freeifaddrs(ifap);
+}
+
+static void
+in6_fillscopeid(struct sockaddr_in6 *sin6)
+{
+#if defined(__KAME__) && defined(KAME_SCOPEID)
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ sin6->sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
+ sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+}
+
+static void
+in6_status(int s __unused, const struct rt_addrinfo * info)
+{
+ struct sockaddr_in6 *sin, null_sin;
+ struct in6_ifreq ifr6;
+ int s6;
+ u_int32_t flags6;
+ struct in6_addrlifetime lifetime;
+ time_t t = time(NULL);
+ int error;
+ u_int32_t scopeid;
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
+ if (sin == NULL)
+ return;
+
+ strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warn("socket(AF_INET6,SOCK_DGRAM)");
+ return;
+ }
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ warn("ioctl(SIOCGIFAFLAG_IN6)");
+ close(s6);
+ return;
+ }
+ flags6 = ifr6.ifr_ifru.ifru_flags6;
+ memset(&lifetime, 0, sizeof(lifetime));
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
+ warn("ioctl(SIOCGIFALIFETIME_IN6)");
+ close(s6);
+ return;
+ }
+ lifetime = ifr6.ifr_ifru.ifru_lifetime;
+ close(s6);
+
+ /* XXX: embedded link local addr check */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+ *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+ u_short index;
+
+ index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+ *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = ntohs(index);
+ }
+ scopeid = sin->sin6_scope_id;
+
+ error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
+ sizeof(addr_buf), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ if (error != 0)
+ inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+ sizeof(addr_buf));
+ printf("\tinet6 %s ", addr_buf);
+
+ if (flags & IFF_POINTOPOINT) {
+ /* note RTAX_BRD overlap with IFF_BROADCAST */
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
+ /*
+ * some of the interfaces do not have valid destination
+ * address.
+ */
+ if (sin && sin->sin6_family == AF_INET6) {
+ int error;
+
+ /* XXX: embedded link local addr check */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+ *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+ u_short index;
+
+ index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+ *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = ntohs(index);
+ }
+
+ error = getnameinfo((struct sockaddr *)sin,
+ sin->sin6_len, addr_buf,
+ sizeof(addr_buf), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ if (error != 0)
+ inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+ sizeof(addr_buf));
+ printf("--> %s ", addr_buf);
+ }
+ }
+
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
+ if (!sin)
+ sin = &null_sin;
+ printf("prefixlen %d ", prefix(&sin->sin6_addr,
+ sizeof(struct in6_addr)));
+
+ if ((flags6 & IN6_IFF_ANYCAST) != 0)
+ printf("anycast ");
+ if ((flags6 & IN6_IFF_TENTATIVE) != 0)
+ printf("tentative ");
+ if ((flags6 & IN6_IFF_DUPLICATED) != 0)
+ printf("duplicated ");
+ if ((flags6 & IN6_IFF_DETACHED) != 0)
+ printf("detached ");
+ if ((flags6 & IN6_IFF_DEPRECATED) != 0)
+ printf("deprecated ");
+ if ((flags6 & IN6_IFF_AUTOCONF) != 0)
+ printf("autoconf ");
+ if ((flags6 & IN6_IFF_TEMPORARY) != 0)
+ printf("temporary ");
+
+ if (scopeid)
+ printf("scopeid 0x%x ", scopeid);
+
+ if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
+ printf("pltime ");
+ if (lifetime.ia6t_preferred) {
+ printf("%s ", lifetime.ia6t_preferred < t
+ ? "0" : sec2str(lifetime.ia6t_preferred - t));
+ } else
+ printf("infty ");
+
+ printf("vltime ");
+ if (lifetime.ia6t_expire) {
+ printf("%s ", lifetime.ia6t_expire < t
+ ? "0" : sec2str(lifetime.ia6t_expire - t));
+ } else
+ printf("infty ");
+ }
+
+ putchar('\n');
+}
+
+#define SIN6(x) ((struct sockaddr_in6 *) &(x))
+static struct sockaddr_in6 *sin6tab[] = {
+ SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
+ SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
+};
+
+static void
+in6_getprefix(const char *plen, int which)
+{
+ struct sockaddr_in6 *sin = sin6tab[which];
+ u_char *cp;
+ int len = atoi(plen);
+
+ if ((len < 0) || (len > 128))
+ errx(1, "%s: bad value", plen);
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+ if ((len == 0) || (len == 128)) {
+ memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
+ return;
+ }
+ memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
+ for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
+ *cp++ = 0xff;
+ *cp = 0xff << (8 - len);
+}
+
+static void
+in6_getaddr(const char *s, int which)
+{
+ struct sockaddr_in6 *sin = sin6tab[which];
+ struct addrinfo hints, *res;
+ int error = -1;
+
+ newaddr &= 1;
+
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+
+ if (which == ADDR) {
+ char *p = NULL;
+ if((p = strrchr(s, '/')) != NULL) {
+ *p = '\0';
+ in6_getprefix(p + 1, MASK);
+ explicit_prefix = 1;
+ }
+ }
+
+ if (sin->sin6_family == AF_INET6) {
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET6;
+ error = getaddrinfo(s, NULL, &hints, &res);
+ }
+ if (error != 0) {
+ if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
+ errx(1, "%s: bad value", s);
+ } else
+ bcopy(res->ai_addr, sin, res->ai_addrlen);
+}
+
+static int
+prefix(void *val, int size)
+{
+ u_char *name = (u_char *)val;
+ int byte, bit, plen = 0;
+
+ for (byte = 0; byte < size; byte++, plen += 8)
+ if (name[byte] != 0xff)
+ break;
+ if (byte == size)
+ return (plen);
+ for (bit = 7; bit != 0; bit--, plen++)
+ if (!(name[byte] & (1 << bit)))
+ break;
+ for (; bit != 0; bit--)
+ if (name[byte] & (1 << bit))
+ return(0);
+ byte++;
+ for (; byte < size; byte++)
+ if (name[byte])
+ return(0);
+ return (plen);
+}
+
+static char *
+sec2str(time_t total)
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ if (0) {
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += sprintf(p, "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += sprintf(p, "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += sprintf(p, "%dm", mins);
+ }
+ sprintf(p, "%ds", secs);
+ } else
+ sprintf(result, "%lu", (unsigned long)total);
+
+ return(result);
+}
+
+static void
+in6_postproc(int s, const struct afswtch *afp)
+{
+ if (explicit_prefix == 0) {
+ /* Aggregatable address architecture defines all prefixes
+ are 64. So, it is convenient to set prefixlen to 64 if
+ it is not specified. */
+ setifprefixlen("64", 0, s, afp);
+ /* in6_getprefix("64", MASK) if MASK is available here... */
+ }
+}
+
+static void
+in6_status_tunnel(int s)
+{
+ char src[NI_MAXHOST];
+ char dst[NI_MAXHOST];
+#ifdef NI_WITHSCOPEID
+ const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+ const int niflag = NI_NUMERICHOST;
+#endif
+ struct in6_ifreq in6_ifr;
+ const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
+
+ memset(&in6_ifr, 0, sizeof(in6_ifr));
+ strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
+
+ if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
+ return;
+ if (sa->sa_family == AF_INET6)
+ in6_fillscopeid(&in6_ifr.ifr_addr);
+ if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, niflag) != 0)
+ src[0] = '\0';
+
+ if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
+ return;
+ if (sa->sa_family == AF_INET6)
+ in6_fillscopeid(&in6_ifr.ifr_addr);
+ if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, niflag) != 0)
+ dst[0] = '\0';
+
+ printf("\ttunnel inet6 %s --> %s\n", src, dst);
+}
+
+static void
+in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+ struct in6_aliasreq in6_addreq;
+
+ memset(&in6_addreq, 0, sizeof(in6_addreq));
+ strncpy(in6_addreq.ifra_name, name, IFNAMSIZ);
+ memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+ memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
+ dstres->ai_addr->sa_len);
+
+ if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
+ warn("SIOCSIFPHYADDR_IN6");
+}
+
+static struct cmd inet6_cmds[] = {
+ DEF_CMD_ARG("prefixlen", setifprefixlen),
+ DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags),
+ DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags),
+ DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags),
+ DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
+ DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
+ DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
+ DEF_CMD_ARG("pltime", setip6pltime),
+ DEF_CMD_ARG("vltime", setip6vltime),
+ DEF_CMD("eui64", 0, setip6eui64),
+};
+
+static struct afswtch af_inet6 = {
+ .af_name = "inet6",
+ .af_af = AF_INET6,
+ .af_status = in6_status,
+ .af_getaddr = in6_getaddr,
+ .af_getprefix = in6_getprefix,
+ .af_postproc = in6_postproc,
+ .af_status_tunnel = in6_status_tunnel,
+ .af_settunnel = in6_set_tunnel,
+ .af_difaddr = SIOCDIFADDR_IN6,
+ .af_aifaddr = SIOCAIFADDR_IN6,
+ .af_ridreq = &in6_addreq,
+ .af_addreq = &in6_addreq,
+};
+
+static void
+in6_Lopt_cb(const char *optarg __unused)
+{
+ ip6lifetime++; /* print IPv6 address lifetime */
+}
+static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb };
+
+static __constructor void
+inet6_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(inet6_cmds); i++)
+ cmd_register(&inet6_cmds[i]);
+ af_register(&af_inet6);
+ opt_register(&in6_Lopt);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/af_ipx.c src/sbin/ifconfig/af_ipx.c
--- src.preview/sbin/ifconfig/af_ipx.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_ipx.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/if_var.h>
+#define IPXIP
+#define IPTUNNEL
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq ipx_addreq;
+static struct ifreq ipx_ridreq;
+
+static void
+ipx_status(int s __unused, const struct rt_addrinfo * info)
+{
+ struct sockaddr_ipx *sipx, null_sipx;
+
+ sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
+ if (sipx == NULL)
+ return;
+
+ printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
+
+ if (flags & IFF_POINTOPOINT) {
+ sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
+ if (!sipx) {
+ memset(&null_sipx, 0, sizeof(null_sipx));
+ sipx = &null_sipx;
+ }
+ printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
+ }
+ putchar('\n');
+}
+
+#define SIPX(x) ((struct sockaddr_ipx *) &(x))
+struct sockaddr_ipx *sipxtab[] = {
+ SIPX(ipx_ridreq.ifr_addr), SIPX(ipx_addreq.ifra_addr),
+ SIPX(ipx_addreq.ifra_mask), SIPX(ipx_addreq.ifra_broadaddr)
+};
+
+static void
+ipx_getaddr(const char *addr, int which)
+{
+ struct sockaddr_ipx *sipx = sipxtab[which];
+
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_len = sizeof(*sipx);
+ sipx->sipx_addr = ipx_addr(addr);
+ if (which == MASK)
+ printf("Attempt to set IPX netmask will be ineffectual\n");
+}
+
+static void
+ipx_postproc(int s, const struct afswtch *afp)
+{
+ if (setipdst) {
+ struct ipxip_req rq;
+ int size = sizeof(rq);
+
+ rq.rq_ipx = ipx_addreq.ifra_addr;
+ rq.rq_ip = ipx_addreq.ifra_dstaddr;
+
+ if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
+ Perror("Encapsulation Routing");
+ }
+}
+
+static struct afswtch af_ipx = {
+ .af_name = "ipx",
+ .af_af = AF_IPX,
+ .af_status = ipx_status,
+ .af_getaddr = ipx_getaddr,
+ .af_postproc = ipx_postproc,
+ .af_difaddr = SIOCDIFADDR,
+ .af_aifaddr = SIOCAIFADDR,
+ .af_ridreq = &ipx_ridreq,
+ .af_addreq = &ipx_addreq,
+};
+
+static __constructor void
+ipx_ctor(void)
+{
+ af_register(&af_ipx);
+}
diff -N -u -r src.preview/sbin/ifconfig/af_link.c src/sbin/ifconfig/af_link.c
--- src.preview/sbin/ifconfig/af_link.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_link.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h> /* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+#include "ifconfig.h"
+
+static struct ifreq link_ridreq;
+
+static void
+link_status(int s __unused, const struct rt_addrinfo *info)
+{
+ const struct sockaddr_dl *sdl =
+ (const struct sockaddr_dl *) info->rti_info[RTAX_IFA];
+
+ if (sdl != NULL && sdl->sdl_alen > 0) {
+ if (sdl->sdl_type == IFT_ETHER &&
+ sdl->sdl_alen == ETHER_ADDR_LEN)
+ printf("\tether %s\n",
+ ether_ntoa((const struct ether_addr *)LLADDR(sdl)));
+ else {
+ int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+ printf("\tlladdr %s\n", link_ntoa(sdl) + n);
+ }
+ }
+}
+
+static void
+link_getaddr(const char *addr, int which)
+{
+ char *temp;
+ struct sockaddr_dl sdl;
+ struct sockaddr *sa = &link_ridreq.ifr_addr;
+
+ if (which != ADDR)
+ errx(1, "can't set link-level netmask or broadcast");
+ if ((temp = malloc(strlen(addr) + 1)) == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strcpy(temp + 1, addr);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen > sizeof(sa->sa_data))
+ errx(1, "malformed link-level address");
+ sa->sa_family = AF_LINK;
+ sa->sa_len = sdl.sdl_alen;
+ bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
+}
+
+static struct afswtch af_link = {
+ .af_name = "link",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+static struct afswtch af_ether = {
+ .af_name = "ether",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+static struct afswtch af_lladdr = {
+ .af_name = "lladdr",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+
+static __constructor void
+link_ctor(void)
+{
+ af_register(&af_link);
+ af_register(&af_ether);
+ af_register(&af_lladdr);
+}
diff -N -u -r src.preview/sbin/ifconfig/ifcarp.c src/sbin/ifconfig/ifcarp.c
--- src.preview/sbin/ifconfig/ifcarp.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/ifcarp.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,199 @@
+/* $FreeBSD$ */
+/* from $OpenBSD: ifconfig.c,v 1.82 2003/10/19 05:43:35 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
+ * Copyright (c) 2003 Ryan McBride. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES 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 MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/ip_carp.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static const char *carp_states[] = { CARP_STATES };
+
+void carp_status(int s);
+void setcarp_advbase(const char *,int, int, const struct afswtch *rafp);
+void setcarp_advskew(const char *, int, int, const struct afswtch *rafp);
+void setcarp_passwd(const char *, int, int, const struct afswtch *rafp);
+void setcarp_vhid(const char *, int, int, const struct afswtch *rafp);
+
+void
+carp_status(int s)
+{
+ const char *state;
+ struct carpreq carpr;
+
+ memset((char *)&carpr, 0, sizeof(struct carpreq));
+ ifr.ifr_data = (caddr_t)&carpr;
+
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ return;
+
+ if (carpr.carpr_vhid > 0) {
+ if (carpr.carpr_state > CARP_MAXSTATE)
+ state = "<UNKNOWN>";
+ else
+ state = carp_states[carpr.carpr_state];
+
+ printf("\tcarp: %s vhid %d advbase %d advskew %d\n",
+ state, carpr.carpr_vhid, carpr.carpr_advbase,
+ carpr.carpr_advskew);
+ }
+
+ return;
+
+}
+
+void
+setcarp_passwd(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct carpreq carpr;
+
+ memset((char *)&carpr, 0, sizeof(struct carpreq));
+ ifr.ifr_data = (caddr_t)&carpr;
+
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGVH");
+
+ /* XXX Should hash the password into the key here, perhaps? */
+ strlcpy(carpr.carpr_key, val, CARP_KEY_LEN);
+
+ if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVH");
+
+ return;
+}
+
+void
+setcarp_vhid(const char *val, int d, int s, const struct afswtch *afp)
+{
+ int vhid;
+ struct carpreq carpr;
+
+ vhid = atoi(val);
+
+ if (vhid <= 0)
+ errx(1, "vhid must be greater than 0");
+
+ memset((char *)&carpr, 0, sizeof(struct carpreq));
+ ifr.ifr_data = (caddr_t)&carpr;
+
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGVH");
+
+ carpr.carpr_vhid = vhid;
+
+ if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVH");
+
+ return;
+}
+
+void
+setcarp_advskew(const char *val, int d, int s, const struct afswtch *afp)
+{
+ int advskew;
+ struct carpreq carpr;
+
+ advskew = atoi(val);
+
+ memset((char *)&carpr, 0, sizeof(struct carpreq));
+ ifr.ifr_data = (caddr_t)&carpr;
+
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGVH");
+
+ carpr.carpr_advskew = advskew;
+
+ if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVH");
+
+ return;
+}
+
+void
+setcarp_advbase(const char *val, int d, int s, const struct afswtch *afp)
+{
+ int advbase;
+ struct carpreq carpr;
+
+ advbase = atoi(val);
+
+ memset((char *)&carpr, 0, sizeof(struct carpreq));
+ ifr.ifr_data = (caddr_t)&carpr;
+
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGVH");
+
+ carpr.carpr_advbase = advbase;
+
+ if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVH");
+
+ return;
+}
+
+static struct cmd carp_cmds[] = {
+ DEF_CMD_ARG("advbase", setcarp_advbase),
+ DEF_CMD_ARG("advskew", setcarp_advskew),
+ DEF_CMD_ARG("pass", setcarp_passwd),
+ DEF_CMD_ARG("vhid", setcarp_vhid),
+};
+static struct afswtch af_carp = {
+ .af_name = "af_carp",
+ .af_af = AF_UNSPEC,
+ .af_other_status = carp_status,
+};
+
+static __constructor void
+carp_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(carp_cmds); i++)
+ cmd_register(&carp_cmds[i]);
+ af_register(&af_carp);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifclone.c src/sbin/ifconfig/ifclone.c
--- src.preview/sbin/ifconfig/ifclone.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/ifclone.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void
+list_cloners(void)
+{
+ struct if_clonereq ifcr;
+ char *cp, *buf;
+ int idx;
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+ memset(&ifcr, 0, sizeof(ifcr));
+
+ if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+ err(1, "SIOCIFGCLONERS for count");
+
+ buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
+ if (buf == NULL)
+ err(1, "unable to allocate cloner name buffer");
+
+ ifcr.ifcr_count = ifcr.ifcr_total;
+ ifcr.ifcr_buffer = buf;
+
+ if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+ err(1, "SIOCIFGCLONERS for names");
+
+ /*
+ * In case some disappeared in the mean time, clamp it down.
+ */
+ if (ifcr.ifcr_count > ifcr.ifcr_total)
+ ifcr.ifcr_count = ifcr.ifcr_total;
+
+ for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
+ if (idx > 0)
+ putchar(' ');
+ printf("%s", cp);
+ }
+
+ putchar('\n');
+ free(buf);
+}
+
+void
+clone_create(void)
+{
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
+ err(1, "SIOCIFCREATE");
+
+ /*
+ * If we get a different name back then we put in, we probably
+ * want to print it out, but we might change our mind later so
+ * we just signal our intrest and leave the printout for later.
+ */
+ if (strcmp(name, ifr.ifr_name) != 0) {
+ printname = 1;
+ strlcpy(name, ifr.ifr_name, sizeof(name));
+ }
+
+ close(s);
+}
+
+static void
+clone_destroy(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+ (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
+ err(1, "SIOCIFDESTROY");
+ /*
+ * If we create and destroy an interface in the same command,
+ * there isn't any reason to print it's name.
+ */
+ printname = 0;
+}
+
+static struct cmd clone_cmds[] = {
+ DEF_CMD("destroy", 0, clone_destroy),
+ DEF_CMD("unplumb", 0, clone_destroy),
+};
+
+static void
+clone_Copt_cb(const char *optarg __unused)
+{
+ list_cloners();
+ exit(0);
+}
+static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb };
+
+static __constructor void
+clone_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(clone_cmds); i++)
+ cmd_register(&clone_cmds[i]);
+ opt_register(&clone_Copt);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifconfig.8 src/sbin/ifconfig/ifconfig.8
--- src.preview/sbin/ifconfig/ifconfig.8 2005-04-25 13:33:26.000000000 -0400
+++ src/sbin/ifconfig/ifconfig.8 2005-09-27 15:02:10.000000000 -0400
@@ -26,10 +26,9 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
-.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.85 2004/07/27 09:51:49 yar Exp $
-.\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.7 2005/04/25 17:33:26 swildner Exp $
+.\" $FreeBSD$
.\"
-.Dd July 26, 2004
+.Dd November 2, 2004
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -56,6 +55,7 @@
.Op Fl d
.Op Fl m
.Op Fl u
+.Op Fl v
.Op Ar address_family
.Nm
.Fl l
@@ -67,6 +67,7 @@
.Op Fl d
.Op Fl m
.Op Fl u
+.Op Fl v
.Op Fl C
.Sh DESCRIPTION
The
@@ -224,6 +225,14 @@
.It Fl arp
Disable the use of the Address Resolution Protocol
.Pq Xr arp 4 .
+.It Cm staticarp
+If the Address Resolution Protocol is enabled,
+the host will only reply to requests for its addresses,
+and will never send any requests.
+.It Fl staticarp
+If the Address Resolution Protocol is enabled,
+the host will perform normally,
+sending out requests and listening for replies.
.It Cm broadcast
(Inet only.)
Specify the address to use to represent broadcasts to the
@@ -256,15 +265,18 @@
Fill interface index
(lowermost 64bit of an IPv6 address)
automatically.
-.\" .It Cm ipdst
-.\" This is used to specify an Internet host who is willing to receive
-.\" ip packets encapsulating NS packets bound for a remote network.
-.\" An apparent point to point link is constructed, and
-.\" the address specified will be taken as the NS address and network
-.\" of the destination.
-.\" IP encapsulation of
-.\" .Tn CLNP
-.\" packets is done differently.
+.It Cm ipdst
+This is used to specify an Internet host who is willing to receive
+IP packets encapsulating IPX packets bound for a remote network.
+An apparent point to point link is constructed, and
+the address specified will be taken as the IPX address and network
+of the destination.
+.\".It Cm maclabel Ar label
+.\"If Mandatory Access Control support is enabled in the kernel,
+.\"set the MAC label to
+.\".Ar label .
+.\" (see
+.\" .Xr maclabel 7 ) .
.It Cm media Ar type
If the driver supports the media selection system, set the media type
of the interface to
@@ -318,18 +330,18 @@
of each other, so setting one may also set the other.
The driver will offload as much checksum work as it can reliably
support, the exact level of offloading varies between drivers.
-.\".It Fl rxcsum , Fl txcsum
-.\"If the driver supports user-configurable checksum offloading,
-.\"disable receive (or transmit) checksum offloading on the interface.
-.\"These settings may not always be independent of each other.
-.\".It Cm polling
-.\"If the driver has user-configurable
-.\".Xr polling 4
-.\"support, select the polling mode on the interface.
-.\".It Fl polling
-.\"If the driver has user-configurable
-.\".Xr polling 4
-.\"support, select the interrupt mode on the interface.
+.It Fl rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+disable receive (or transmit) checksum offloading on the interface.
+These settings may not always be independent of each other.
+.It Cm polling
+If the driver has user-configurable
+.Xr polling 4
+support, select the polling mode on the interface.
+.It Fl polling
+If the driver has user-configurable
+.Xr polling 4
+support, select the interrupt mode on the interface.
.It Cm tunnel Ar src_addr dest_addr
(IP tunnel devices only.)
Configure the physical source and destination address for IP tunnel
@@ -350,7 +362,10 @@
If the interface is given without a unit number, try to create a new
device with an arbitrary unit number.
If creation of an arbitrary device is successful, the new device name is
-printed to standard output.
+printed to standard output unless the interface is renamed or destroyed
+in the same
+.Nm
+invocation.
.It Cm destroy
Destroy the specified network pseudo-device.
.It Cm plumb
@@ -446,7 +461,7 @@
not on a
.Xr vlan 4
interface itself.
-.It Fl vlanmtu , Fl vlanhwtag
+.It Fl vlanmtu , vlanhwtag
If the driver offers user-configurable VLAN support, disable
reception of extended frames or tag processing in hardware,
respectively.
@@ -568,13 +583,13 @@
.It Fl link Op Cm 0 No - Cm 2
.Sm on
Disable special processing at the link level with the specified interface.
-.\".It Cm monitor
-.\"Put the interface in monitor mode.
-.\"No packets are transmitted, and received packets are discarded after
-.\".Xr bpf 4
-.\"processing.
-.\".It Fl monitor
-.\"Take the interface out of monitor mode.
+.It Cm monitor
+Put the interface in monitor mode.
+No packets are transmitted, and received packets are discarded after
+.Xr bpf 4
+processing.
+.It Fl monitor
+Take the interface out of monitor mode.
.It Cm up
Mark an interface
.Dq up .
@@ -583,64 +598,104 @@
It happens automatically when setting the first address on an interface.
If the interface was reset when previously marked down,
the hardware will be re-initialized.
-.It Cm ssid Ar ssid
-For IEEE 802.11 wireless interfaces, set the desired Service Set
-Identifier (aka network name).
-The SSID is a string up to 32 characters
-in length and may be specified as either a normal string or in
-hexadecimal when proceeded by
-.Ql 0x .
-Additionally, the SSID may be cleared by setting it to
-.Ql - .
-.It Cm nwid Ar ssid
-Another name for the
-.Cm ssid
-parameter.
-Included for
-.Nx
-compatibility.
-.It Cm stationname Ar name
-For IEEE 802.11 wireless interfaces, set the name of this station.
-It appears that the station name is not really part of the IEEE 802.11
-protocol though all interfaces seem to support it.
-As such it only
-seems to be meaningful to identical or virtually identical equipment.
-Setting the station name is identical in syntax to setting the SSID.
-.It Cm station Ar name
-Another name for the
-.Cm stationname
-parameter.
-Included for
-.Bsx
-compatibility.
-.It Cm channel Ar number
-For IEEE 802.11 wireless interfaces, set the desired channel.
-Channels range from 1 to 14, but the exact selection available
-depends on the region your adaptor was manufactured for.
-Setting
-the channel to 0 will give you the default for your adaptor.
-Many
-adaptors ignore this setting unless you are in ad-hoc mode.
+.El
+.Pp
+The following parameters are specific to IEEE 802.11 wireless interfaces:
+.Bl -tag -width indent
+.It Cm apbridge
+When operating as an access point, pass packets between
+wireless clients directly (default).
+To instead let them pass up through the
+system and be forwarded using some other mechanism, use
+.Fl apbridge .
+Disabling the internal bridging
+is useful when traffic is to be processed with
+packet filtering.
.It Cm authmode Ar mode
-For IEEE 802.11 wireless interfaces, set the desired authentication mode
-in infrastructure mode.
+Set the desired authentication mode in infrastructure mode.
Not all adaptors support all modes.
The set of
valid modes is
.Dq Li none ,
.Dq Li open ,
+.Dq Li shared
+(shared key),
+.Dq Li 8021x
+(IEEE 802.1x),
+or
+.Dq Li wpa
+(IEEE WPA/WPA2/802.11i).
+The
+.Dq Li 8021x
and
-.Dq Li shared .
+.Dq Li wpa
+modes are only useful when used an authentication service
+(a supplicant for client operation or an authenticator when
+operating as an access point).
Modes are case insensitive.
+.It Cm bssid Ar address
+Specify the MAC address of the access point to use when operating
+as a station in a BSS network.
+This overrides any automatic selection done by the system.
+To disable a previously selected access point, supply
+.Dq Li any ,
+.Dq Li none ,
+or
+.Dq Li -
+for the address.
+This option is useful when more than one access points have the same SSID.
+Another name for the
+.Cm bssid
+parameter is
+.Cm ap .
+.It Cm chanlist Ar channels
+Set the desired channels to use when scanning for access
+points, neighbors in an IBSS network, or looking for unoccupied
+channels when operating as an access point.
+The set of channels is specified as a comma-separated list with
+each element in the list representing either a single channel number or a range
+of the form
+.Dq Li a-b .
+Channel numbers must be in the range 1 to 255 and be permissible
+according to the operating characteristics of the device.
+.It Cm channel Ar number
+Set a single desired channel.
+Channels range from 1 to 255, but the exact selection available
+depends on the region your adaptor was manufactured for.
+Setting
+the channel to
+.Dq Li 0 ,
+.Dq Li any ,
+or
+.Dq Li -
+will give you the default for your adaptor.
+Many
+adaptors ignore this setting unless you are in ad-hoc mode.
+Alternatively the frequency, in megahertz, may be specified
+instead of the channel number.
+.It Cm hidessid
+When operating as an access point, do not broadcast the SSID
+in beacon frames.
+By default, the SSID is included in beacon frames.
+To re-enable the broadcast of the SSID, use
+.Fl hidessid .
.It Cm powersave
-For IEEE 802.11 wireless interfaces, enable powersave mode.
-.It Fl powersave
-For IEEE 802.11 wireless interfaces, disable powersave mode.
+Enable powersave operation.
+When operating as a client, the station will conserve power by
+periodically turning off the radio and listening for
+messages from the access point telling it there are packets waiting.
+The station must then retrieve the packets.
+When operating as an access point, the station must honor power
+save operation of associated clients.
+Not all devices support power save operation, either as a client
+or as an access point.
+Use
+.Fl powersave
+to disable powersave operation.
.It Cm powersavesleep Ar sleep
-For IEEE 802.11 wireless interfaces, set the desired max powersave sleep
-time in milliseconds.
+Set the desired max powersave sleep time in milliseconds.
.It Cm protmode Ar technique
-For IEEE 802.11 wireless interfaces operating in 11g, use the specified
+For interfaces operating in 802.11g, use the specified
.Ar technique
for protecting OFDM frames in a mixed 11b/11g network.
The set of valid techniques is
@@ -651,8 +706,26 @@
.Dq Li rtscts
(RTS/CTS).
Technique names are case insensitive.
+.It Cm roaming Ar mode
+When operating as a station, control how the system will
+behave when communication with the current access point
+is broken.
+The
+.Ar mode
+argument may be one of
+.Dq Li device
+(leave it to the hardware device to decide),
+.Dq Li auto
+(handle either in the device or the operating system\[em]as appropriate),
+.Dq Li manual
+(do nothing until explicitly instructed).
+By default, the device is left to handle this if it is
+capable; otherwise, the operating system will automatically
+attempt to reestablish communication.
+Manual mode is mostly useful when an application wants to
+control the selection of an access point.
.It Cm rtsthreshold Ar length
-For IEEE 802.11 wireless interfaces, set the threshold for which
+Set the threshold for which
transmitted frames are preceded by transmission of an
RTS
control frame.
@@ -661,8 +734,26 @@
argument
is the frame size in bytes and must be in the range 1 to 2312.
Not all adaptors support setting the RTS threshold.
+.It Cm ssid Ar ssid
+Set the desired Service Set Identifier (aka network name).
+The SSID is a string up to 32 characters
+in length and may be specified as either a normal string or in
+hexadecimal when proceeded by
+.Ql 0x .
+Additionally, the SSID may be cleared by setting it to
+.Ql - .
+.It Cm scan
+Display the current set of scanned neighbors and/or trigger a new scan.
+Only the super-user can trigger a scan.
+.It Cm stationname Ar name
+Set the name of this station.
+It appears that the station name is not really part of the IEEE 802.11
+protocol though all interfaces seem to support it.
+As such it only
+seems to be meaningful to identical or virtually identical equipment.
+Setting the station name is identical in syntax to setting the SSID.
.It Cm txpower Ar power
-For IEEE 802.11 wireless interfaces, set the power used to transmit frames.
+Set the power used to transmit frames.
The
.Ar power
argument
@@ -673,7 +764,7 @@
the driver will use the setting closest to the specified value.
Not all adaptors support changing the transmit power.
.It Cm wepmode Ar mode
-For IEEE 802.11 wireless interfaces, set the desired WEP mode.
+Set the desired WEP mode.
Not all adaptors support all modes.
The set of valid modes is
.Dq Li off ,
@@ -693,10 +784,9 @@
.Dq Li mixed .
Modes are case insensitive.
.It Cm weptxkey Ar index
-For IEEE 802.11 wireless interfaces, set the WEP key to be used for
-transmission.
+Set the WEP key to be used for transmission.
.It Cm wepkey Ar key Ns | Ns Ar index : Ns Ar key
-For IEEE 802.11 wireless interfaces, set the selected WEP key.
+Set the selected WEP key.
If an
.Ar index
is not given, key 1 is set.
@@ -719,6 +809,31 @@
If that is the case, then the first four keys
(1-4) will be the standard temporary keys and any others will be adaptor
specific keys such as permanent keys stored in NVRAM.
+.It Cm wme
+Enable Wireless Media Extensions (WME) support, if available,
+for the specified interface.
+WME is a subset of the IEEE 802.11e standard to support the
+efficient communication of realtime and multimedia data.
+To disable WME support, use
+.Fl wme .
+.El
+.Pp
+The following parameters are support for compatibility with other systems:
+.Bl -tag -width indent
+.It Cm nwid Ar ssid
+Another name for the
+.Cm ssid
+parameter.
+Included for
+.Nx
+compatibility.
+.It Cm station Ar name
+Another name for the
+.Cm stationname
+parameter.
+Included for
+.Bsx
+compatibility.
.It Cm wep
Another way of saying
.Cm wepmode on .
@@ -733,9 +848,7 @@
compatibility.
.It Cm nwkey key
Another way of saying:
-.Pp
.Dq Li "wepmode on weptxkey 1 wepkey 1:key wepkey 2:- wepkey 3:- wepkey 4:-" .
-.Pp
Included for
.Nx
compatibility.
@@ -745,16 +858,13 @@
.Sm on
.Xc
Another way of saying
-.Pp
.Dq Li "wepmode on weptxkey n wepkey 1:k1 wepkey 2:k2 wepkey 3:k3 wepkey 4:k4" .
-.Pp
Included for
.Nx
compatibility.
.It Fl nwkey
Another way of saying
.Cm wepmode off .
-.Pp
Included for
.Nx
compatibility.
@@ -768,9 +878,6 @@
.Nm
will report only the details specific to that protocol family.
.Pp
-If the driver does supports the media selection system, the supported
-media list will be included in the output.
-.Pp
If the
.Fl m
flag is passed before an interface name,
@@ -810,6 +917,10 @@
(only list interfaces that are up).
.Pp
The
+.Fl v
+flag may be used to get more verbose status for an interface.
+.Pp
+The
.Fl C
flag may be used to list all of the interface cloners available on
the system, with no additional information.
@@ -823,22 +934,10 @@
Messages indicating the specified interface does not exist, the
requested address is unknown, or the user is not privileged and
tried to alter an interface's configuration.
-.Sh BUGS
-Basic IPv6 node operation requires a link-local address on each
-interface configured for IPv6.
-Normally, such an address is automatically configured by the
-kernel on each interface added to the system; this behaviour may
-be disabled by setting the sysctl MIB variable
-.Va net.inet6.ip6.auto_linklocal
-to 0.
-.Pp
-If you delete such an address using
-.Nm ,
-the kernel may act very oddly.
-Do this at your own risk.
.Sh SEE ALSO
.Xr netstat 1 ,
.Xr netintro 4 ,
+.Xr polling 4 ,
.Xr vlan 4 ,
.\" .Xr eon 5 ,
.Xr rc 8 ,
@@ -849,3 +948,16 @@
.Nm
utility appeared in
.Bx 4.2 .
+.Sh BUGS
+Basic IPv6 node operation requires a link-local address on each
+interface configured for IPv6.
+Normally, such an address is automatically configured by the
+kernel on each interface added to the system; this behaviour may
+be disabled by setting the sysctl MIB variable
+.Va net.inet6.ip6.auto_linklocal
+to 0.
+.Pp
+If you delete such an address using
+.Nm ,
+the kernel may act very oddly.
+Do this at your own risk.
diff -N -u -r src.preview/sbin/ifconfig/ifconfig.c src/sbin/ifconfig/ifconfig.c
--- src.preview/sbin/ifconfig/ifconfig.c 2005-05-26 05:06:40.000000000 -0400
+++ src/sbin/ifconfig/ifconfig.c 2005-09-27 15:03:42.000000000 -0400
@@ -25,17 +25,25 @@
* 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.
- *
- * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved.
- * @(#)ifconfig.c 8.2 (Berkeley) 2/16/94
- * $FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.96 2004/02/27 06:43:14 kan Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.24 2005/05/26 09:06:40 dillon Exp $
*/
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/module.h>
@@ -54,30 +62,6 @@
#include <arpa/inet.h>
#include <netdb.h>
-#ifdef INET6
-#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
-#endif
-
-#ifndef NO_IPX
-/* IPX */
-#define IPXIP
-#define IPTUNNEL
-#include <netipx/ipx.h>
-#include <netipx/ipx_if.h>
-#endif
-
-/* Appletalk */
-#include <netatalk/at.h>
-
-/* XNS */
-#ifdef NS
-#define NSIP
-#include <netns/ns.h>
-#include <netns/ns_if.h>
-#endif
-
-/* OSI */
-
#include <ctype.h>
#include <err.h>
#include <errno.h>
@@ -86,34 +70,15 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <ifaddrs.h>
#include "ifconfig.h"
-/* wrapper for KAME-special getnameinfo() */
-#ifndef NI_WITHSCOPEID
-#define NI_WITHSCOPEID 0
-#endif
-
/*
* Since "struct ifreq" is composed of various union members, callers
* should pay special attention to interprete the value.
* (.e.g. little/big endian difference in the structure.)
*/
-struct ifreq ifr, ridreq;
-struct ifaliasreq addreq;
-#ifdef INET6
-struct in6_ifreq in6_ridreq;
-struct in6_aliasreq in6_addreq =
- { { 0 },
- { 0, 0, 0, 0, { { { 0 } } }, 0 },
- { 0, 0, 0, 0, { { { 0 } } }, 0 },
- { 0, 0, 0, 0, { { { 0 } } }, 0 },
- 0,
- { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
-#endif
-struct sockaddr_in netmask;
-struct netrange at_nr; /* AppleTalk net range */
+struct ifreq ifr;
char name[IFNAMSIZ];
int flags;
@@ -123,326 +88,78 @@
int doalias;
int clearaddr;
int newaddr = 1;
-#ifdef INET6
-static int ip6lifetime;
-#endif
+int verbose;
-struct afswtch;
+int supmedia = 0;
+int printname = 0; /* Print the name of the created interface. */
-int supmedia = 0;
-int listcloners = 0;
-int printname = 0; /* Print the name of the created interface. */
-
-#ifdef INET6
-char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
-#endif
-
-void Perror(const char *cmd);
-void checkatrange(struct sockaddr_at *);
-int ifconfig(int argc, char *const *argv, const struct afswtch *afp);
-void notealias(const char *, int, int, const struct afswtch *afp);
-void list_cloners(void);
-void printb(const char *s, unsigned value, const char *bits);
-void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
-void status(const struct afswtch *afp, int addrcount,
+static int ifconfig(int argc, char *const *argv, const struct afswtch *afp);
+static void status(const struct afswtch *afp, int addrcount,
struct sockaddr_dl *sdl, struct if_msghdr *ifm,
struct ifa_msghdr *ifam);
-void tunnel_status(int s);
-void usage(void);
-void ifmaybeload(char *if_nm);
-
-#ifdef INET6
-void in6_fillscopeid(struct sockaddr_in6 *sin6);
-int prefix(void *, int);
-static char *sec2str(time_t);
-int explicit_prefix = 0;
-#endif
-
-typedef void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
-typedef void c_func2(const char *arg, const char *arg2, int s, const struct afswtch *afp);
-c_func setatphase, setatrange;
-c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask;
-c_func2 settunnel;
-c_func deletetunnel;
-#ifdef INET6
-c_func setifprefixlen;
-c_func setip6flags;
-c_func setip6pltime;
-c_func setip6vltime;
-c_func2 setip6lifetime;
-c_func setip6eui64;
-#endif
-c_func setifipdst;
-c_func setifflags, setifmetric, setifmtu, setifcap;
-c_func clone_destroy;
-c_func setifname;
-
-void clone_create(void);
-
-
-#define NEXTARG 0xffffff
-#define NEXTARG2 0xfffffe
-
-const
-struct cmd {
- const char *c_name;
- int c_parameter; /* NEXTARG means next argv */
- void (*c_func)(const char *, int, int, const struct afswtch *afp);
- void (*c_func2)(const char *, const char *, int, const struct afswtch *afp);
-} cmds[] = {
- { "up", IFF_UP, setifflags, NULL },
- { "down", -IFF_UP, setifflags, NULL },
- { "polling", IFF_POLLING, setifflags, NULL },
- { "-polling", -IFF_POLLING, setifflags, NULL },
- { "arp", -IFF_NOARP, setifflags, NULL },
- { "-arp", IFF_NOARP, setifflags, NULL },
- { "debug", IFF_DEBUG, setifflags, NULL },
- { "-debug", -IFF_DEBUG, setifflags, NULL },
- { "promisc", IFF_PPROMISC, setifflags, NULL },
- { "-promisc", -IFF_PPROMISC, setifflags, NULL },
- { "add", IFF_UP, notealias, NULL },
- { "alias", IFF_UP, notealias, NULL },
- { "-alias", -IFF_UP, notealias, NULL },
- { "delete", -IFF_UP, notealias, NULL },
- { "remove", -IFF_UP, notealias, NULL },
-#ifdef notdef
-#define EN_SWABIPS 0x1000
- { "swabips", EN_SWABIPS, setifflags, NULL },
- { "-swabips", -EN_SWABIPS, setifflags, NULL },
-#endif
- { "netmask", NEXTARG, setifnetmask, NULL },
-#ifdef INET6
- { "prefixlen", NEXTARG, setifprefixlen, NULL },
- { "anycast", IN6_IFF_ANYCAST, setip6flags, NULL },
- { "tentative", IN6_IFF_TENTATIVE, setip6flags, NULL },
- { "-tentative", -IN6_IFF_TENTATIVE, setip6flags, NULL },
- { "deprecated", IN6_IFF_DEPRECATED, setip6flags, NULL },
- { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags, NULL },
- { "autoconf", IN6_IFF_AUTOCONF, setip6flags, NULL },
- { "-autoconf", -IN6_IFF_AUTOCONF, setip6flags, NULL },
- { "pltime", NEXTARG, setip6pltime, NULL },
- { "vltime", NEXTARG, setip6vltime, NULL },
- { "eui64", 0, setip6eui64, NULL },
-#endif
- { "range", NEXTARG, setatrange, NULL },
- { "phase", NEXTARG, setatphase, NULL },
- { "metric", NEXTARG, setifmetric, NULL },
- { "broadcast", NEXTARG, setifbroadaddr, NULL },
- { "ipdst", NEXTARG, setifipdst, NULL },
- { "tunnel", NEXTARG2, NULL, settunnel },
- { "deletetunnel", 0, deletetunnel, NULL },
- { "link0", IFF_LINK0, setifflags, NULL },
- { "-link0", -IFF_LINK0, setifflags, NULL },
- { "link1", IFF_LINK1, setifflags, NULL },
- { "-link1", -IFF_LINK1, setifflags, NULL },
- { "link2", IFF_LINK2, setifflags, NULL },
- { "-link2", -IFF_LINK2, setifflags, NULL },
-#if notyet
- { "monitor", IFF_MONITOR, setifflags, NULL },
- { "-monitor", -IFF_MONITOR, setifflags, NULL },
- { "staticarp", IFF_STATICARP, setifflags, NULL },
- { "-staticarp", -IFF_STATICARP, setifflags, NULL },
-#endif
+static void tunnel_status(int s);
+static void usage(void);
-#ifdef USE_IF_MEDIA
- { "media", NEXTARG, setmedia, NULL },
- { "mode", NEXTARG, setmediamode, NULL },
- { "mediaopt", NEXTARG, setmediaopt, NULL },
- { "-mediaopt", NEXTARG, unsetmediaopt, NULL },
-#endif
-#ifdef USE_VLANS
- { "vlan", NEXTARG, setvlantag, NULL },
- { "vlandev", NEXTARG, setvlandev, NULL },
- { "-vlandev", NEXTARG, unsetvlandev, NULL },
-#endif
-#if 0
- /* XXX `create' special-cased below */
- {"create", 0, clone_create, NULL },
- {"plumb", 0, clone_create, NULL },
-#endif
- {"destroy", 0, clone_destroy, NULL },
- {"unplumb", 0, clone_destroy, NULL },
-#ifdef USE_IEEE80211
- { "ssid", NEXTARG, set80211ssid, NULL },
- { "nwid", NEXTARG, set80211ssid, NULL },
- { "stationname", NEXTARG, set80211stationname, NULL },
- { "station", NEXTARG, set80211stationname, NULL }, /* BSD/OS */
- { "channel", NEXTARG, set80211channel, NULL },
- { "authmode", NEXTARG, set80211authmode, NULL },
- { "powersavemode", NEXTARG, set80211powersavemode, NULL },
- { "powersave", 1, set80211powersave, NULL },
- { "-powersave", 0, set80211powersave, NULL },
- { "powersavesleep", NEXTARG, set80211powersavesleep, NULL },
- { "wepmode", NEXTARG, set80211wepmode, NULL },
- { "wep", 1, set80211wep, NULL },
- { "-wep", 0, set80211wep, NULL },
- { "weptxkey", NEXTARG, set80211weptxkey, NULL },
- { "wepkey", NEXTARG, set80211wepkey, NULL },
- { "nwkey", NEXTARG, set80211nwkey, NULL }, /* NetBSD */
- { "-nwkey", 0, set80211wep, NULL }, /* NetBSD */
- { "rtsthreshold",NEXTARG, set80211rtsthreshold, NULL },
- { "protmode", NEXTARG, set80211protmode, NULL },
- { "txpower", NEXTARG, set80211txpower, NULL },
-#endif
- { "rxcsum", IFCAP_RXCSUM, setifcap, NULL },
- { "-rxcsum", -IFCAP_RXCSUM, setifcap, NULL },
- { "txcsum", IFCAP_TXCSUM, setifcap, NULL },
- { "-txcsum", -IFCAP_TXCSUM, setifcap, NULL },
- { "netcons", IFCAP_NETCONS, setifcap, NULL },
- { "-netcons", -IFCAP_NETCONS, setifcap, NULL },
- { "vlanmtu", IFCAP_VLAN_MTU, setifcap, NULL },
- { "-vlanmtu", -IFCAP_VLAN_MTU, setifcap, NULL },
- { "vlanhwtag", IFCAP_VLAN_HWTAGGING, setifcap, NULL },
- { "-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap, NULL },
- { "normal", -IFF_LINK0, setifflags, NULL },
- { "compress", IFF_LINK0, setifflags, NULL },
- { "noicmp", IFF_LINK1, setifflags, NULL },
- { "mtu", NEXTARG, setifmtu, NULL },
- { "name", NEXTARG, setifname, NULL },
- { NULL, 0, setifaddr, NULL },
- { NULL, 0, setifdstaddr, NULL },
-};
-
-/*
- * XNS support liberally adapted from code written at the University of
- * Maryland principally by James O'Toole and Chris Torek.
- */
-typedef void af_status(int, struct rt_addrinfo *);
-typedef void af_getaddr(const char *, int);
-typedef void af_getprefix(const char *, int);
-
-af_status in_status, at_status, link_status;
-af_getaddr in_getaddr, at_getaddr, link_getaddr;
-
-#ifndef NO_IPX
-af_status ipx_status;
-af_getaddr ipx_getaddr;
-#endif
+static struct afswtch *af_getbyname(const char *name);
+static struct afswtch *af_getbyfamily(int af);
+static void af_other_status(int);
-#ifdef INET6
-af_status in6_status;
-af_getaddr in6_getaddr;
-af_getprefix in6_getprefix;
-#endif /*INET6*/
-#ifdef NS
-af_status xns_status;
-af_getaddr xns_getaddr;
-#endif
-
-/* Known address families */
-const
-struct afswtch {
- const char *af_name;
- short af_af;
- af_status *af_status;
- af_getaddr *af_getaddr;
- af_getprefix *af_getprefix;
- u_long af_difaddr;
- u_long af_aifaddr;
- caddr_t af_ridreq;
- caddr_t af_addreq;
-} afs[] = {
-#define C(x) ((caddr_t) &x)
- { "inet", AF_INET, in_status, in_getaddr, NULL,
- SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#ifdef INET6
- { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
- SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
- C(in6_ridreq), C(in6_addreq) },
-#endif /*INET6*/
-#ifndef NO_IPX
- { "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL,
- SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#endif
- { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
- SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
-#ifdef NS
- { "ns", AF_NS, xns_status, xns_getaddr, NULL,
- SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#endif
- { "link", AF_LINK, link_status, link_getaddr, NULL,
- 0, SIOCSIFLLADDR, NULL, C(ridreq) },
- { "ether", AF_LINK, link_status, link_getaddr, NULL,
- 0, SIOCSIFLLADDR, NULL, C(ridreq) },
- { "lladdr", AF_LINK, link_status, link_getaddr, NULL,
- 0, SIOCSIFLLADDR, NULL, C(ridreq) },
- { NULL, 0, NULL, NULL, NULL, 0, 0, NULL, NULL }
-};
-
-/*
- * Expand the compacted form of addresses as returned via the
- * configuration read via sysctl().
- */
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+static struct option *opts = NULL;
void
-rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
+opt_register(struct option *p)
{
- struct sockaddr *sa;
- int i;
-
- memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
- for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
- if ((rtinfo->rti_addrs & (1 << i)) == 0)
- continue;
- rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
- ADVANCE(cp, sa);
- }
+ p->next = opts;
+ opts = p;
}
-
-void
+static void
usage(void)
{
-#ifndef INET6
- fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
- "usage: ifconfig interface address_family [address [dest_address]]",
- " [parameters]",
- " ifconfig -C",
- " ifconfig interface create",
- " ifconfig -a [-d] [-m] [-u] [address_family]",
- " ifconfig -l [-d] [-u] [address_family]",
- " ifconfig [-d] [-m] [-u]");
-#else
- fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
- "usage: ifconfig [-L] interface address_family [address [dest_address]]",
- " [parameters]",
- " ifconfig -C",
- " ifconfig interface create",
- " ifconfig -a [-L] [-d] [-m] [-u] [address_family]",
- " ifconfig -l [-d] [-u] [address_family]",
- " ifconfig [-L] [-d] [-m] [-u]");
-#endif
+ char options[1024];
+ struct option *p;
+
+ /* XXX not right but close enough for now */
+ options[0] = '\0';
+ for (p = opts; p != NULL; p = p->next) {
+ strlcat(options, p->opt_usage, sizeof(options));
+ strlcat(options, " ", sizeof(options));
+ }
+
+ fprintf(stderr,
+ "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
+ " [parameters]\n"
+ " ifconfig interface create\n"
+ " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
+ " ifconfig -l [-d] [-u] [address_family]\n"
+ " ifconfig %s[-d] [-m] [-u] [-v]\n",
+ options, options, options);
exit(1);
}
int
-main(int argc, char * const *argv)
+main(int argc, char *argv[])
{
- int c;
- int all, namesonly, downonly, uponly;
+ int c, all, namesonly, downonly, uponly;
int need_nl = 0, count = 0;
- const struct afswtch *afp = 0;
+ const struct afswtch *afp = NULL;
int addrcount, ifindex;
- struct if_msghdr *ifm, *nextifm;
- struct ifa_msghdr *ifam;
- struct sockaddr_dl *sdl;
- char *buf, *lim, *next;
-
+ struct if_msghdr *ifm, *nextifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ char *buf, *lim, *next;
size_t needed;
int mib[6];
+ char options[1024];
+ struct option *p;
+
+ all = downonly = uponly = namesonly = verbose = 0;
/* Parse leading line options */
- all = downonly = uponly = namesonly = 0;
- while ((c = getopt(argc, argv, "adlmuC"
-#ifdef INET6
- "L"
-#endif
- )) != -1) {
+ strlcpy(options, "adlmuv", sizeof(options));
+ for (p = opts; p != NULL; p = p->next)
+ strlcat(options, p->opt, sizeof(options));
+ while ((c = getopt(argc, argv, options)) != -1) {
switch (c) {
case 'a': /* scan all interfaces */
all++;
@@ -459,32 +176,23 @@
case 'u': /* restrict scan to "up" interfaces */
uponly++;
break;
- case 'C':
- listcloners = 1;
+ case 'v':
+ verbose++;
break;
-#ifdef INET6
- case 'L':
- ip6lifetime++; /* print IPv6 address lifetime */
- break;
-#endif
default:
- usage();
+ for (p = opts; p != NULL; p = p->next)
+ if (p->opt[0] == c) {
+ p->cb(optarg);
+ break;
+ }
+ if (p == NULL)
+ usage();
break;
}
}
argc -= optind;
argv += optind;
- if (listcloners) {
- /* -C must be solitary */
- if (all || supmedia || uponly || downonly || namesonly ||
- argc > 0)
- usage();
-
- list_cloners();
- exit(0);
- }
-
/* -l cannot be used with -a or -m */
if (namesonly && (all || supmedia))
usage();
@@ -504,13 +212,11 @@
ifindex = 0;
if (argc == 1) {
- for (afp = afs; afp->af_name; afp++)
- if (strcmp(afp->af_name, *argv) == 0) {
- argc--, argv++;
- break;
- }
- if (afp->af_name == NULL)
+ afp = af_getbyname(*argv);
+ if (afp == NULL)
usage();
+ if (afp->af_name != NULL)
+ argc--, argv++;
/* leave with afp non-zero */
}
} else {
@@ -543,13 +249,9 @@
/* Check for address family */
if (argc > 0) {
- for (afp = afs; afp->af_name; afp++)
- if (strcmp(afp->af_name, *argv) == 0) {
- argc--, argv++;
- break;
- }
- if (afp->af_name == NULL)
- afp = NULL; /* not a family, NULL */
+ afp = af_getbyname(*argv);
+ if (afp != NULL)
+ argc--, argv++;
}
retry:
@@ -561,7 +263,7 @@
mib[5] = ifindex; /* interface index */
/* if particular family specified, only ask about it */
- if (afp)
+ if (afp != NULL)
mib[3] = afp->af_af;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
@@ -586,10 +288,10 @@
if (ifm->ifm_type == RTM_IFINFO) {
#if notyet
- if (ifm->ifm_data.ifi_datalen == 0)
- ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
- sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
- sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
+ if (ifm->ifm_data.ifi_datalen == 0)
+ ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
+ sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
+ sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
#else
sdl = (struct sockaddr_dl *)(ifm + 1);
#endif
@@ -627,14 +329,6 @@
sizeof(name)-1 : sdl->sdl_nlen] = '\0';
if (all || namesonly) {
- size_t len;
-
- /* sdl_data may not be terminated, don't use strlcpy */
- if ((len = sdl->sdl_nlen) > sizeof(name) - 1)
- len = sizeof(name) - 1;
- bcopy(sdl->sdl_data, name, len);
- name[len] = 0;
-
if (uponly)
if ((flags & IFF_UP) == 0)
continue; /* not up */
@@ -642,9 +336,8 @@
if (flags & IFF_UP)
continue; /* not down */
if (namesonly) {
- if (afp == NULL ||
- afp->af_status != link_status ||
- sdl->sdl_type == IFT_ETHER) {
+ if (afp == NULL || afp->af_af != AF_LINK ||
+ sdl->sdl_type == IFT_ETHER) {
if (need_nl)
putchar(' ');
fputs(name, stdout);
@@ -670,92 +363,192 @@
exit (0);
}
+static struct afswtch *afs = NULL;
-int
+void
+af_register(struct afswtch *p)
+{
+ p->af_next = afs;
+ afs = p;
+}
+
+static struct afswtch *
+af_getbyname(const char *name)
+{
+ struct afswtch *afp;
+
+ for (afp = afs; afp != NULL; afp = afp->af_next)
+ if (strcmp(afp->af_name, name) == 0)
+ return afp;
+ return NULL;
+}
+
+static struct afswtch *
+af_getbyfamily(int af)
+{
+ struct afswtch *afp;
+
+ for (afp = afs; afp != NULL; afp = afp->af_next)
+ if (afp->af_af == af)
+ return afp;
+ return NULL;
+}
+
+static void
+af_other_status(int s)
+{
+ struct afswtch *afp;
+ uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+ memset(afmask, 0, sizeof(afmask));
+ for (afp = afs; afp != NULL; afp = afp->af_next) {
+ if (afp->af_other_status == NULL)
+ continue;
+ if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+ continue;
+ afp->af_other_status(s);
+ setbit(afmask, afp->af_af);
+ }
+}
+
+static void
+af_all_tunnel_status(int s)
+{
+ struct afswtch *afp;
+ uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+ memset(afmask, 0, sizeof(afmask));
+ for (afp = afs; afp != NULL; afp = afp->af_next) {
+ if (afp->af_status_tunnel == NULL)
+ continue;
+ if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+ continue;
+ afp->af_status_tunnel(s);
+ setbit(afmask, afp->af_af);
+ }
+}
+
+static struct cmd *cmds = NULL;
+
+void
+cmd_register(struct cmd *p)
+{
+ p->c_next = cmds;
+ cmds = p;
+}
+
+static const struct cmd *
+cmd_lookup(const char *name)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ const struct cmd *p;
+
+ for (p = cmds; p != NULL; p = p->c_next)
+ if (strcmp(name, p->c_name) == 0)
+ return p;
+ return NULL;
+#undef N
+}
+
+struct callback {
+ callback_func *cb_func;
+ void *cb_arg;
+ struct callback *cb_next;
+};
+static struct callback *callbacks = NULL;
+
+void
+callback_register(callback_func *func, void *arg)
+{
+ struct callback *cb;
+
+ cb = malloc(sizeof(struct callback));
+ if (cb == NULL)
+ errx(1, "unable to allocate memory for callback");
+ cb->cb_func = func;
+ cb->cb_arg = arg;
+ cb->cb_next = callbacks;
+ callbacks = cb;
+}
+
+/* specially-handled commands */
+static void setifaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
+
+static void setifdstaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifdstaddr_cmd =
+ DEF_CMD("ifdstaddr", 0, setifdstaddr);
+
+static int
ifconfig(int argc, char *const *argv, const struct afswtch *afp)
{
+ struct callback *cb;
int s;
if (afp == NULL)
- afp = &afs[0];
- ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
+ afp = af_getbyname("inet");
+ ifr.ifr_addr.sa_family =
+ afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
+ AF_INET : afp->af_af;
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
- err(1, "socket");
+ err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
while (argc > 0) {
const struct cmd *p;
- for (p = cmds; p->c_name; p++)
- if (strcmp(*argv, p->c_name) == 0)
- break;
- if (p->c_name == 0 && setaddr)
- p++; /* got src, do dst */
- if (p->c_func || p->c_func2) {
+ p = cmd_lookup(*argv);
+ if (p == NULL) {
+ /*
+ * Not a recognized command, choose between setting
+ * the interface address and the dst address.
+ */
+ p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
+ }
+ if (p->c_u.c_func || p->c_u.c_func2) {
if (p->c_parameter == NEXTARG) {
if (argv[1] == NULL)
errx(1, "'%s' requires argument",
p->c_name);
- (*p->c_func)(argv[1], 0, s, afp);
+ p->c_u.c_func(argv[1], 0, s, afp);
argc--, argv++;
+ } else if (p->c_parameter == OPTARG) {
+ p->c_u.c_func(argv[1], 0, s, afp);
+ if (argv[1] != NULL)
+ argc--, argv++;
} else if (p->c_parameter == NEXTARG2) {
if (argc < 3)
errx(1, "'%s' requires 2 arguments",
p->c_name);
- (*p->c_func2)(argv[1], argv[2], s, afp);
+ p->c_u.c_func2(argv[1], argv[2], s, afp);
argc -= 2, argv += 2;
} else
- (*p->c_func)(*argv, p->c_parameter, s, afp);
+ p->c_u.c_func(*argv, p->c_parameter, s, afp);
}
argc--, argv++;
}
-#ifdef INET6
- if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) {
- /* Aggregatable address architecture defines all prefixes
- are 64. So, it is convenient to set prefixlen to 64 if
- it is not specified. */
- setifprefixlen("64", 0, s, afp);
- /* in6_getprefix("64", MASK) if MASK is available here... */
- }
-#endif
-#ifndef NO_IPX
- if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
- struct ipxip_req rq;
- int size = sizeof(rq);
-
- rq.rq_ipx = addreq.ifra_addr;
- rq.rq_ip = addreq.ifra_dstaddr;
-
- if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
- Perror("Encapsulation Routing");
- }
-#endif
- if (ifr.ifr_addr.sa_family == AF_APPLETALK)
- checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
-#ifdef NS
- if (setipdst && ifr.ifr_addr.sa_family == AF_NS) {
- struct nsip_req rq;
- int size = sizeof(rq);
- rq.rq_ns = addreq.ifra_addr;
- rq.rq_ip = addreq.ifra_dstaddr;
-
- if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
- Perror("Encapsulation Routing");
- }
-#endif
+ /*
+ * Do any post argument processing required by the address family.
+ */
+ if (afp->af_postproc != NULL)
+ afp->af_postproc(s, afp);
+ /*
+ * Do deferred operations.
+ */
if (clearaddr) {
if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
warnx("interface %s cannot change %s addresses!",
name, afp->af_name);
- clearaddr = NULL;
+ clearaddr = 0;
}
}
if (clearaddr) {
int ret;
strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
- if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
+ ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
+ if (ret < 0) {
if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
/* means no previous address for interface */
} else
@@ -774,20 +567,23 @@
if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
Perror("ioctl (SIOCAIFADDR)");
}
+
+ /*
+ * Do deferred callbacks registered while processing
+ * command-line arguments.
+ */
+ for (cb = callbacks; cb != NULL; cb = cb->cb_next)
+ cb->cb_func(s, cb->cb_arg);
+
close(s);
return(0);
}
-#define RIDADDR 0
-#define ADDR 1
-#define MASK 2
-#define DSTADDR 3
/*ARGSUSED*/
-void
-setifaddr(const char *addr, int param __unused, int s __unused,
- const struct afswtch *afp)
+static void
+setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
{
- if (*afp->af_getaddr == NULL)
+ if (afp->af_getaddr == NULL)
return;
/*
* Delay the ioctl to set the interface addr until flags are all set.
@@ -797,21 +593,20 @@
setaddr++;
if (doalias == 0 && afp->af_af != AF_LINK)
clearaddr = 1;
- (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
+ afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
}
-void
+static void
settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
{
- struct addrinfo hints, *srcres, *dstres;
- struct ifaliasreq addr_req;
+ struct addrinfo *srcres, *dstres;
int ecode;
-#ifdef INET6
- struct in6_aliasreq in6_addr_req;
-#endif
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = afp->af_af;
+ if (afp->af_settunnel == NULL) {
+ warn("address family %s does not support tunnel setup",
+ afp->af_name);
+ return;
+ }
if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
errx(1, "error in parsing address string: %s",
@@ -825,178 +620,58 @@
errx(1,
"source and destination address families do not match");
- switch (srcres->ai_addr->sa_family) {
- case AF_INET:
- memset(&addr_req, 0, sizeof(addr_req));
- strncpy(addr_req.ifra_name, name, IFNAMSIZ);
- memcpy(&addr_req.ifra_addr, srcres->ai_addr,
- srcres->ai_addr->sa_len);
- memcpy(&addr_req.ifra_dstaddr, dstres->ai_addr,
- dstres->ai_addr->sa_len);
-
- if (ioctl(s, SIOCSIFPHYADDR, &addr_req) < 0)
- warn("SIOCSIFPHYADDR");
- break;
-
-#ifdef INET6
- case AF_INET6:
- memset(&in6_addr_req, 0, sizeof(in6_addr_req));
- strncpy(in6_addr_req.ifra_name, name, IFNAMSIZ);
- memcpy(&in6_addr_req.ifra_addr, srcres->ai_addr,
- srcres->ai_addr->sa_len);
- memcpy(&in6_addr_req.ifra_dstaddr, dstres->ai_addr,
- dstres->ai_addr->sa_len);
-
- if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addr_req) < 0)
- warn("SIOCSIFPHYADDR_IN6");
- break;
-#endif /* INET6 */
-
- default:
- warn("address family not supported");
- }
+ afp->af_settunnel(s, srcres, dstres);
freeaddrinfo(srcres);
freeaddrinfo(dstres);
}
/* ARGSUSED */
-void
-deletetunnel(const char *vname __unused, int param __unused, int s,
- const struct afswtch *afp __unused)
+static void
+deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
{
+
if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
err(1, "SIOCDIFPHYADDR");
}
-void
-setifnetmask(const char *addr, int dummy __unused, int s __unused,
- const struct afswtch *afp)
-{
- if (*afp->af_getaddr == NULL)
- return;
- setmask++;
- (*afp->af_getaddr)(addr, MASK);
-}
-
-#ifdef INET6
-void
-setifprefixlen(const char *addr, int dummy __unused, int s __unused,
- const struct afswtch *afp)
-{
- if (*afp->af_getprefix)
- (*afp->af_getprefix)(addr, MASK);
- explicit_prefix = 1;
-}
-
-void
-setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
- const struct afswtch *afp)
-{
- if (afp->af_af != AF_INET6)
- err(1, "address flags can be set only for inet6 addresses");
-
- if (flag < 0)
- in6_addreq.ifra_flags &= ~(-flag);
- else
- in6_addreq.ifra_flags |= flag;
-}
-
-void
-setip6pltime(const char *seconds, int dummy __unused, int s,
- const struct afswtch *afp)
+static void
+setifnetmask(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
{
- setip6lifetime("pltime", seconds, s, afp);
-}
-
-void
-setip6vltime(const char *seconds, int dummy __unused, int s,
- const struct afswtch *afp)
-{
- setip6lifetime("vltime", seconds, s, afp);
-}
-
-void
-setip6lifetime(const char *cmd, const char *val, int s __unused,
- const struct afswtch *afp)
-{
- time_t newval, t;
- char *ep;
-
- t = time(NULL);
- newval = (time_t)strtoul(val, &ep, 0);
- if (val == ep)
- errx(1, "invalid %s", cmd);
- if (afp->af_af != AF_INET6)
- errx(1, "%s not allowed for the AF", cmd);
- if (strcmp(cmd, "vltime") == 0) {
- in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
- in6_addreq.ifra_lifetime.ia6t_vltime = newval;
- } else if (strcmp(cmd, "pltime") == 0) {
- in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
- in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+ if (afp->af_getaddr != NULL) {
+ setmask++;
+ afp->af_getaddr(addr, MASK);
}
}
-void
-setip6eui64(const char *cmd, int dummy __unused, int s __unused,
- const struct afswtch *afp)
+static void
+setifbroadaddr(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
{
- struct ifaddrs *ifap, *ifa;
- const struct sockaddr_in6 *sin6 = NULL;
- const struct in6_addr *lladdr = NULL;
- struct in6_addr *in6;
-
- if (afp->af_af != AF_INET6)
- errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
- in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
- if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
- errx(EXIT_FAILURE, "interface index is already filled");
- if (getifaddrs(&ifap) != 0)
- err(EXIT_FAILURE, "getifaddrs");
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family == AF_INET6 &&
- strcmp(ifa->ifa_name, name) == 0) {
- sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
- lladdr = &sin6->sin6_addr;
- break;
- }
- }
- }
- if (!lladdr)
- errx(EXIT_FAILURE, "could not determine link local address");
-
- memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
-
- freeifaddrs(ifap);
+ if (afp->af_getaddr != NULL)
+ afp->af_getaddr(addr, DSTADDR);
}
-#endif
-void
-setifbroadaddr(const char *addr, int dummy __unused, int s __unused,
- const struct afswtch *afp)
+static void
+setifipdst(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
{
- if (*afp->af_getaddr == NULL)
- return;
- (*afp->af_getaddr)(addr, DSTADDR);
-}
+ const struct afswtch *inet;
-void
-setifipdst(const char *addr, int dummy __unused, int s __unused,
- const struct afswtch *afp __unused)
-{
- in_getaddr(addr, DSTADDR);
+ inet = af_getbyname("inet");
+ if (inet == NULL)
+ return;
+ inet->af_getaddr(addr, DSTADDR);
setipdst++;
clearaddr = 0;
newaddr = 0;
}
-#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
-void
-notealias(const char *addr __unused, int param, int s __unused,
- const struct afswtch *afp)
+static void
+notealias(const char *addr, int param, int s, const struct afswtch *afp)
{
+#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
if (setaddr && doalias == 0 && param < 0)
if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
bcopy((caddr_t)rqtosa(af_addreq),
@@ -1008,16 +683,16 @@
newaddr = 0;
} else
clearaddr = 0;
+#undef rqtosa
}
/*ARGSUSED*/
-void
-setifdstaddr(const char *addr, int param __unused, int s __unused,
- const struct afswtch *afp)
+static void
+setifdstaddr(const char *addr, int param __unused, int s,
+ const struct afswtch *afp)
{
- if (*afp->af_getaddr == NULL)
- return;
- (*afp->af_getaddr)(addr, DSTADDR);
+ if (afp->af_getaddr != NULL)
+ afp->af_getaddr(addr, DSTADDR);
}
/*
@@ -1025,9 +700,8 @@
* of the ifreq structure, which may confuse other parts of ifconfig.
* Make a private copy so we can avoid that.
*/
-void
-setifflags(const char *vname, int value, int s,
- const struct afswtch *afp __unused)
+static void
+setifflags(const char *vname, int value, int s, const struct afswtch *afp)
{
struct ifreq my_ifr;
@@ -1052,8 +726,7 @@
}
void
-setifcap(const char *vname, int value, int s,
- const struct afswtch *afp __unused)
+setifcap(const char *vname, int value, int s, const struct afswtch *afp)
{
if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
@@ -1071,9 +744,9 @@
Perror(vname);
}
-void
-setifmetric(const char *val, int dummy __unused, int s,
- const struct afswtch *afp __unused)
+static void
+setifmetric(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
{
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_metric = atoi(val);
@@ -1081,9 +754,9 @@
warn("ioctl (set metric)");
}
-void
-setifmtu(const char *val, int dummy __unused, int s,
- const struct afswtch *afp __unused)
+static void
+setifmtu(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
{
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_mtu = atoi(val);
@@ -1091,14 +764,17 @@
warn("ioctl (set mtu)");
}
-void
+static void
setifname(const char *val, int dummy __unused, int s,
- const struct afswtch *afp __unused)
+ const struct afswtch *afp)
{
- char *newname;
+ char *newname;
newname = strdup(val);
-
+ if (newname == NULL) {
+ warn("no memory to set ifname");
+ return;
+ }
ifr.ifr_data = newname;
if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
warn("ioctl (set name)");
@@ -1106,7 +782,6 @@
return;
}
strlcpy(name, newname, sizeof(name));
-
free(newname);
/*
@@ -1116,38 +791,62 @@
printname = 0;
}
+/*
+ * Expand the compacted form of addresses as returned via the
+ * configuration read via sysctl().
+ */
+#define SA_SIZE(sa) \
+ ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
+ sizeof(long) : \
+ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
+
+static void
+rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
+{
+ struct sockaddr *sa;
+ int i;
+
+ memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+ for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+ if ((rtinfo->rti_addrs & (1 << i)) == 0)
+ continue;
+ rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+ cp += SA_SIZE(sa);
+ }
+}
+
#define IFFBITS \
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
"\20MULTICAST\21POLLING\23MONITOR\24STATICARP"
#define IFCAPBITS \
-"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING"
+"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU"
/*
* Print the status of the interface. If an address family was
- * specified, show it and it only; otherwise, show them all.
+ * specified, show only it; otherwise, show them all.
*/
-void
-status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl,
- struct if_msghdr *ifm, struct ifa_msghdr *ifam)
+static void
+status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl,
+ struct if_msghdr *ifm, struct ifa_msghdr *ifam)
{
- const struct afswtch *p = NULL;
struct rt_addrinfo info;
int allfamilies, s;
struct ifstat ifs;
if (afp == NULL) {
allfamilies = 1;
- afp = &afs[0];
+ afp = af_getbyname("inet");
} else
allfamilies = 0;
ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
- strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
- err(1, "socket");
+ s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
+ if (s < 0)
+ err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
printf("%s: ", name);
printb("flags", flags, IFFBITS);
@@ -1163,8 +862,7 @@
putchar('\n');
}
if (supmedia && ifr.ifr_reqcap != 0) {
- printf("\tcapability list:\n");
- printb("\t\t", ifr.ifr_reqcap, IFCAPBITS);
+ printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
putchar('\n');
}
}
@@ -1172,395 +870,53 @@
tunnel_status(s);
while (addrcount > 0) {
-
info.rti_addrs = ifam->ifam_addrs;
-
/* Expand the compacted addresses */
rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
&info);
- if (!allfamilies) {
- if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) {
- p = afp;
- (*p->af_status)(s, &info);
- }
- } else for (p = afs; p->af_name; p++) {
- if (p->af_af == info.rti_info[RTAX_IFA]->sa_family)
- (*p->af_status)(s, &info);
- }
+ if (allfamilies) {
+ const struct afswtch *p;
+ p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family);
+ if (p != NULL)
+ p->af_status(s, &info);
+ } else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family)
+ afp->af_status(s, &info);
addrcount--;
ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
}
- if (allfamilies || afp->af_status == link_status)
- link_status(s, (struct rt_addrinfo *)sdl);
-#ifdef USE_IF_MEDIA
- if (allfamilies || afp->af_status == media_status)
- media_status(s, NULL);
-#endif
-#ifdef USE_VLANS
- if (allfamilies || afp->af_status == vlan_status)
- vlan_status(s, NULL);
-#endif
-#ifdef USE_IEEE80211
- if (allfamilies || afp->af_status == ieee80211_status)
- ieee80211_status(s, NULL);
-#endif
- strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
- if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
- printf("%s", ifs.ascii);
-
- if (!allfamilies && !p &&
-#ifdef USE_IF_MEDIA
- afp->af_status != media_status &&
-#endif
- afp->af_status != link_status
-#ifdef USE_VLANS
- && afp->af_status != vlan_status
-#endif
- )
- warnx("%s has no %s interface address!", name, afp->af_name);
-
- close(s);
- return;
-}
-
-void
-tunnel_status(int s)
-{
- char psrcaddr[NI_MAXHOST];
- char pdstaddr[NI_MAXHOST];
- u_long srccmd, dstcmd;
- struct ifreq *ifrp;
- const char *ver = "";
-#ifdef NI_WITHSCOPEID
- const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
-#else
- const int niflag = NI_NUMERICHOST;
-#endif
-#ifdef INET6
- struct in6_ifreq in6_ifr;
- int s6;
-#endif /* INET6 */
-
- psrcaddr[0] = pdstaddr[0] = '\0';
-
-#ifdef INET6
- memset(&in6_ifr, 0, sizeof(in6_ifr));
- strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
- s6 = socket(AF_INET6, SOCK_DGRAM, 0);
- if (s6 < 0) {
- srccmd = SIOCGIFPSRCADDR;
- dstcmd = SIOCGIFPDSTADDR;
- ifrp = 𝔦
- } else {
- close(s6);
- srccmd = SIOCGIFPSRCADDR_IN6;
- dstcmd = SIOCGIFPDSTADDR_IN6;
- ifrp = (struct ifreq *)&in6_ifr;
- }
-#else /* INET6 */
- srccmd = SIOCGIFPSRCADDR;
- dstcmd = SIOCGIFPDSTADDR;
- ifrp = 𝔦
-#endif /* INET6 */
-
- if (ioctl(s, srccmd, (caddr_t)ifrp) < 0)
- return;
-#if defined(INET6) && defined(__KAME__) && defined(KAME_SCOPEID)
- if (ifrp->ifr_addr.sa_family == AF_INET6)
- in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
-#endif
- getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
- psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
-#ifdef INET6
- if (ifrp->ifr_addr.sa_family == AF_INET6)
- ver = "6";
-#endif
-
- if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0)
- return;
-#if defined(INET6) && defined(__KAME__) && defined(KAME_SCOPEID)
- if (ifrp->ifr_addr.sa_family == AF_INET6)
- in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
-#endif
- getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
- pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
-
- printf("\ttunnel inet%s %s --> %s\n", ver,
- psrcaddr, pdstaddr);
-}
-
-void
-in_status(int s __unused, struct rt_addrinfo *info)
-{
- struct sockaddr_in *addr_in, null_in;
-
- memset(&null_in, 0, sizeof(null_in));
-
- addr_in = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
- printf("\tinet %s ", inet_ntoa(addr_in->sin_addr));
-
- if (flags & IFF_POINTOPOINT) {
- /* note RTAX_BRD overlap with IFF_BROADCAST */
- addr_in = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
- if (!addr_in)
- addr_in = &null_in;
- printf("--> %s ", inet_ntoa(addr_in->sin_addr));
- }
-
- addr_in = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
- if (!addr_in)
- addr_in = &null_in;
- printf("netmask 0x%lx ",
- (unsigned long)ntohl(addr_in->sin_addr.s_addr));
-
- if (flags & IFF_BROADCAST) {
- /* note RTAX_BRD overlap with IFF_POINTOPOINT */
- addr_in = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
- if (addr_in && addr_in->sin_addr.s_addr != 0)
- printf("broadcast %s", inet_ntoa(addr_in->sin_addr));
- }
- putchar('\n');
-}
-
-#ifdef INET6
-#if defined(__KAME__) && defined(KAME_SCOPEID)
-void
-in6_fillscopeid(struct sockaddr_in6 *sin6 __unused)
-{
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
- sin6->sin6_scope_id =
- ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
- sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
- }
-}
-#endif /* defined(__KAME__) && defined(KAME_SCOPEID) */
-
-void
-in6_status(int s __unused, struct rt_addrinfo *info)
-{
- struct sockaddr_in6 *addr_in, null_in;
- struct in6_ifreq ifr6;
- int s6;
- u_int32_t flags6;
- struct in6_addrlifetime lifetime;
- time_t t = time(NULL);
- int error;
- u_int32_t scopeid;
-
- memset(&null_in, 0, sizeof(null_in));
-
- addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
- strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
- if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- perror("ifconfig: socket");
- return;
- }
- ifr6.ifr_addr = *addr_in;
- if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
- perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)");
- close(s6);
- return;
- }
- flags6 = ifr6.ifr_ifru.ifru_flags6;
- memset(&lifetime, 0, sizeof(lifetime));
- ifr6.ifr_addr = *addr_in;
- if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
- perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)");
- close(s6);
- return;
- }
- lifetime = ifr6.ifr_ifru.ifru_lifetime;
- close(s6);
+ if (allfamilies || afp->af_af == AF_LINK) {
+ const struct afswtch *lafp;
- /* XXX: embedded link local addr check */
- if (IN6_IS_ADDR_LINKLOCAL(&addr_in->sin6_addr) &&
- *(u_short *)&addr_in->sin6_addr.s6_addr[2] != 0) {
- u_short idx;
-
- idx = *(u_short *)&addr_in->sin6_addr.s6_addr[2];
- *(u_short *)&addr_in->sin6_addr.s6_addr[2] = 0;
- if (addr_in->sin6_scope_id == 0)
- addr_in->sin6_scope_id = ntohs(idx);
- }
- scopeid = addr_in->sin6_scope_id;
-
- error = getnameinfo((struct sockaddr *)addr_in, addr_in->sin6_len, addr_buf,
- sizeof(addr_buf), NULL, 0,
- NI_NUMERICHOST|NI_WITHSCOPEID);
- if (error != 0)
- inet_ntop(AF_INET6, &addr_in->sin6_addr, addr_buf,
- sizeof(addr_buf));
- printf("\tinet6 %s ", addr_buf);
-
- if (flags & IFF_POINTOPOINT) {
- /* note RTAX_BRD overlap with IFF_BROADCAST */
- addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
/*
- * some of the interfaces do not have valid destination
- * address.
+ * Hack; the link level address is received separately
+ * from the routing information so any address is not
+ * handled above. Cobble together an entry and invoke
+ * the status method specially.
*/
- if (addr_in && addr_in->sin6_family == AF_INET6) {
- /* XXX: embedded link local addr check */
- if (IN6_IS_ADDR_LINKLOCAL(&addr_in->sin6_addr) &&
- *(u_short *)&addr_in->sin6_addr.s6_addr[2] != 0) {
- u_short idx;
-
- idx = *(u_short *)&addr_in->sin6_addr.s6_addr[2];
- *(u_short *)&addr_in->sin6_addr.s6_addr[2] = 0;
- if (addr_in->sin6_scope_id == 0)
- addr_in->sin6_scope_id = ntohs(idx);
- }
-
- error = getnameinfo((struct sockaddr *)addr_in,
- addr_in->sin6_len, addr_buf,
- sizeof(addr_buf), NULL, 0,
- NI_NUMERICHOST|NI_WITHSCOPEID);
- if (error != 0)
- inet_ntop(AF_INET6, &addr_in->sin6_addr, addr_buf,
- sizeof(addr_buf));
- printf("--> %s ", addr_buf);
+ lafp = af_getbyname("lladdr");
+ if (lafp != NULL) {
+ info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
+ lafp->af_status(s, &info);
}
}
+ if (allfamilies)
+ af_other_status(s);
+ afp->af_other_status(s);
- addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
- if (!addr_in)
- addr_in = &null_in;
- printf("prefixlen %d ", prefix(&addr_in->sin6_addr,
- sizeof(struct in6_addr)));
-
- if ((flags6 & IN6_IFF_ANYCAST) != 0)
- printf("anycast ");
- if ((flags6 & IN6_IFF_TENTATIVE) != 0)
- printf("tentative ");
- if ((flags6 & IN6_IFF_DUPLICATED) != 0)
- printf("duplicated ");
- if ((flags6 & IN6_IFF_DETACHED) != 0)
- printf("detached ");
- if ((flags6 & IN6_IFF_DEPRECATED) != 0)
- printf("deprecated ");
- if ((flags6 & IN6_IFF_AUTOCONF) != 0)
- printf("autoconf ");
- if ((flags6 & IN6_IFF_TEMPORARY) != 0)
- printf("temporary ");
-
- if (scopeid)
- printf("scopeid 0x%x ", scopeid);
-
- if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
- printf("pltime ");
- if (lifetime.ia6t_preferred) {
- printf("%s ", lifetime.ia6t_preferred < t
- ? "0" : sec2str(lifetime.ia6t_preferred - t));
- } else
- printf("infty ");
-
- printf("vltime ");
- if (lifetime.ia6t_expire) {
- printf("%s ", lifetime.ia6t_expire < t
- ? "0" : sec2str(lifetime.ia6t_expire - t));
- } else
- printf("infty ");
- }
-
- putchar('\n');
-}
-#endif /*INET6*/
-
-#ifndef NO_IPX
-void
-ipx_status(int s __unused, struct rt_addrinfo *info)
-{
- struct sockaddr_ipx *sipx, null_sipx;
-
- memset(&null_sipx, 0, sizeof(null_sipx));
-
- sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
- printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
-
- if (flags & IFF_POINTOPOINT) {
- sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
- if (!sipx)
- sipx = &null_sipx;
- printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
- }
- putchar('\n');
-}
-#endif
-
-void
-at_status(int s __unused, struct rt_addrinfo *info)
-{
- struct sockaddr_at *sat, null_sat;
- struct netrange *nr;
-
- memset(&null_sat, 0, sizeof(null_sat));
-
- sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
- nr = &sat->sat_range.r_netrange;
- printf("\tatalk %d.%d range %d-%d phase %d",
- ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
- ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
- if (flags & IFF_POINTOPOINT) {
- /* note RTAX_BRD overlap with IFF_BROADCAST */
- sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
- if (!sat)
- sat = &null_sat;
- printf("--> %d.%d",
- ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
- }
- if (flags & IFF_BROADCAST) {
- /* note RTAX_BRD overlap with IFF_POINTOPOINT */
- sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
- if (sat)
- printf(" broadcast %d.%d",
- ntohs(sat->sat_addr.s_net),
- sat->sat_addr.s_node);
- }
-
- putchar('\n');
-}
-
-#ifdef NS
-void
-xns_status(int s __unused, struct rt_addrinfo *info)
-{
- struct sockaddr_ns *sns, null_sns;
-
- memset(&null_sns, 0, sizeof(null_sns));
-
- sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA];
- printf("\tns %s ", ns_ntoa(sns->sns_addr));
-
- if (flags & IFF_POINTOPOINT) {
- sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD];
- if (!sns)
- sns = &null_sns;
- printf("--> %s ", ns_ntoa(sns->sns_addr));
- }
+ strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
+ if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
+ printf("%s", ifs.ascii);
- putchar('\n');
close(s);
+ return;
}
-#endif
-
-void
-link_status(int s __unused, struct rt_addrinfo *info)
+static void
+tunnel_status(int s)
{
- struct sockaddr_dl *sdl = (struct sockaddr_dl *)info;
-
- if (sdl->sdl_alen > 0) {
- if (sdl->sdl_type == IFT_ETHER &&
- sdl->sdl_alen == ETHER_ADDR_LEN)
- printf("\tether %s\n",
- ether_ntoa((struct ether_addr *)LLADDR(sdl)));
- else {
- int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
-
- printf("\tlladdr %s\n", link_ntoa(sdl) + n);
- }
- }
+ af_all_tunnel_status(s);
}
void
@@ -1581,116 +937,6 @@
}
}
-#define SIN(x) ((struct sockaddr_in *) &(x))
-struct sockaddr_in *sintab[] = {
-SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
-SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
-
-void
-in_getaddr(const char *s, int which)
-{
- struct sockaddr_in *addr_in = sintab[which];
- struct hostent *hp;
- struct netent *np;
-
- addr_in->sin_len = sizeof(*addr_in);
- if (which != MASK)
- addr_in->sin_family = AF_INET;
-
- if (which == ADDR) {
- char *p = NULL;
-
- if((p = strrchr(s, '/')) != NULL) {
- /* address is `name/masklen' */
- int masklen;
- int ret;
- struct sockaddr_in *min = sintab[MASK];
- *p = '\0';
- ret = sscanf(p+1, "%u", &masklen);
- if(ret != 1 || (masklen < 0 || masklen > 32)) {
- *p = '/';
- errx(1, "%s: bad value", s);
- }
- min->sin_len = sizeof(*min);
- min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) &
- 0xffffffff);
- }
- }
-
- if (inet_aton(s, &addr_in->sin_addr))
- return;
- if ((hp = gethostbyname(s)) != 0)
- bcopy(hp->h_addr, (char *)&addr_in->sin_addr,
- MIN((size_t)hp->h_length, sizeof(addr_in->sin_addr)));
- else if ((np = getnetbyname(s)) != 0)
- addr_in->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
- else
- errx(1, "%s: bad value", s);
-}
-
-#ifdef INET6
-#define SIN6(x) ((struct sockaddr_in6 *) &(x))
-struct sockaddr_in6 *sin6tab[] = {
-SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
-SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
-
-void
-in6_getaddr(const char *s, int which)
-{
- struct sockaddr_in6 *addr_in = sin6tab[which];
- struct addrinfo hints, *res;
- int error = -1;
-
- newaddr &= 1;
-
- addr_in->sin6_len = sizeof(*addr_in);
- if (which != MASK)
- addr_in->sin6_family = AF_INET6;
-
- if (which == ADDR) {
- char *p = NULL;
- if((p = strrchr(s, '/')) != NULL) {
- *p = '\0';
- in6_getprefix(p + 1, MASK);
- explicit_prefix = 1;
- }
- }
-
- if (addr_in->sin6_family == AF_INET6) {
- bzero(&hints, sizeof(struct addrinfo));
- hints.ai_family = AF_INET6;
- error = getaddrinfo(s, NULL, &hints, &res);
- }
- if (error != 0) {
- if (inet_pton(AF_INET6, s, &addr_in->sin6_addr) != 1)
- errx(1, "%s: bad value", s);
- } else
- bcopy(res->ai_addr, addr_in, res->ai_addrlen);
-}
-
-void
-in6_getprefix(const char *plen, int which)
-{
- struct sockaddr_in6 *addr_in = sin6tab[which];
- u_char *cp;
- int len = atoi(plen);
-
- if ((len < 0) || (len > 128))
- errx(1, "%s: bad value", plen);
- addr_in->sin6_len = sizeof(*addr_in);
- if (which != MASK)
- addr_in->sin6_family = AF_INET6;
- if ((len == 0) || (len == 128)) {
- memset(&addr_in->sin6_addr, 0xff, sizeof(struct in6_addr));
- return;
- }
- memset((void *)&addr_in->sin6_addr, 0x00, sizeof(addr_in->sin6_addr));
- for (cp = (u_char *)&addr_in->sin6_addr; len > 7; len -= 8)
- *cp++ = 0xff;
- *cp = 0xff << (8 - len);
-}
-#endif
-
/*
* Print a value a la the %b format of the kernel's printf
*/
@@ -1722,200 +968,16 @@
}
}
-#ifndef NO_IPX
-#define SIPX(x) ((struct sockaddr_ipx *) &(x))
-struct sockaddr_ipx *sipxtab[] = {
-SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
-SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
-
-void
-ipx_getaddr(const char *addr, int which)
-{
- struct sockaddr_ipx *sipx = sipxtab[which];
-
- sipx->sipx_family = AF_IPX;
- sipx->sipx_len = sizeof(*sipx);
- sipx->sipx_addr = ipx_addr(addr);
- if (which == MASK)
- printf("Attempt to set IPX netmask will be ineffectual\n");
-}
-#endif
-
-void
-at_getaddr(const char *addr, int which)
-{
- struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
- u_int net, node;
-
- sat->sat_family = AF_APPLETALK;
- sat->sat_len = sizeof(*sat);
- if (which == MASK)
- errx(1, "AppleTalk does not use netmasks");
- if (sscanf(addr, "%u.%u", &net, &node) != 2
- || net > 0xffff || node > 0xfe)
- errx(1, "%s: illegal address", addr);
- sat->sat_addr.s_net = htons(net);
- sat->sat_addr.s_node = node;
-}
-
-void
-link_getaddr(const char *addr, int which)
-{
- char *temp;
- struct sockaddr_dl sdl;
- struct sockaddr *sa = &ridreq.ifr_addr;
-
- if (which != ADDR)
- errx(1, "can't set link-level netmask or broadcast");
- if ((temp = malloc(strlen(addr) + 1)) == NULL)
- errx(1, "malloc failed");
- temp[0] = ':';
- strcpy(temp + 1, addr);
- sdl.sdl_len = sizeof(sdl);
- link_addr(temp, &sdl);
- free(temp);
- if (sdl.sdl_alen > sizeof(sa->sa_data))
- errx(1, "malformed link-level address");
- sa->sa_family = AF_LINK;
- sa->sa_len = sdl.sdl_alen;
- bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
-}
-
-/* XXX FIXME -- should use strtoul for better parsing. */
-void
-setatrange(const char *range, int dummy __unused, int s __unused,
- const struct afswtch *afp __unused)
-{
- u_int first = 123, last = 123;
-
- if (sscanf(range, "%u-%u", &first, &last) != 2
- || first == 0 || first > 0xffff
- || last == 0 || last > 0xffff || first > last)
- errx(1, "%s: illegal net range: %u-%u", range, first, last);
- at_nr.nr_firstnet = htons(first);
- at_nr.nr_lastnet = htons(last);
-}
-
-void
-setatphase(const char *phase, int dummy __unused, int s __unused,
- const struct afswtch *afp __unused)
-{
- if (!strcmp(phase, "1"))
- at_nr.nr_phase = 1;
- else if (!strcmp(phase, "2"))
- at_nr.nr_phase = 2;
- else
- errx(1, "%s: illegal phase", phase);
-}
-
-void
-checkatrange(struct sockaddr_at *sat)
-{
- if (at_nr.nr_phase == 0)
- at_nr.nr_phase = 2; /* Default phase 2 */
- if (at_nr.nr_firstnet == 0)
- at_nr.nr_firstnet = /* Default range of one */
- at_nr.nr_lastnet = sat->sat_addr.s_net;
-printf("\tatalk %d.%d range %d-%d phase %d\n",
- ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
- ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
- if ((u_short) ntohs(at_nr.nr_firstnet) >
- (u_short) ntohs(sat->sat_addr.s_net)
- || (u_short) ntohs(at_nr.nr_lastnet) <
- (u_short) ntohs(sat->sat_addr.s_net))
- errx(1, "AppleTalk address is not in range");
- sat->sat_range.r_netrange = at_nr;
-}
-
-#ifdef NS
-#define SNS(x) ((struct sockaddr_ns *) &(x))
-struct sockaddr_ns *snstab[] = {
-SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
-SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
-
-void
-xns_getaddr(const char *addr, int which)
-{
- struct sockaddr_ns *sns = snstab[which];
-
- sns->sns_family = AF_NS;
- sns->sns_len = sizeof(*sns);
- sns->sns_addr = ns_addr(addr);
- if (which == MASK)
- printf("Attempt to set XNS netmask will be ineffectual\n");
-}
-#endif
-
-#ifdef INET6
-int
-prefix(void *val, int size)
-{
- u_char *addr = (u_char *)val;
- int byte, bit, plen = 0;
-
- for (byte = 0; byte < size; byte++, plen += 8)
- if (addr[byte] != 0xff)
- break;
- if (byte == size)
- return (plen);
- for (bit = 7; bit != 0; bit--, plen++)
- if (!(addr[byte] & (1 << bit)))
- break;
- for (; bit != 0; bit--)
- if (addr[byte] & (1 << bit))
- return(0);
- byte++;
- for (; byte < size; byte++)
- if (addr[byte])
- return(0);
- return (plen);
-}
-
-static char *
-sec2str(time_t total)
-{
- static char result[256];
- int days, hours, mins, secs;
- int first = 1;
- char *p = result;
-
- if (0) {
- days = total / 3600 / 24;
- hours = (total / 3600) % 24;
- mins = (total / 60) % 60;
- secs = total % 60;
-
- if (days) {
- first = 0;
- p += sprintf(p, "%dd", days);
- }
- if (!first || hours) {
- first = 0;
- p += sprintf(p, "%dh", hours);
- }
- if (!first || mins) {
- first = 0;
- p += sprintf(p, "%dm", mins);
- }
- sprintf(p, "%ds", secs);
- } else
- sprintf(result, "%lu", (unsigned long)total);
-
- return(result);
-}
-#endif /*INET6*/
-
void
-ifmaybeload(char *if_nm)
+ifmaybeload(char *name)
{
struct module_stat mstat;
int fileid, modid;
char ifkind[35], *cp, *dp;
-
/* turn interface and unit into module name */
strcpy(ifkind, "if_");
- for (cp = if_nm, dp = ifkind + 3;
+ for (cp = name, dp = ifkind + 3;
(*cp != 0) && !isdigit(*cp); cp++, dp++)
*dp = *cp;
*dp = 0;
@@ -1935,8 +997,8 @@
cp = mstat.name;
}
/* already loaded? */
- if (strncmp(if_nm, cp, strlen(cp)) == 0 ||
- strncmp(ifkind, cp, strlen(cp)) == 0)
+ if (strncmp(name, cp, strlen(cp)) == 0 ||
+ strncmp(ifkind, cp, strlen(cp)) == 0)
return;
}
}
@@ -1945,87 +1007,61 @@
kldload(ifkind);
}
-void
-list_cloners(void)
-{
- struct if_clonereq ifcr;
- char *cp, *buf;
- int idx;
- int s;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s == -1)
- err(1, "socket");
-
- memset(&ifcr, 0, sizeof(ifcr));
-
- if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
- err(1, "SIOCIFGCLONERS for count");
-
- buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
- if (buf == NULL)
- err(1, "unable to allocate cloner name buffer");
-
- ifcr.ifcr_count = ifcr.ifcr_total;
- ifcr.ifcr_buffer = buf;
-
- if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
- err(1, "SIOCIFGCLONERS for names");
-
- /*
- * In case some disappeared in the mean time, clamp it down.
- */
- if (ifcr.ifcr_count > ifcr.ifcr_total)
- ifcr.ifcr_count = ifcr.ifcr_total;
-
- for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
- if (idx > 0)
- putchar(' ');
- printf("%s", cp);
- }
-
- putchar('\n');
- free(buf);
-}
-
-void
-clone_create(void)
-{
- int s;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s == -1)
- err(1, "socket");
-
- memset(&ifr, 0, sizeof(ifr));
- (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
- err(1, "SIOCIFCREATE");
-
- /*
- * If we get a different name back then we put in, we probably
- * want to print it out, but we might change our mind later so
- * we just signal our intrest and leave the printout for later.
- */
- if (strcmp(name, ifr.ifr_name) != 0) {
- printname = 1;
- strlcpy(name, ifr.ifr_name, sizeof(name));
- }
-
- close(s);
-}
+static struct cmd basic_cmds[] = {
+ DEF_CMD("up", IFF_UP, setifflags),
+ DEF_CMD("down", -IFF_UP, setifflags),
+ DEF_CMD("arp", -IFF_NOARP, setifflags),
+ DEF_CMD("-arp", IFF_NOARP, setifflags),
+ DEF_CMD("debug", IFF_DEBUG, setifflags),
+ DEF_CMD("-debug", -IFF_DEBUG, setifflags),
+ DEF_CMD("promisc", IFF_PPROMISC, setifflags),
+ DEF_CMD("-promisc", -IFF_PPROMISC, setifflags),
+ DEF_CMD("add", IFF_UP, notealias),
+ DEF_CMD("alias", IFF_UP, notealias),
+ DEF_CMD("-alias", -IFF_UP, notealias),
+ DEF_CMD("delete", -IFF_UP, notealias),
+ DEF_CMD("remove", -IFF_UP, notealias),
+#ifdef notdef
+#define EN_SWABIPS 0x1000
+ DEF_CMD("swabips", EN_SWABIPS, setifflags),
+ DEF_CMD("-swabips", -EN_SWABIPS, setifflags),
+#endif
+ DEF_CMD_ARG("netmask", setifnetmask),
+ DEF_CMD_ARG("metric", setifmetric),
+ DEF_CMD_ARG("broadcast", setifbroadaddr),
+ DEF_CMD_ARG("ipdst", setifipdst),
+ DEF_CMD_ARG2("tunnel", settunnel),
+ DEF_CMD("deletetunnel", 0, deletetunnel),
+ DEF_CMD("link0", IFF_LINK0, setifflags),
+ DEF_CMD("-link0", -IFF_LINK0, setifflags),
+ DEF_CMD("link1", IFF_LINK1, setifflags),
+ DEF_CMD("-link1", -IFF_LINK1, setifflags),
+ DEF_CMD("link2", IFF_LINK2, setifflags),
+ DEF_CMD("-link2", -IFF_LINK2, setifflags),
+ DEF_CMD("monitor", IFF_MONITOR, setifflags),
+ DEF_CMD("-monitor", -IFF_MONITOR, setifflags),
+ DEF_CMD("staticarp", IFF_STATICARP, setifflags),
+ DEF_CMD("-staticarp", -IFF_STATICARP, setifflags),
+ DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap),
+ DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap),
+ DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap),
+ DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap),
+ DEF_CMD("netcons", IFCAP_NETCONS, setifcap),
+ DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap),
+ DEF_CMD("normal", -IFF_LINK0, setifflags),
+ DEF_CMD("compress", IFF_LINK0, setifflags),
+ DEF_CMD("noicmp", IFF_LINK1, setifflags),
+ DEF_CMD_ARG("mtu", setifmtu),
+ DEF_CMD_ARG("name", setifname),
+};
-void
-clone_destroy(const char *val __unused, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static __constructor void
+ifconfig_ctor(void)
{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
- (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
- err(1, "SIOCIFDESTROY");
- /*
- * If we create and destroy an interface in the same command,
- * there isn't any reason to print it's name.
- */
- printname = 0;
+ for (i = 0; i < N(basic_cmds); i++)
+ cmd_register(&basic_cmds[i]);
+#undef N
}
diff -N -u -r src.preview/sbin/ifconfig/ifconfig.h src/sbin/ifconfig/ifconfig.h
--- src.preview/sbin/ifconfig/ifconfig.h 2005-04-25 13:33:26.000000000 -0400
+++ src/sbin/ifconfig/ifconfig.h 2005-09-27 15:02:10.000000000 -0400
@@ -31,41 +31,112 @@
*
* so there!
*
- * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.12 2004/03/30 22:59:22 sam Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.h,v 1.5 2005/04/25 17:33:26 swildner Exp $
+ * $FreeBSD$
*/
-extern struct ifreq ifr;
+#define __constructor __attribute__((constructor))
-extern char name[IFNAMSIZ]; /* name of interface */
-extern int allmedia;
-extern int supmedia;
struct afswtch;
+struct cmd;
-extern void setmedia(const char *, int, int, const struct afswtch *rafp);
-extern void setmediamode(const char *, int, int, const struct afswtch *rafp);
-extern void setmediaopt(const char *, int, int, const struct afswtch *rafp);
-extern void unsetmediaopt(const char *, int, int, const struct afswtch *rafp);
-extern void media_status(int s, struct rt_addrinfo *);
-
-extern void setvlantag(const char *, int, int, const struct afswtch *rafp);
-extern void setvlandev(const char *, int, int, const struct afswtch *rafp);
-extern void unsetvlandev(const char *, int, int, const struct afswtch *rafp);
-extern void vlan_status(int s, struct rt_addrinfo *);
-
-extern void set80211ssid(const char *, int, int, const struct afswtch *rafp);
-extern void set80211stationname(const char *, int, int, const struct afswtch *rafp);
-extern void set80211channel(const char *, int, int, const struct afswtch *rafp);
-extern void set80211authmode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211powersave(const char *, int, int, const struct afswtch *rafp);
-extern void set80211powersavemode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211powersavesleep(const char *, int, int, const struct afswtch *rafp);
-extern void set80211wepmode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211wep(const char *, int, int, const struct afswtch *rafp);
-extern void set80211weptxkey(const char *, int, int, const struct afswtch *rafp);
-extern void set80211wepkey(const char *, int, int, const struct afswtch *rafp);
-extern void set80211nwkey(const char *, int, int, const struct afswtch *rafp);
-extern void set80211rtsthreshold(const char *, int, int, const struct afswtch *rafp);
-extern void set80211protmode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211txpower(const char *, int, int, const struct afswtch *rafp);
-extern void ieee80211_status(int s, struct rt_addrinfo *);
+typedef void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
+typedef void c_func2(const char *arg1, const char *arg2, int s, const struct afswtch *afp);
+
+struct cmd {
+ const char *c_name;
+ int c_parameter;
+#define NEXTARG 0xffffff /* has following arg */
+#define NEXTARG2 0xfffffe /* has 2 following args */
+#define OPTARG 0xfffffd /* has optional following arg */
+ union {
+ c_func *c_func;
+ c_func2 *c_func2;
+ } c_u;
+ struct cmd *c_next;
+};
+void cmd_register(struct cmd *);
+
+typedef void callback_func(int s, void *);
+void callback_register(callback_func *, void *);
+
+/*
+ * Macros for declaring command functions and initializing entries.
+ */
+#define DECL_CMD_FUNC(name, cmd, arg) \
+ void name(const char *cmd, int arg, int s, const struct afswtch *afp)
+#define DECL_CMD_FUNC2(name, arg1, arg2) \
+ void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp)
+
+#define DEF_CMD(name, param, func) { name, param, { .c_func = func } }
+#define DEF_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func } }
+#define DEF_CMD_OPTARG(name, func) { name, OPTARG, { .c_func = func } }
+#define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func } }
+
+struct rt_addrinfo;
+struct addrinfo;
+
+enum {
+ RIDADDR,
+ ADDR,
+ MASK,
+ DSTADDR,
+};
+
+struct afswtch {
+ const char *af_name; /* as given on cmd line, e.g. "inet" */
+ short af_af; /* AF_* */
+ /*
+ * Status is handled one of two ways; if there is an
+ * address associated with the interface then the
+ * associated address family af_status method is invoked
+ * with the appropriate addressin info. Otherwise, if
+ * all possible info is to be displayed and af_other_status
+ * is defined then it is invoked after all address status
+ * is presented.
+ */
+ void (*af_status)(int, const struct rt_addrinfo *);
+ void (*af_other_status)(int);
+ /* parse address method */
+ void (*af_getaddr)(const char *, int);
+ /* parse prefix method (IPv6) */
+ void (*af_getprefix)(const char *, int);
+ void (*af_postproc)(int s, const struct afswtch *);
+ u_long af_difaddr; /* set dst if address ioctl */
+ u_long af_aifaddr; /* set if address ioctl */
+ void *af_ridreq; /* */
+ void *af_addreq; /* */
+ struct afswtch *af_next;
+
+ /* XXX doesn't fit model */
+ void (*af_status_tunnel)(int);
+ void (*af_settunnel)(int s, struct addrinfo *srcres,
+ struct addrinfo *dstres);
+};
+void af_register(struct afswtch *);
+
+struct option {
+ const char *opt;
+ const char *opt_usage;
+ void (*cb)(const char *arg);
+ struct option *next;
+};
+void opt_register(struct option *);
+
+extern struct ifreq ifr;
+extern char name[IFNAMSIZ]; /* name of interface */
+extern int allmedia;
+extern int supmedia;
+extern int printname;
+extern int flags;
+extern int newaddr;
+extern int verbose;
+extern int setipdst;
+
+void setifcap(const char *, int value, int s, const struct afswtch *);
+
+void Perror(const char *cmd);
+void printb(const char *s, unsigned value, const char *bits);
+
+void ifmaybeload(char *name);
+
+void clone_create(void);
diff -N -u -r src.preview/sbin/ifconfig/ifieee80211.c src/sbin/ifconfig/ifieee80211.c
--- src.preview/sbin/ifconfig/ifieee80211.c 2005-03-06 00:01:59.000000000 -0500
+++ src/sbin/ifconfig/ifieee80211.c 2005-09-27 15:02:10.000000000 -0400
@@ -24,8 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.1.2.3 2002/02/07 15:12:37 ambrisko Exp $
- * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.8 2005/03/06 05:01:59 dillon Exp $
+ * $FreeBSD$
*/
/*-
@@ -75,7 +74,10 @@
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_media.h>
#include <net/route.h>
+
+#include <netproto/802_11/ieee80211_dragonfly.h>
#include <netproto/802_11/ieee80211.h>
#include <netproto/802_11/ieee80211_crypto.h>
#include <netproto/802_11/ieee80211_ioctl.h>
@@ -96,9 +98,15 @@
u_int8_t *buf, int *lenp);
static void print_string(const u_int8_t *buf, int len);
-void
-set80211ssid(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static int
+isanyarg(const char *arg)
+{
+ return (strcmp(arg, "-") == 0 ||
+ strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
+}
+
+static void
+set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
{
int ssid;
int len;
@@ -118,9 +126,8 @@
set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
}
-void
-set80211stationname(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
{
int len;
u_int8_t data[33];
@@ -132,19 +139,50 @@
set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
}
-void
-set80211channel(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+static u_int
+ieee80211_ieee2mhz(u_int chan)
+{
+ if (chan == 14)
+ return 2484;
+ if (chan < 14) /* 0-13 */
+ return 2407 + chan*5;
+ if (chan < 27) /* 15-26 */
+ return 2512 + ((chan-15)*20);
+ return 5000 + (chan*5);
+}
+
+/*
+ * Convert MHz frequency to IEEE channel number.
+ */
+static u_int
+ieee80211_mhz2ieee(u_int freq)
+{
+ if (freq == 2484)
+ return 14;
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+ if (freq < 5000)
+ return 15 + ((freq - 2512) / 20);
+ return (freq - 5000) / 5;
+}
+
+static void
+set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
{
- if (strcmp(val, "-") == 0)
+ if (!isanyarg(val)) {
+ int v = atoi(val);
+ if (v > 255) /* treat as frequency */
+ v = ieee80211_mhz2ieee(v);
+ set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
+ } else
set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
- else
- set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
}
-void
-set80211authmode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -154,6 +192,10 @@
mode = IEEE80211_AUTH_OPEN;
} else if (strcasecmp(val, "shared") == 0) {
mode = IEEE80211_AUTH_SHARED;
+ } else if (strcasecmp(val, "8021x") == 0) {
+ mode = IEEE80211_AUTH_8021X;
+ } else if (strcasecmp(val, "wpa") == 0) {
+ mode = IEEE80211_AUTH_WPA;
} else {
err(1, "unknown authmode");
}
@@ -161,9 +203,8 @@
set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
}
-void
-set80211powersavemode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -184,9 +225,8 @@
set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
}
-void
-set80211powersave(const char *val __unused, int d, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
{
if (d == 0)
set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
@@ -196,16 +236,14 @@
0, NULL);
}
-void
-set80211powersavesleep(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
}
-void
-set80211wepmode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -222,23 +260,29 @@
set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
}
-void
-set80211wep(const char *val __unused, int d, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
}
-void
-set80211weptxkey(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static int
+isundefarg(const char *arg)
{
- set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
+ return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
}
-void
-set80211wepkey(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ if (isundefarg(val))
+ set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
+ else
+ set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
+}
+
+static void
+set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
{
int key = 0;
int len;
@@ -261,9 +305,8 @@
* iterface is too inflexable, but it's there so we'll support it since
* it's not all that hard.
*/
-void
-set80211nwkey(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
{
int txkey;
int i, len;
@@ -298,16 +341,14 @@
set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
}
-void
-set80211rtsthreshold(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL);
}
-void
-set80211protmode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -324,160 +365,1049 @@
set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
}
-void
-set80211txpower(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+static void
+set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
}
-void
-ieee80211_status (int s, struct rt_addrinfo *info __unused)
+#define IEEE80211_ROAMING_DEVICE 0
+#define IEEE80211_ROAMING_AUTO 1
+#define IEEE80211_ROAMING_MANUAL 2
+
+static void
+set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
{
- int i;
- int num;
- struct ieee80211req ireq;
- u_int8_t data[32];
- char spacer;
+ int mode;
+
+ if (strcasecmp(val, "device") == 0) {
+ mode = IEEE80211_ROAMING_DEVICE;
+ } else if (strcasecmp(val, "auto") == 0) {
+ mode = IEEE80211_ROAMING_AUTO;
+ } else if (strcasecmp(val, "manual") == 0) {
+ mode = IEEE80211_ROAMING_MANUAL;
+ } else {
+ err(1, "unknown roaming mode");
+ }
+ set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
+}
+
+static void
+set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
+}
+
+static void
+set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
+}
+
+static void
+set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
+}
+
+static void
+set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ struct ieee80211req_chanlist chanlist;
+#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
+ char *temp, *cp, *tp;
+
+ temp = malloc(strlen(val) + 1);
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ strcpy(temp, val);
+ memset(&chanlist, 0, sizeof(chanlist));
+ cp = temp;
+ for (;;) {
+ int first, last, f;
+
+ tp = strchr(cp, ',');
+ if (tp != NULL)
+ *tp++ = '\0';
+ switch (sscanf(cp, "%u-%u", &first, &last)) {
+ case 1:
+ if (first > MAXCHAN)
+ errx(-1, "channel %u out of range, max %u",
+ first, MAXCHAN);
+ setbit(chanlist.ic_channels, first);
+ break;
+ case 2:
+ if (first > MAXCHAN)
+ errx(-1, "channel %u out of range, max %u",
+ first, MAXCHAN);
+ if (last > MAXCHAN)
+ errx(-1, "channel %u out of range, max %u",
+ last, MAXCHAN);
+ if (first > last)
+ errx(-1, "void channel range, %u > %u",
+ first, last);
+ for (f = first; f <= last; f++)
+ setbit(chanlist.ic_channels, f);
+ break;
+ }
+ if (tp == NULL)
+ break;
+ while (isspace(*tp))
+ tp++;
+ if (!isdigit(*tp))
+ break;
+ cp = tp;
+ }
+ set80211(s, IEEE80211_IOC_CHANLIST, 0,
+ sizeof(chanlist), (uint8_t *) &chanlist);
+#undef MAXCHAN
+}
+
+static void
+set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+ if (!isanyarg(val)) {
+ char *temp;
+ struct sockaddr_dl sdl;
+
+ temp = malloc(strlen(val) + 1);
+ 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_BSSID, 0,
+ IEEE80211_ADDR_LEN, LLADDR(&sdl));
+ } else {
+ uint8_t zerobssid[IEEE80211_ADDR_LEN];
+ memset(zerobssid, 0, sizeof(zerobssid));
+ set80211(s, IEEE80211_IOC_BSSID, 0,
+ IEEE80211_ADDR_LEN, zerobssid);
+ }
+}
+
+static int
+getac(const char *ac)
+{
+ if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
+ return WME_AC_BE;
+ if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
+ return WME_AC_BK;
+ if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
+ return WME_AC_VI;
+ if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
+ return WME_AC_VO;
+ errx(1, "unknown wme access class %s", ac);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmin, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmax, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211aifs, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211txoplimit, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211acm, val, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACM, d, WME_AC_BE, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ackpolicy, val, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACKPOLICY, d, WME_AC_BE, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bssaifs, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211dtimperiod, val, d)
+{
+ set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bintval, val, d)
+{
+ set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
+}
+
+static void
+set80211macmac(int s, int op, const char *val)
+{
+ char *temp;
+ struct sockaddr_dl sdl;
+
+ temp = malloc(strlen(val) + 1);
+ 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, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
+}
+
+static
+DECL_CMD_FUNC(set80211addmac, val, d)
+{
+ set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211delmac, val, d)
+{
+ set80211macmac(s, IEEE80211_IOC_DELMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211maccmd, val, d)
+{
+ set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
+}
+
+static int
+getmaxrate(uint8_t rates[15], uint8_t nrates)
+{
+ int i, maxrate = -1;
+
+ for (i = 0; i < nrates; i++) {
+ int rate = rates[i] & IEEE80211_RATE_VAL;
+ if (rate > maxrate)
+ maxrate = rate;
+ }
+ return maxrate / 2;
+}
+
+static const char *
+getcaps(int capinfo)
+{
+ static char capstring[32];
+ char *cp = capstring;
+
+ if (capinfo & IEEE80211_CAPINFO_ESS)
+ *cp++ = 'E';
+ if (capinfo & IEEE80211_CAPINFO_IBSS)
+ *cp++ = 'I';
+ if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
+ *cp++ = 'c';
+ if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
+ *cp++ = 'C';
+ if (capinfo & IEEE80211_CAPINFO_PRIVACY)
+ *cp++ = 'P';
+ if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
+ *cp++ = 'S';
+ if (capinfo & IEEE80211_CAPINFO_PBCC)
+ *cp++ = 'B';
+ if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
+ *cp++ = 'A';
+ if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
+ *cp++ = 's';
+ if (capinfo & IEEE80211_CAPINFO_RSN)
+ *cp++ = 'R';
+ if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
+ *cp++ = 'D';
+ *cp = '\0';
+ return capstring;
+}
+
+static void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+ printf("%s", tag);
+ if (verbose) {
+ maxlen -= strlen(tag)+2;
+ if (2*ielen > maxlen)
+ maxlen--;
+ printf("<");
+ for (; ielen > 0; ie++, ielen--) {
+ if (maxlen-- <= 0)
+ break;
+ printf("%02x", *ie);
+ }
+ if (ielen != 0)
+ printf("-");
+ printf(">");
+ }
+}
+
+/*
+ * Copy the ssid string contents into buf, truncating to fit. If the
+ * ssid is entirely printable then just copy intact. Otherwise convert
+ * to hexadecimal. If the result is truncated then replace the last
+ * three characters with "...".
+ */
+static size_t
+copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
+{
+ const u_int8_t *p;
+ size_t maxlen;
+ int i;
+
+ if (essid_len > bufsize)
+ maxlen = bufsize;
+ else
+ maxlen = essid_len;
+ /* determine printable or not */
+ for (i = 0, p = essid; i < maxlen; i++, p++) {
+ if (*p < ' ' || *p > 0x7e)
+ break;
+ }
+ if (i != maxlen) { /* not printable, print as hex */
+ if (bufsize < 3)
+ return 0;
+ strlcpy(buf, "0x", bufsize);
+ bufsize -= 2;
+ p = essid;
+ for (i = 0; i < maxlen && bufsize >= 2; i++) {
+ sprintf(&buf[2+2*i], "%02x", *p++);
+ bufsize -= 2;
+ }
+ maxlen = 2+2*i;
+ } else { /* printable, truncate as needed */
+ memcpy(buf, essid, maxlen);
+ }
+ if (maxlen != essid_len)
+ memcpy(buf+maxlen-3, "...", 3);
+ return maxlen;
+}
+
+/* unalligned little endian access */
+#define LE_READ_4(p) \
+ ((u_int32_t) \
+ ((((const u_int8_t *)(p))[0] ) | \
+ (((const u_int8_t *)(p))[1] << 8) | \
+ (((const u_int8_t *)(p))[2] << 16) | \
+ (((const u_int8_t *)(p))[3] << 24)))
+
+static int __inline
+iswpaoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static int __inline
+iswmeoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
+}
+
+static int __inline
+isatherosoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
+}
+
+static void
+printies(const u_int8_t *vp, int ielen, int maxcols)
+{
+ while (ielen > 0) {
+ switch (vp[0]) {
+ case IEEE80211_ELEMID_VENDOR:
+ if (iswpaoui(vp))
+ printie(" WPA", vp, 2+vp[1], maxcols);
+ else if (iswmeoui(vp))
+ printie(" WME", vp, 2+vp[1], maxcols);
+ else if (isatherosoui(vp))
+ printie(" ATH", vp, 2+vp[1], maxcols);
+ else
+ printie(" VEN", vp, 2+vp[1], maxcols);
+ break;
+ case IEEE80211_ELEMID_RSN:
+ printie(" RSN", vp, 2+vp[1], maxcols);
+ break;
+ default:
+ printie(" ???", vp, 2+vp[1], maxcols);
+ break;
+ }
+ ielen -= 2+vp[1];
+ vp += 2+vp[1];
+ }
+}
+
+static void
+list_scan(int s)
+{
+ uint8_t buf[24*1024];
+ struct ieee80211req ireq;
+ char ssid[14];
+ uint8_t *cp;
+ int len;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
+ ireq.i_data = buf;
+ ireq.i_len = sizeof(buf);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get scan results");
+ len = ireq.i_len;
+ if (len < sizeof(struct ieee80211req_scan_result))
+ return;
+
+ printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n"
+ , "SSID"
+ , "BSSID"
+ , "CHAN"
+ , "RATE"
+ , "S:N"
+ , "INT"
+ , "CAPS"
+ );
+ cp = buf;
+ do {
+ struct ieee80211req_scan_result *sr;
+ uint8_t *vp;
+
+ sr = (struct ieee80211req_scan_result *) cp;
+ vp = (u_int8_t *)(sr+1);
+ printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
+ , copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len)
+ , ssid
+ , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
+ , ieee80211_mhz2ieee(sr->isr_freq)
+ , getmaxrate(sr->isr_rates, sr->isr_nrates)
+ , sr->isr_rssi, sr->isr_noise
+ , sr->isr_intval
+ , getcaps(sr->isr_capinfo)
+ );
+ printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
+ printf("\n");
+ cp += sr->isr_len, len -= sr->isr_len;
+ } while (len >= sizeof(struct ieee80211req_scan_result));
+}
+
+static void
+scan_and_wait(int s)
+{
+ struct ieee80211req ireq;
+ int sroute;
+
+ sroute = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (sroute < 0) {
+ perror("socket(PF_ROUTE,SOCK_RAW)");
+ return;
+ }
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_SCAN_REQ;
+ /* NB: only root can trigger a scan so ignore errors */
+ if (ioctl(s, SIOCS80211, &ireq) >= 0) {
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
+
+ do {
+ if (read(sroute, buf, sizeof(buf)) < 0) {
+ perror("read(PF_ROUTE)");
+ break;
+ }
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION)
+ break;
+ ifan = (struct if_announcemsghdr *) rtm;
+ } while (rtm->rtm_type != RTM_IEEE80211 ||
+ ifan->ifan_what != RTM_IEEE80211_SCAN);
+ }
+ close(sroute);
+}
+
+static
+DECL_CMD_FUNC(set80211scan, val, d)
+{
+ scan_and_wait(s);
+ list_scan(s);
+}
+
+static void
+list_stations(int s)
+{
+ uint8_t buf[24*1024];
+ struct ieee80211req ireq;
+ uint8_t *cp;
+ int len;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_STA_INFO;
+ ireq.i_data = buf;
+ ireq.i_len = sizeof(buf);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get station information");
+ len = ireq.i_len;
+ if (len < sizeof(struct ieee80211req_sta_info))
+ return;
+
+ printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
+ , "ADDR"
+ , "AID"
+ , "CHAN"
+ , "RATE"
+ , "RSSI"
+ , "IDLE"
+ , "TXSEQ"
+ , "RXSEQ"
+ , "CAPS"
+ , "ERP"
+ cp = buf;
+ do {
+ struct ieee80211req_sta_info *si;
+ uint8_t *vp;
+
+ si = (struct ieee80211req_sta_info *) cp;
+ vp = (u_int8_t *)(si+1);
+ printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
+ , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
+ , IEEE80211_AID(si->isi_associd)
+ , ieee80211_mhz2ieee(si->isi_freq)
+ , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
+ , si->isi_rssi
+ , si->isi_inact
+ , si->isi_txseqs[0]
+ , si->isi_rxseqs[0]
+ , getcaps(si->isi_capinfo)
+ , si->isi_erp
+ );
+ printies(vp, si->isi_ie_len, 24);
+ printf("\n");
+ cp += si->isi_len, len -= si->isi_len;
+ } while (len >= sizeof(struct ieee80211req_sta_info));
+}
+
+static void
+print_chaninfo(const struct ieee80211_channel *c)
+{
+#define IEEE80211_IS_CHAN_PASSIVE(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
+ char buf[14];
+
+ buf[0] = '\0';
+ if (IEEE80211_IS_CHAN_FHSS(c))
+ strlcat(buf, " FHSS", sizeof(buf));
+ if (IEEE80211_IS_CHAN_A(c))
+ strlcat(buf, " 11a", sizeof(buf));
+ /* XXX 11g schizophrenia */
+ if (IEEE80211_IS_CHAN_G(c) ||
+ IEEE80211_IS_CHAN_PUREG(c))
+ strlcat(buf, " 11g", sizeof(buf));
+ else if (IEEE80211_IS_CHAN_B(c))
+ strlcat(buf, " 11b", sizeof(buf));
+ if (IEEE80211_IS_CHAN_T(c))
+ strlcat(buf, " Turbo", sizeof(buf));
+ printf("Channel %3u : %u%c Mhz%-14.14s",
+ ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
+ IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
+#undef IEEE80211_IS_CHAN_PASSIVE
+}
+
+static void
+list_channels(int s, int allchans)
+{
+ struct ieee80211req ireq;
+ struct ieee80211req_chaninfo chans;
+ struct ieee80211req_chaninfo achans;
+ const struct ieee80211_channel *c;
+ int i, half;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_CHANINFO;
+ ireq.i_data = &chans;
+ ireq.i_len = sizeof(chans);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get channel information");
+ if (!allchans) {
+ struct ieee80211req_chanlist active;
+
+ ireq.i_type = IEEE80211_IOC_CHANLIST;
+ ireq.i_data = &active;
+ ireq.i_len = sizeof(active);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get active channel list");
+ memset(&achans, 0, sizeof(achans));
+ for (i = 0; i < chans.ic_nchans; i++) {
+ c = &chans.ic_chans[i];
+ if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
+ achans.ic_chans[achans.ic_nchans++] = *c;
+ }
+ } else
+ achans = chans;
+ half = achans.ic_nchans / 2;
+ if (achans.ic_nchans % 2)
+ half++;
+ for (i = 0; i < achans.ic_nchans / 2; i++) {
+ print_chaninfo(&achans.ic_chans[i]);
+ print_chaninfo(&achans.ic_chans[half+i]);
+ printf("\n");
+ }
+ if (achans.ic_nchans % 2) {
+ print_chaninfo(&achans.ic_chans[i]);
+ printf("\n");
+ }
+}
+
+static void
+list_keys(int s)
+{
+}
+
+#define IEEE80211_C_BITS \
+"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
+"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
+"\31WPA2\32BURST\33WME"
+
+static void
+list_capabilities(int s)
+{
+ struct ieee80211req ireq;
+ u_int32_t caps;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get driver capabilities");
+ caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
+ printb(name, caps, IEEE80211_C_BITS);
+ putchar('\n');
+}
+
+static void
+list_wme(int s)
+{
+ static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
+ struct ieee80211req ireq;
+ int ac;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_len = 0;
+ for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
+again:
+ if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
+ printf("\t%s", " ");
+ else
+ printf("\t%s", acnames[ac]);
+
+ ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
+
+ /* show WME BSS parameters */
+ ireq.i_type = IEEE80211_IOC_WME_CWMIN;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" cwmin %2u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_CWMAX;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" cwmax %2u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_AIFS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" aifs %2u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" txopLimit %3u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_ACM;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ printf(" acm");
+ else if (verbose)
+ printf(" -acm");
+ }
+ /* !BSS only */
+ if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
+ ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (!ireq.i_val)
+ printf(" -ack");
+ else if (verbose)
+ printf(" ack");
+ }
+ }
+ printf("\n");
+ if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
+ ireq.i_len |= IEEE80211_WMEPARAM_BSS;
+ goto again;
+ } else
+ ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
+ }
+}
+
+static
+DECL_CMD_FUNC(set80211list, arg, d)
+{
+#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
+
+ if (iseq(arg, "sta"))
+ list_stations(s);
+ else if (iseq(arg, "scan") || iseq(arg, "ap"))
+ list_scan(s);
+ else if (iseq(arg, "chan") || iseq(arg, "freq"))
+ list_channels(s, 1);
+ else if (iseq(arg, "active"))
+ list_channels(s, 0);
+ else if (iseq(arg, "keys"))
+ list_keys(s);
+ else if (iseq(arg, "caps"))
+ list_capabilities(s);
+ else if (iseq(arg, "wme"))
+ list_wme(s);
+ else
+ errx(1, "Don't know how to list %s for %s", arg, name);
+#undef iseq
+}
+
+static enum ieee80211_opmode
+get80211opmode(int s)
+{
+ struct ifmediareq ifmr;
+
+ (void) memset(&ifmr, 0, sizeof(ifmr));
+ (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+ if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
+ return IEEE80211_M_IBSS; /* XXX ahdemo */
+ if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+ return IEEE80211_M_HOSTAP;
+ if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+ return IEEE80211_M_MONITOR;
+ }
+ return IEEE80211_M_STA;
+}
+
+static const struct ieee80211_channel *
+getchaninfo(int s, int chan)
+{
+ struct ieee80211req ireq;
+ static struct ieee80211req_chaninfo chans;
+ static struct ieee80211_channel undef;
+ const struct ieee80211_channel *c;
+ int i, freq;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_CHANINFO;
+ ireq.i_data = &chans;
+ ireq.i_len = sizeof(chans);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get channel information");
+ freq = ieee80211_ieee2mhz(chan);
+ for (i = 0; i < chans.ic_nchans; i++) {
+ c = &chans.ic_chans[i];
+ if (c->ic_freq == freq)
+ return c;
+ }
+ return &undef;
+}
+
+#if 0
+static void
+printcipher(int s, struct ieee80211req *ireq, int keylenop)
+{
+ switch (ireq->i_val) {
+ case IEEE80211_CIPHER_WEP:
+ ireq->i_type = keylenop;
+ if (ioctl(s, SIOCG80211, ireq) != -1)
+ printf("WEP-%s",
+ ireq->i_len <= 5 ? "40" :
+ ireq->i_len <= 13 ? "104" : "128");
+ else
+ printf("WEP");
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ printf("TKIP");
+ break;
+ case IEEE80211_CIPHER_AES_OCB:
+ printf("AES-OCB");
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ printf("AES-CCM");
+ break;
+ case IEEE80211_CIPHER_CKIP:
+ printf("CKIP");
+ break;
+ case IEEE80211_CIPHER_NONE:
+ printf("NONE");
+ break;
+ default:
+ printf("UNKNOWN (0x%x)", ireq->i_val);
+ break;
+ }
+}
+#endif
+
+#define MAXCOL 78
+int col;
+char spacer;
+
+#define LINE_BREAK() do { \
+ if (spacer != '\t') { \
+ printf("\n"); \
+ spacer = '\t'; \
+ } \
+ col = 8; /* 8-col tab */ \
+} while (0)
+#define LINE_CHECK(fmt, ...) do { \
+ col += sizeof(fmt)-2; \
+ if (col > MAXCOL) { \
+ LINE_BREAK(); \
+ col += sizeof(fmt)-2; \
+ } \
+ printf(fmt, __VA_ARGS__); \
+ spacer = ' '; \
+} while (0)
+
+static void
+printkey(const struct ieee80211req_key *ik)
+{
+ static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
+ int keylen = ik->ik_keylen;
+ int printcontents;
+
+ printcontents =
+ (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
+ if (printcontents)
+ LINE_BREAK();
+ switch (ik->ik_type) {
+ case IEEE80211_CIPHER_WEP:
+ /* compatibility */
+ LINE_CHECK("%cwepkey %u:%s", spacer, ik->ik_keyix+1,
+ keylen <= 5 ? "40-bit" :
+ keylen <= 13 ? "104-bit" : "128-bit");
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ if (keylen > 128/8)
+ keylen -= 128/8; /* ignore MIC for now */
+ LINE_CHECK("%cTKIP %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_AES_OCB:
+ LINE_CHECK("%cAES-OCB %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ LINE_CHECK("%cAES-CCM %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_CKIP:
+ LINE_CHECK("%cCKIP %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_NONE:
+ LINE_CHECK("%cNULL %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ default:
+ LINE_CHECK("%cUNKNOWN (0x%x) %u:%u-bit", spacer,
+ ik->ik_type, ik->ik_keyix+1, 8*keylen);
+ break;
+ }
+ if (printcontents) {
+ int i;
+
+ printf(" <");
+ for (i = 0; i < keylen; i++)
+ printf("%02x", ik->ik_keydata[i]);
+ printf(">");
+ if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+ (ik->ik_keyrsc != 0 || verbose))
+ printf(" rsc %llu", ik->ik_keyrsc);
+ if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+ (ik->ik_keytsc != 0 || verbose))
+ printf(" tsc %llu", ik->ik_keytsc);
+ if (ik->ik_flags != 0 && verbose) {
+ const char *sep = " ";
+
+ if (ik->ik_flags & IEEE80211_KEY_XMIT)
+ printf("%stx", sep), sep = "+";
+ if (ik->ik_flags & IEEE80211_KEY_RECV)
+ printf("%srx", sep), sep = "+";
+ if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
+ printf("%sdef", sep), sep = "+";
+ }
+ LINE_BREAK();
+ }
+}
+
+static void
+ieee80211_status(int s)
+{
+ static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+ enum ieee80211_opmode opmode = get80211opmode(s);
+ int i, num, wpa, wme;
+ struct ieee80211req ireq;
+ u_int8_t data[32];
+ const struct ieee80211_channel *c;
(void) memset(&ireq, 0, sizeof(ireq));
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_data = &data;
+ wpa = 0; /* unknown/not set */
+
ireq.i_type = IEEE80211_IOC_SSID;
ireq.i_val = -1;
if (ioctl(s, SIOCG80211, &ireq) < 0) {
/* If we can't get the SSID, the this isn't an 802.11 device. */
return;
}
- printf("\tssid ");
- print_string(data, ireq.i_len);
num = 0;
ireq.i_type = IEEE80211_IOC_NUMSSIDS;
- if (ioctl(s, SIOCG80211, &ireq) >= 0) {
+ if (ioctl(s, SIOCG80211, &ireq) >= 0)
num = ireq.i_val;
- }
- ireq.i_type = IEEE80211_IOC_SSID;
- for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
- if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
- printf(" %d:", ireq.i_val + 1);
- print_string(data, ireq.i_len);
+ printf("\tssid ");
+ if (num > 1) {
+ ireq.i_type = IEEE80211_IOC_SSID;
+ for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
+ if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
+ printf(" %d:", ireq.i_val + 1);
+ print_string(data, ireq.i_len);
+ }
}
- }
- printf("\n");
+ } else
+ print_string(data, ireq.i_len);
+
+ ireq.i_type = IEEE80211_IOC_CHANNEL;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ goto end;
+ c = getchaninfo(s, ireq.i_val);
+ if (ireq.i_val != -1) {
+ printf(" channel %d", ireq.i_val);
+ if (verbose)
+ printf(" (%u)", c->ic_freq);
+ } else if (verbose)
+ printf(" channel UNDEF");
+
+ ireq.i_type = IEEE80211_IOC_BSSID;
+ ireq.i_len = IEEE80211_ADDR_LEN;
+ if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
+ memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0)
+ printf(" bssid %s", ether_ntoa(ireq.i_data));
ireq.i_type = IEEE80211_IOC_STATIONNAME;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("\tstationname ");
+ printf("\n\tstationname ");
print_string(data, ireq.i_len);
- printf("\n");
}
- ireq.i_type = IEEE80211_IOC_CHANNEL;
- if (ioctl(s, SIOCG80211, &ireq) < 0) {
- goto end;
- }
- printf("\tchannel %d", ireq.i_val);
+ spacer = ' '; /* force first break */
+ LINE_BREAK();
ireq.i_type = IEEE80211_IOC_AUTHMODE;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf(" authmode");
switch (ireq.i_val) {
case IEEE80211_AUTH_NONE:
- printf(" NONE");
+ LINE_CHECK("%cauthmode NONE", spacer);
break;
case IEEE80211_AUTH_OPEN:
- printf(" OPEN");
+ LINE_CHECK("%cauthmode OPEN", spacer);
break;
case IEEE80211_AUTH_SHARED:
- printf(" SHARED");
+ LINE_CHECK("%cauthmode SHARED", spacer);
break;
- default:
- printf(" UNKNOWN");
+ case IEEE80211_AUTH_8021X:
+ LINE_CHECK("%cauthmode 802.1x", spacer);
break;
- }
- }
-
- ireq.i_type = IEEE80211_IOC_POWERSAVE;
- if (ioctl(s, SIOCG80211, &ireq) != -1 &&
- ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
- printf(" powersavemode");
- switch (ireq.i_val) {
- case IEEE80211_POWERSAVE_OFF:
- printf(" OFF");
+ case IEEE80211_AUTH_WPA:
+ ireq.i_type = IEEE80211_IOC_WPA;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ wpa = ireq.i_val;
+ if (!wpa)
+ wpa = 1; /* default to WPA1 */
+ switch (wpa) {
+ case 2:
+ LINE_CHECK("%cauthmode WPA2/802.11i",
+ spacer);
+ break;
+ case 3:
+ LINE_CHECK("%cauthmode WPA1+WPA2/802.11i",
+ spacer);
+ break;
+ default:
+ LINE_CHECK("%cauthmode WPA", spacer);
+ break;
+ }
break;
- case IEEE80211_POWERSAVE_CAM:
- printf(" CAM");
- break;
- case IEEE80211_POWERSAVE_PSP:
- printf(" PSP");
- break;
- case IEEE80211_POWERSAVE_PSP_CAM:
- printf(" PSP-CAM");
- break;
- }
-
- ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- if (ireq.i_val)
- printf(" powersavesleep %d", ireq.i_val);
- }
- }
-
- printf("\n");
-
- spacer = '\t';
- ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%crtsthreshold %d", spacer, ireq.i_val);
- spacer = ' ';
- }
-
- ireq.i_type = IEEE80211_IOC_PROTMODE;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%cprotmode", spacer);
- switch (ireq.i_val) {
- case IEEE80211_PROTMODE_OFF:
- printf(" OFF");
- break;
- case IEEE80211_PROTMODE_CTS:
- printf(" CTS");
- break;
- case IEEE80211_PROTMODE_RTSCTS:
- printf(" RTSCTS");
+ case IEEE80211_AUTH_AUTO:
+ LINE_CHECK("%cauthmode AUTO", spacer);
break;
default:
- printf(" UNKNOWN");
+ LINE_CHECK("%cauthmode UNKNOWN (0x%x)",
+ spacer, ireq.i_val);
break;
}
- spacer = ' ';
}
- ireq.i_type = IEEE80211_IOC_TXPOWER;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%ctxpower %d", spacer, ireq.i_val);
- spacer = ' ';
- }
-
- if (spacer != '\t')
- printf("\n");
-
ireq.i_type = IEEE80211_IOC_WEP;
if (ioctl(s, SIOCG80211, &ireq) != -1 &&
ireq.i_val != IEEE80211_WEP_NOSUP) {
- printf("\twepmode");
- switch (ireq.i_val) {
+ int firstkey, wepmode;
+
+ wepmode = ireq.i_val;
+ switch (wepmode) {
case IEEE80211_WEP_OFF:
- printf(" OFF");
+ LINE_CHECK("%cprivacy OFF", spacer);
break;
case IEEE80211_WEP_ON:
- printf(" ON");
+ LINE_CHECK("%cprivacy ON", spacer);
break;
case IEEE80211_WEP_MIXED:
- printf(" MIXED");
+ LINE_CHECK("%cprivacy MIXED", spacer);
break;
default:
- printf(" UNKNOWN");
+ LINE_CHECK("%cprivacy UNKNOWN (0x%x)",
+ spacer, wepmode);
break;
}
@@ -491,7 +1421,10 @@
warn("WEP support, but no tx key!");
goto end;
}
- printf(" weptxkey %d", ireq.i_val+1);
+ if (ireq.i_val != -1)
+ LINE_CHECK("%cdeftxkey %d", spacer, ireq.i_val+1);
+ else if (wepmode != IEEE80211_WEP_OFF || verbose)
+ LINE_CHECK("%cdeftxkey UNDEF", spacer);
ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
if (ioctl(s, SIOCG80211, &ireq) < 0) {
@@ -500,28 +1433,201 @@
}
num = ireq.i_val;
- printf("\n");
-
- ireq.i_type = IEEE80211_IOC_WEPKEY;
- spacer = '\t';
+ firstkey = 1;
for (i = 0; i < num; i++) {
- ireq.i_val = i;
+ struct ieee80211req_key ik;
+
+ memset(&ik, 0, sizeof(ik));
+ ik.ik_keyix = i;
+ ireq.i_type = IEEE80211_IOC_WPAKEY;
+ ireq.i_data = &ik;
+ ireq.i_len = sizeof(ik);
if (ioctl(s, SIOCG80211, &ireq) < 0) {
warn("WEP support, but can get keys!");
goto end;
}
- if (ireq.i_len == 0 ||
- ireq.i_len > IEEE80211_KEYBUF_SIZE)
- continue;
- printf("%cwepkey %d:%s", spacer, i+1,
- ireq.i_len <= 5 ? "40-bit" :
- ireq.i_len <= 13 ? "104-bit" : "128-bit");
- if (spacer == '\t')
+ if (ik.ik_keylen != 0) {
+ if (verbose)
+ LINE_BREAK();
+ printkey(&ik);
+ firstkey = 0;
+ }
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_POWERSAVE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1 &&
+ ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
+ if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
+ switch (ireq.i_val) {
+ case IEEE80211_POWERSAVE_OFF:
+ LINE_CHECK("%cpowersavemode OFF",
+ spacer);
+ break;
+ case IEEE80211_POWERSAVE_CAM:
+ LINE_CHECK("%cpowersavemode CAM",
+ spacer);
+ break;
+ case IEEE80211_POWERSAVE_PSP:
+ LINE_CHECK("%cpowersavemode PSP",
+ spacer);
+ break;
+ case IEEE80211_POWERSAVE_PSP_CAM:
+ LINE_CHECK("%cpowersavemode PSP-CAM",
+ spacer);
+ break;
+ }
+ ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%cpowersavesleep %d",
+ spacer, ireq.i_val);
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_TXPOWMAX;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%ctxpowmax %d", spacer, ireq.i_val);
+
+ if (verbose) {
+ ireq.i_type = IEEE80211_IOC_TXPOWER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%ctxpower %d", spacer, ireq.i_val);
+ }
+
+ ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
+ LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val);
+ }
+
+ if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
+ ireq.i_type = IEEE80211_IOC_PROTMODE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ switch (ireq.i_val) {
+ case IEEE80211_PROTMODE_OFF:
+ LINE_CHECK("%cprotmode OFF", spacer);
+ break;
+ case IEEE80211_PROTMODE_CTS:
+ LINE_CHECK("%cprotmode CTS", spacer);
+ break;
+ case IEEE80211_PROTMODE_RTSCTS:
+ LINE_CHECK("%cprotmode RTSCTS", spacer);
+ break;
+ default:
+ LINE_CHECK("%cprotmode UNKNOWN (0x%x)",
+ spacer, ireq.i_val);
+ break;
+ }
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_WME;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ wme = ireq.i_val;
+ if (wme)
+ LINE_CHECK("%cwme", spacer);
+ else if (verbose)
+ LINE_CHECK("%c-wme", spacer);
+ } else
+ wme = 0;
+
+ if (opmode == IEEE80211_M_HOSTAP) {
+ ireq.i_type = IEEE80211_IOC_HIDESSID;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("%cssid HIDE", spacer);
+ else if (verbose)
+ LINE_CHECK("%cssid SHOW", spacer);
+ }
+
+ ireq.i_type = IEEE80211_IOC_APBRIDGE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (!ireq.i_val)
+ LINE_CHECK("%c-apbridge", spacer);
+ else if (verbose)
+ LINE_CHECK("%capbridge", spacer);
+ }
+
+ ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%cdtimperiod %u", spacer, ireq.i_val);
+ } else {
+ ireq.i_type = IEEE80211_IOC_ROAMING;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
+ switch (ireq.i_val) {
+ case IEEE80211_ROAMING_DEVICE:
+ LINE_CHECK("%croaming DEVICE", spacer);
+ break;
+ case IEEE80211_ROAMING_AUTO:
+ LINE_CHECK("%croaming AUTO", spacer);
+ break;
+ case IEEE80211_ROAMING_MANUAL:
+ LINE_CHECK("%croaming MANUAL", spacer);
+ break;
+ default:
+ LINE_CHECK("%croaming UNKNOWN (0x%x)",
+ spacer, ireq.i_val);
+ break;
+ }
+ }
+ }
+ }
+ ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("%cbintval %u", spacer, ireq.i_val);
+ else if (verbose)
+ LINE_CHECK("%cbintval %u", spacer, ireq.i_val);
+ }
+
+ if (wme && verbose) {
+ LINE_BREAK();
+ list_wme(s);
+ }
+
+ if (wpa) {
+ ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("%ccountermeasures", spacer);
+ else if (verbose)
+ LINE_CHECK("%c-countermeasures", spacer);
+ }
+#if 0
+ /* XXX not interesting with WPA done in user space */
+ ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ }
+
+ ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ printf("%cmcastcipher ", spacer);
+ printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
+ spacer = ' ';
+ }
+
+ ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ printf("%cucastcipher ", spacer);
+ printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
+ }
+
+ if (wpa & 2) {
+ ireq.i_type = IEEE80211_IOC_RSNCAPS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ printf("%cRSN caps 0x%x", spacer, ireq.i_val);
spacer = ' ';
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
}
- if (spacer == ' ')
- printf("\n");
+#endif
+ LINE_BREAK();
}
+ LINE_BREAK();
end:
return;
@@ -623,3 +1729,79 @@
}
}
+static struct cmd ieee80211_cmds[] = {
+ DEF_CMD_ARG("ssid", set80211ssid),
+ DEF_CMD_ARG("nwid", set80211ssid),
+ DEF_CMD_ARG("stationname", set80211stationname),
+ DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
+ DEF_CMD_ARG("channel", set80211channel),
+ DEF_CMD_ARG("authmode", set80211authmode),
+ DEF_CMD_ARG("powersavemode", set80211powersavemode),
+ DEF_CMD("powersave", 1, set80211powersave),
+ DEF_CMD("-powersave", 0, set80211powersave),
+ DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
+ DEF_CMD_ARG("wepmode", set80211wepmode),
+ DEF_CMD("wep", 1, set80211wep),
+ DEF_CMD("-wep", 0, set80211wep),
+ DEF_CMD_ARG("deftxkey", set80211weptxkey),
+ DEF_CMD_ARG("weptxkey", set80211weptxkey),
+ DEF_CMD_ARG("wepkey", set80211wepkey),
+ DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
+ DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
+ DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
+ DEF_CMD_ARG("protmode", set80211protmode),
+ DEF_CMD_ARG("txpower", set80211txpower),
+ DEF_CMD_ARG("roaming", set80211roaming),
+ DEF_CMD("wme", 1, set80211wme),
+ DEF_CMD("-wme", 0, set80211wme),
+ DEF_CMD("hidessid", 1, set80211hidessid),
+ DEF_CMD("-hidessid", 0, set80211hidessid),
+ DEF_CMD("apbridge", 1, set80211apbridge),
+ DEF_CMD("-apbridge", 0, set80211apbridge),
+ DEF_CMD_ARG("chanlist", set80211chanlist),
+ DEF_CMD_ARG("bssid", set80211bssid),
+ DEF_CMD_ARG("ap", set80211bssid),
+ DEF_CMD("scan", 0, set80211scan),
+ DEF_CMD_ARG("list", set80211list),
+ DEF_CMD_ARG2("cwmin", set80211cwmin),
+ DEF_CMD_ARG2("cwmax", set80211cwmax),
+ DEF_CMD_ARG2("aifs", set80211aifs),
+ DEF_CMD_ARG2("txoplimit", set80211txoplimit),
+ DEF_CMD("acm", 1, set80211acm),
+ DEF_CMD("-acm", 0, set80211acm),
+ DEF_CMD("ack", 1, set80211ackpolicy),
+ DEF_CMD("-ack", 0, set80211ackpolicy),
+ DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
+ DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
+ DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
+ DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
+ DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
+ DEF_CMD_ARG("bintval", set80211bintval),
+ DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
+ DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
+ DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
+ DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
+ DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
+ DEF_CMD_ARG("mac:add", set80211addmac),
+ DEF_CMD_ARG("mac:del", set80211delmac),
+#if 0
+ DEF_CMD_ARG("mac:kick", set80211kickmac),
+#endif
+};
+static struct afswtch af_ieee80211 = {
+ .af_name = "af_ieee80211",
+ .af_af = AF_UNSPEC,
+ .af_other_status = ieee80211_status,
+};
+
+static __constructor void
+ieee80211_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(ieee80211_cmds); i++)
+ cmd_register(&ieee80211_cmds[i]);
+ af_register(&af_ieee80211);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifmac.c src/sbin/ifconfig/ifmac.c
--- src.preview/sbin/ifconfig/ifmac.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/ifmac.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by NAI Labs, the
+ * Security Research Division of Network Associates, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ifconfig.h"
+
+static void
+maclabel_status(int s)
+{
+ struct ifreq ifr;
+ mac_t label;
+ char *label_text;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (mac_prepare_ifnet_label(&label) == -1)
+ return;
+ ifr.ifr_ifru.ifru_data = (void *)label;
+ if (ioctl(s, SIOCGIFMAC, &ifr) == -1)
+ goto mac_free;
+
+
+ if (mac_to_text(label, &label_text) == -1)
+ goto mac_free;
+
+ if (strlen(label_text) != 0)
+ printf("\tmaclabel %s\n", label_text);
+ free(label_text);
+
+mac_free:
+ mac_free(label);
+}
+
+static void
+setifmaclabel(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ struct ifreq ifr;
+ mac_t label;
+ int error;
+
+ if (mac_from_text(&label, val) == -1) {
+ perror(val);
+ return;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_data = (void *)label;
+
+ error = ioctl(s, SIOCSIFMAC, &ifr);
+ mac_free(label);
+ if (error == -1)
+ perror("setifmac");
+}
+
+static struct cmd mac_cmds[] = {
+ DEF_CMD_ARG("maclabel", setifmaclabel),
+};
+static struct afswtch af_mac = {
+ .af_name = "af_maclabel",
+ .af_af = AF_UNSPEC,
+ .af_other_status = maclabel_status,
+};
+
+static __constructor void
+mac_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(mac_cmds); i++)
+ cmd_register(&mac_cmds[i]);
+ af_register(&af_mac);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifmedia.c src/sbin/ifconfig/ifmedia.c
--- src.preview/sbin/ifconfig/ifmedia.c 2005-03-06 00:01:59.000000000 -0500
+++ src/sbin/ifconfig/ifmedia.c 2005-09-27 15:02:10.000000000 -0400
@@ -1,6 +1,5 @@
/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */
-/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.6.2.3 2001/11/14 04:35:07 yar Exp $ */
-/* $DragonFly: src/sbin/ifconfig/ifmedia.c,v 1.8 2005/03/06 05:01:59 dillon Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1997 Jason R. Thorpe.
@@ -90,24 +89,6 @@
#include "ifconfig.h"
-#ifndef IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS
- #define IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS { \
- { IFM_AUTO, "autoselect" }, \
- { IFM_IEEE80211_11A, "11a" }, \
- { IFM_IEEE80211_11B, "11b" }, \
- { IFM_IEEE80211_11G, "11g" }, \
- { IFM_IEEE80211_FH, "fh" }, \
- { 0, NULL }, \
-}
-#endif
-
-#ifndef IFM_SUBTYPE_IEEE80211_MODE_ALIASES
- #define IFM_SUBTYPE_IEEE80211_MODE_ALIASES { \
- { IFM_AUTO, "auto" }, \
- { 0, NULL }, \
-}
-#endif
-
static void domediaopt(const char *, int, int);
static int get_media_subtype(int, const char *);
static int get_media_mode(int, const char *);
@@ -121,8 +102,8 @@
static struct ifmedia_description *get_subtype_desc(int,
struct ifmedia_type_to_subtype *ttos);
-void
-media_status(int s, struct rt_addrinfo *info __unused)
+static void
+media_status(int s)
{
struct ifmediareq ifmr;
int *media_list, i;
@@ -179,14 +160,12 @@
printf("no ring");
break;
-#if notyet
case IFM_ATM:
if (ifmr.ifm_status & IFM_ACTIVE)
printf("active");
else
printf("no carrier");
break;
-#endif
case IFM_IEEE80211:
/* XXX: Different value for adhoc? */
@@ -211,29 +190,72 @@
free(media_list);
}
-void
-setmedia(const char *val, int d __unused, int s,
- const struct afswtch *afp __unused)
+static struct ifmediareq *
+getifmediastate(int s)
{
- struct ifmediareq ifmr;
- int first_type, subtype;
+ static struct ifmediareq *ifmr = NULL;
+ int *mwords;
- (void) memset(&ifmr, 0, sizeof(ifmr));
- (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+ if (ifmr == NULL) {
+ ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
+ if (ifmr == NULL)
+ err(1, "malloc");
+
+ (void) memset(ifmr, 0, sizeof(struct ifmediareq));
+ (void) strncpy(ifmr->ifm_name, name,
+ sizeof(ifmr->ifm_name));
+
+ ifmr->ifm_count = 0;
+ ifmr->ifm_ulist = NULL;
- ifmr.ifm_count = 1;
- ifmr.ifm_ulist = &first_type;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
/*
- * If we get E2BIG, the kernel is telling us
- * that there are more, so we can ignore it.
+ * We must go through the motions of reading all
+ * supported media because we need to know both
+ * the current media type and the top-level type.
*/
- if (errno != E2BIG)
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
+ err(1, "SIOCGIFMEDIA");
+ }
+
+ if (ifmr->ifm_count == 0)
+ errx(1, "%s: no media types?", name);
+
+ mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
+ if (mwords == NULL)
+ err(1, "malloc");
+
+ ifmr->ifm_ulist = mwords;
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
err(1, "SIOCGIFMEDIA");
}
- if (ifmr.ifm_count == 0)
- errx(1, "%s: no media types?", name);
+ return ifmr;
+}
+
+static void
+setifmediacallback(int s, void *arg)
+{
+ struct ifmediareq *ifmr = (struct ifmediareq *)arg;
+ static int did_it = 0;
+
+ if (!did_it) {
+ if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
+ err(1, "SIOCSIFMEDIA (media)");
+ free(ifmr->ifm_ulist);
+ free(ifmr);
+ did_it = 1;
+ }
+}
+
+static void
+setmedia(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifmediareq *ifmr;
+ int subtype;
+
+
+ ifmr = getifmediastate(s);
/*
* We are primarily concerned with the top-level type.
@@ -244,27 +266,29 @@
* (I'm assuming that all supported media types for a given
* interface will be the same top-level type..)
*/
- subtype = get_media_subtype(IFM_TYPE(first_type), val);
+ subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
- IFM_TYPE(first_type) | subtype;
+ ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
+ IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
+
+ if ((ifr.ifr_media & IFM_TMASK) == 0) {
+ ifr.ifr_media &= ~IFM_GMASK;
+ }
- if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
- err(1, "SIOCSIFMEDIA (media)");
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
}
-void
-setmediaopt(const char *val, int d __unused, int s,
- const struct afswtch *afp __unused)
+static void
+setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
{
domediaopt(val, 0, s);
}
-void
-unsetmediaopt(const char *val, int d __unused, int s,
- const struct afswtch *afp __unused)
+static void
+unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
{
domediaopt(val, 1, s);
@@ -273,87 +297,40 @@
static void
domediaopt(const char *val, int clear, int s)
{
- struct ifmediareq ifmr;
- int *mwords, options;
+ struct ifmediareq *ifmr;
+ int options;
- (void) memset(&ifmr, 0, sizeof(ifmr));
- (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+ ifmr = getifmediastate(s);
- /*
- * We must go through the motions of reading all
- * supported media because we need to know both
- * the current media type and the top-level type.
- */
-
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
- err(1, "SIOCGIFMEDIA");
-
- if (ifmr.ifm_count == 0)
- errx(1, "%s: no media types?", name);
-
- mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
- if (mwords == NULL)
- err(1, "malloc");
-
- ifmr.ifm_ulist = mwords;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
- err(1, "SIOCGIFMEDIA");
-
- options = get_media_options(IFM_TYPE(mwords[0]), val);
-
- free(mwords);
+ options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- ifr.ifr_media = ifmr.ifm_current;
+ ifr.ifr_media = ifmr->ifm_current;
if (clear)
ifr.ifr_media &= ~options;
else
ifr.ifr_media |= options;
- if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
- err(1, "SIOCSIFMEDIA (mediaopt)");
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
}
-void
-setmediamode(const char *val, int d __unused, int s,
- const struct afswtch *afp __unused)
+static void
+setmediamode(const char *val, int d, int s, const struct afswtch *afp)
{
- struct ifmediareq ifmr;
- int *mwords, mode;
-
- (void) memset(&ifmr, 0, sizeof(ifmr));
- (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
-
- /*
- * We must go through the motions of reading all
- * supported media because we need to know both
- * the current media type and the top-level type.
- */
+ struct ifmediareq *ifmr;
+ int mode;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
- err(1, "SIOCGIFMEDIA");
-
- if (ifmr.ifm_count == 0)
- errx(1, "%s: no media types?", name);
-
- mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
- if (mwords == NULL)
- err(1, "malloc");
-
- ifmr.ifm_ulist = mwords;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
- err(1, "SIOCGIFMEDIA");
-
- mode = get_media_mode(IFM_TYPE(mwords[0]), val);
+ ifmr = getifmediastate(s);
- free(mwords);
+ mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- ifr.ifr_media = (ifmr.ifm_current & ~IFM_MMASK) | mode;
+ ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
- if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
- err(1, "SIOCSIFMEDIA (mode)");
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
}
/**********************************************************************
@@ -405,7 +382,6 @@
struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
-#if notyet
static struct ifmedia_description ifm_subtype_atm_descriptions[] =
IFM_SUBTYPE_ATM_DESCRIPTIONS;
@@ -414,7 +390,6 @@
static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
-#endif
static struct ifmedia_description ifm_subtype_shared_descriptions[] =
IFM_SUBTYPE_SHARED_DESCRIPTIONS;
@@ -516,17 +491,13 @@
{
{ &ifm_subtype_shared_descriptions[0], 0 },
{ &ifm_subtype_shared_aliases[0], 1 },
-#if notyet
{ &ifm_subtype_atm_descriptions[0], 0 },
{ &ifm_subtype_atm_aliases[0], 1 },
-#endif
{ NULL, 0 },
},
{
{ &ifm_shared_option_descriptions[0], 0 },
-#if notyet
{ &ifm_subtype_atm_option_descriptions[0], 0 },
-#endif
{ NULL, 0 },
},
{
@@ -808,3 +779,27 @@
/**********************************************************************
* ...until here.
**********************************************************************/
+
+static struct cmd media_cmds[] = {
+ DEF_CMD_ARG("media", setmedia),
+ DEF_CMD_ARG("mode", setmediamode),
+ DEF_CMD_ARG("mediaopt", setmediaopt),
+ DEF_CMD_ARG("-mediaopt",unsetmediaopt),
+};
+static struct afswtch af_media = {
+ .af_name = "af_media",
+ .af_af = AF_UNSPEC,
+ .af_other_status = media_status,
+};
+
+static __constructor void
+ifmedia_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(media_cmds); i++)
+ cmd_register(&media_cmds[i]);
+ af_register(&af_media);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifpfsync.c src/sbin/ifconfig/ifpfsync.c
--- src.preview/sbin/ifconfig/ifpfsync.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/ifpfsync.c 2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2003 Ryan McBride. All rights reserved.
+ * Copyright (c) 2004 Max Laier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <net/if_pfsync.h>
+#include <net/route.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+void setpfsync_syncif(const char *, int, int, const struct afswtch *rafp);
+void unsetpfsync_syncif(const char *, int, int, const struct afswtch *rafp);
+void setpfsync_maxupd(const char *, int, int, const struct afswtch *rafp);
+void pfsync_status(int);
+
+void
+setpfsync_syncif(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ struct pfsyncreq preq;
+
+ bzero((char *)&preq, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETPFSYNC");
+
+ strlcpy(preq.pfsyncr_syncif, val, sizeof(preq.pfsyncr_syncif));
+
+ if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFSYNC");
+}
+
+void
+unsetpfsync_syncif(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ struct pfsyncreq preq;
+
+ bzero((char *)&preq, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETPFSYNC");
+
+ bzero((char *)&preq.pfsyncr_syncif, sizeof(preq.pfsyncr_syncif));
+
+ if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFSYNC");
+}
+
+void
+setpfsync_maxupd(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ int maxupdates;
+ struct pfsyncreq preq;
+
+ maxupdates = atoi(val);
+
+ memset((char *)&preq, 0, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETPFSYNC");
+
+ preq.pfsyncr_maxupdates = maxupdates;
+
+ if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFSYNC");
+}
+
+void
+pfsync_status(int s)
+{
+ struct pfsyncreq preq;
+
+ bzero((char *)&preq, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ return;
+
+ if (preq.pfsyncr_syncif[0] != '\0') {
+ printf("\tpfsync: syncif: %s maxupd: %d\n",
+ preq.pfsyncr_syncif, preq.pfsyncr_maxupdates);
+ }
+}
+
+static struct cmd pfsync_cmds[] = {
+ DEF_CMD_ARG("syncif", setpfsync_syncif),
+ DEF_CMD_ARG("maxupd", setpfsync_maxupd),
+ DEF_CMD("-syncif", 1, unsetpfsync_syncif),
+};
+static struct afswtch af_pfsync = {
+ .af_name = "af_pfsync",
+ .af_af = AF_UNSPEC,
+ .af_other_status = pfsync_status,
+};
+
+static __constructor void
+pfsync_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(pfsync_cmds); i++)
+ af_register(&af_pfsync);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifvlan.c src/sbin/ifconfig/ifvlan.c
--- src.preview/sbin/ifconfig/ifvlan.c 2005-03-06 00:01:59.000000000 -0500
+++ src/sbin/ifconfig/ifvlan.c 2005-09-27 15:02:10.000000000 -0400
@@ -28,9 +28,6 @@
* 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: src/sbin/ifconfig/ifvlan.c,v 1.2 1999/08/28 00:13:09 peter Exp $
- * $DragonFly: src/sbin/ifconfig/ifvlan.c,v 1.6 2005/03/06 05:01:59 dillon Exp $
*/
#include <sys/param.h>
@@ -61,7 +58,8 @@
static int __tag = 0;
static int __have_tag = 0;
-void vlan_status(int s, struct rt_addrinfo *info __unused)
+static void
+vlan_status(int s)
{
struct vlanreq vreq;
@@ -78,8 +76,8 @@
return;
}
-void setvlantag(const char *val, int d __unused, int s,
- const struct afswtch *afp __unused)
+static void
+setvlantag(const char *val, int d, int s, const struct afswtch *afp)
{
u_int16_t tag;
struct vlanreq vreq;
@@ -101,8 +99,8 @@
return;
}
-void setvlandev(const char *val, int d __unused, int s,
- const struct afswtch *afp __unused)
+static void
+setvlandev(const char *val, int d, int s, const struct afswtch *afp)
{
struct vlanreq vreq;
@@ -124,8 +122,8 @@
return;
}
-void unsetvlandev(const char *val __unused, int d __unused, int s,
- const struct afswtch *afp __unused)
+static void
+unsetvlandev(const char *val, int d, int s, const struct afswtch *afp)
{
struct vlanreq vreq;
@@ -143,3 +141,30 @@
return;
}
+
+static struct cmd vlan_cmds[] = {
+ DEF_CMD_ARG("vlan", setvlantag),
+ DEF_CMD_ARG("vlandev", setvlandev),
+ DEF_CMD_ARG("-vlandev", unsetvlandev),
+ DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap),
+ DEF_CMD("-vlanmtu", -IFCAP_VLAN_MTU, setifcap),
+ DEF_CMD("vlanhwtag", IFCAP_VLAN_HWTAGGING, setifcap),
+ DEF_CMD("-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap),
+};
+static struct afswtch af_vlan = {
+ .af_name = "af_vlan",
+ .af_af = AF_UNSPEC,
+ .af_other_status = vlan_status,
+};
+
+static __constructor void
+vlan_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(vlan_cmds); i++)
+ cmd_register(&vlan_cmds[i]);
+ af_register(&af_vlan);
+#undef N
+}
diff -N -u -r src.preview/sys/bus/cam/scsi/scsi_da.c src/sys/bus/cam/scsi/scsi_da.c
--- src.preview/sys/bus/cam/scsi/scsi_da.c 2005-06-02 17:12:45.000000000 -0400
+++ src/sys/bus/cam/scsi/scsi_da.c 2005-09-23 11:24:22.000000000 -0400
@@ -345,14 +345,6 @@
},
{
/*
- * iRiver iFP MP3 player (with UMS Firmware)
- * PR: kern/54881, i386/63941, kern/66124
- */
- {T_DIRECT, SIP_MEDIA_REMOVABLE, "iRiver", "iFP*", "*"},
- /*quirks*/ DA_Q_NO_SYNC_CACHE
- },
- {
- /*
* Frontier Labs NEX IA+ Digital Audio Player, rev 1.10/0.01
* PR: kern/70158
*/
@@ -401,6 +393,14 @@
#endif /* DA_OLD_QUIRKS */
{
/*
+ * iRiver iFP MP3 player (with UMS Firmware)
+ * PR: kern/54881, i386/63941, kern/66124
+ */
+ {T_DIRECT, SIP_MEDIA_REMOVABLE, "iRiver", "iFP*", "*"},
+ /*quirks*/ DA_Q_NO_SYNC_CACHE
+ },
+ {
+ /*
* EXATELECOM (Sigmatel) i-Bead 100/105 USB Flash MP3 Player
* PR: kern/51675
*/
diff -N -u -r src.preview/sys/conf/Makefile.i386 src/sys/conf/Makefile.i386
--- src.preview/sys/conf/Makefile.i386 2005-08-16 22:51:45.000000000 -0400
+++ src/sys/conf/Makefile.i386 2005-09-23 11:24:22.000000000 -0400
@@ -68,6 +68,10 @@
# include path into 100+ source files.
INCLUDES+= -I$S/contrib/ipfilter
+# This hack lets us use the ath_hal code without spamming a new
+# include path into source files.
+INCLUDES+= -I$S/contrib/dev/ath -I$S/contrib/dev/ath/freebsd
+
COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -include opt_global.h
CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS}
diff -N -u -r src.preview/sys/conf/files src/sys/conf/files
--- src.preview/sys/conf/files 2005-09-03 21:28:57.000000000 -0400
+++ src/sys/conf/files 2005-09-23 11:24:22.000000000 -0400
@@ -65,6 +65,7 @@
bus/cam/scsi/scsi_target.c optional targ
bus/cam/scsi/scsi_targ_bh.c optional targbh
+contrib/dev/ath/freebsd/ah_osdep.c optional ath_hal
contrib/ipfilter/netinet/fil.c optional ipfilter inet
contrib/ipfilter/netinet/ip_auth.c optional ipfilter inet
contrib/ipfilter/netinet/ip_fil.c optional ipfilter inet
@@ -144,6 +145,11 @@
dev/disk/ata/atapi-fd.c optional atapifd
dev/disk/ata/atapi-tape.c optional atapist
dev/disk/ata/atapi-cam.c optional atapicam
+dev/netif/ath/if_ath.c optional ath
+dev/netif/ath/if_ath_pci.c optional ath pci
+dev/netif/ath/ath_rate/amrr/amrr.c optional ath_rate_amrr
+dev/netif/ath/ath_rate/onoe/onoe.c optional ath_rate_onoe
+dev/netif/ath/ath_rate/sample/sample.c optional ath_rate_sample
dev/raid/amr/amr_cam.c optional amr
dev/raid/amr/amr_disk.c optional amr
dev/raid/amr/amr_pci.c optional amr
@@ -700,12 +706,18 @@
net/zlib.c optional ppp_deflate
net/zlib.c optional ipsec
netproto/802_11/ieee80211.c optional wlan
+netproto/802_11/ieee80211_acl.c optional wlan
netproto/802_11/ieee80211_crypto.c optional wlan
+netproto/802_11/ieee80211_crypto_none.c optional wlan
+netproto/802_11/ieee80211_crypto_tkip.c optional wlan
+netproto/802_11/ieee80211_crypto_wep.c optional wlan
+netproto/802_11/ieee80211_dragonfly.c optional wlan
netproto/802_11/ieee80211_input.c optional wlan
netproto/802_11/ieee80211_ioctl.c optional wlan
netproto/802_11/ieee80211_node.c optional wlan
netproto/802_11/ieee80211_output.c optional wlan
netproto/802_11/ieee80211_proto.c optional wlan
+netproto/802_11/ieee80211_xauth.c optional wlan
netproto/atalk/aarp.c optional netatalk
netproto/atalk/at_control.c optional netatalk
netproto/atalk/at_proto.c optional netatalk
diff -N -u -r src.preview/sys/conf/files.i386 src/sys/conf/files.i386
--- src.preview/sys/conf/files.i386 2005-08-16 06:31:35.000000000 -0400
+++ src/sys/conf/files.i386 2005-09-23 11:24:22.000000000 -0400
@@ -47,6 +47,16 @@
no-obj no-implicit-rule before-depend \
clean "ukbdmap.h"
#
+hal.o optional ath_hal \
+ dependency "$S/contrib/dev/ath/public/i386-elf.hal.o.uu" \
+ compile-with "uudecode < $S/contrib/dev/ath/public/i386-elf.hal.o.uu" \
+ no-implicit-rule
+opt_ah.h optional ath_hal \
+ dependency "$S/contrib/dev/ath/public/i386-elf.opt_ah.h" \
+ compile-with "cp $S/contrib/dev/ath/public/i386-elf.opt_ah.h opt_ah.h" \
+ no-obj no-implicit-rule before-depend \
+ clean "opt_ah.h"
+#
emulation/linux/linux_file.c optional compat_linux
emulation/linux/linux_getcwd.c optional compat_linux
emulation/linux/linux_ioctl.c optional compat_linux
diff -N -u -r src.preview/sys/contrib/dev/ath/COPYRIGHT src/sys/contrib/dev/ath/COPYRIGHT
--- src.preview/sys/contrib/dev/ath/COPYRIGHT 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/COPYRIGHT 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,42 @@
+All files contained in this distribution are covered by the following
+copyright unless explicitly identified otherwise. Note that this
+copyright does _NOT_ contain a "or GPL" clause and does _NOT_ permit
+redistribution with changes.
+
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+ * Communications, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR 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 DAMAGES.
+ *
+ * $Id: COPYRIGHT,v 1.3 2004/01/07 23:09:27 sam Exp $
+ */
diff -N -u -r src.preview/sys/contrib/dev/ath/README src/sys/contrib/dev/ath/README
--- src.preview/sys/contrib/dev/ath/README 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/README 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,64 @@
+$Id: README,v 1.3 2004/01/07 23:09:27 sam Exp $
+
+
+WARNING: THIS IS A BETA DISTRIBUTION. THIS SOFTWARE HAS KNOWN PROBLEMS AND
+WARNING: LIMITATIONS THAT WILL BE CORRECTED BEFORE A PRODUCTION RELEASE.
+WARNING: USE AT YOUR OWN RISK!
+
+
+Atheros Hardware Access Layer (HAL)
+===================================
+
+* Copyright (c) 2002-2004 Sam Leffler.
+* Copyright (c) 2002-2004 Atheros Communications, Inc.
+* All rights reserved.
+
+Read the file COPYRIGHT for the complete copyright.
+
+This code manages much of the chip-specific operation of the Atheros driver.
+The HAL is provided in a binary-only form in order to comply with FCC
+regulations. In particular, a radio transmitter can only be operated at
+power levels and on frequency channels for which it is approved. The FCC
+requires that a software-defined radio cannot be configured by a user
+to operate outside the approved power levels and frequency channels.
+This makes it difficult to open-source code that enforces limits on
+the power levels, frequency channels and other parameters of the radio
+transmitter. See
+
+http://ftp.fcc.gov/Bureaus/Engineering_Technology/Orders/2001/fcc01264.pdf
+
+for the specific FCC regulation. Because the module is provided in a
+binary-only form it is marked "Proprietary"; this means when you load
+it you will see messages that your system is now "tainted".
+
+If you wish to use this driver on a platform for which an ath_hal
+module is not already provided please contact the author. Note that
+this is only necessary for new _architectures_; the HAL is not tied to
+any specific version of your operating system.
+
+
+Atheros Hardware
+================
+There are currently 3 generations of Atheros 802.11 wireless devices:
+
+5210 supports 11a only
+5211 supports both 11a and 11b
+5212 supports 11a, 11b, and 11g
+
+These parts have been incorporated in a variety of retail products
+including cardbus cards from DLink, Linksys, Netgear, and Proxim; and
+mini-pci cards from some of these same vendors. In addition many
+laptop vendors use Atheros mini-pci cards for their builtin wireless
+support. An (incomplete) list of products that use Atheros parts is:
+
+Netgear WAG511 D-Link DWL-AG520 Linksys WPC55AG
+Netgear WAB501 D-Link DWL-AG650 Linksys WMP55AG
+ D-Link DWL-AB650 Linksys WPC51AB
+
+In general, if a device is identified as ``11a only'' it is almost
+certain to contain an Atheros 5210 part in it. All retail a+b
+products use the 5211. The latest generation of universal a+b+g
+combo products use the 5212. When in doubt check the PCI vendor
+id with a tool like lspci, the Atheros vendor id is 0x168c; e.g.
+
+ 00:13.0 Ethernet controller: Unknown device 168c:0012 (rev 01)
diff -N -u -r src.preview/sys/contrib/dev/ath/ah.h src/sys/contrib/dev/ath/ah.h
--- src.preview/sys/contrib/dev/ath/ah.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/ah.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,691 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+ * Communications, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR 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 DAMAGES.
+ *
+ * $Id: ah.h,v 1.1.1.6 2004/12/08 18:04:16 sam Exp $
+ */
+
+#ifndef _ATH_AH_H_
+#define _ATH_AH_H_
+/*
+ * Atheros Hardware Access Layer
+ *
+ * Clients of the HAL call ath_hal_attach to obtain a reference to an ath_hal
+ * structure for use with the device. Hardware-related operations that
+ * follow must call back into the HAL through interface, supplying the
+ * reference as the first parameter.
+ */
+#include "ah_osdep.h"
+
+/*
+ * __ahdecl is analogous to _cdecl; it defines the calling
+ * convention used within the HAL. For most systems this
+ * can just default to be empty and the compiler will (should)
+ * use _cdecl. For systems where _cdecl is not compatible this
+ * must be defined. See linux/ah_osdep.h for an example.
+ */
+#ifndef __ahdecl
+#define __ahdecl
+#endif
+
+/*
+ * Status codes that may be returned by the HAL. Note that
+ * interfaces that return a status code set it only when an
+ * error occurs--i.e. you cannot check it for success.
+ */
+typedef enum {
+ HAL_OK = 0, /* No error */
+ HAL_ENXIO = 1, /* No hardware present */
+ HAL_ENOMEM = 2, /* Memory allocation failed */
+ HAL_EIO = 3, /* Hardware didn't respond as expected */
+ HAL_EEMAGIC = 4, /* EEPROM magic number invalid */
+ HAL_EEVERSION = 5, /* EEPROM version invalid */
+ HAL_EELOCKED = 6, /* EEPROM unreadable */
+ HAL_EEBADSUM = 7, /* EEPROM checksum invalid */
+ HAL_EEREAD = 8, /* EEPROM read problem */
+ HAL_EEBADMAC = 9, /* EEPROM mac address invalid */
+ HAL_EESIZE = 10, /* EEPROM size not supported */
+ HAL_EEWRITE = 11, /* Attempt to change write-locked EEPROM */
+ HAL_EINVAL = 12, /* Invalid parameter to function */
+ HAL_ENOTSUPP = 13, /* Hardware revision not supported */
+ HAL_ESELFTEST = 14, /* Hardware self-test failed */
+ HAL_EINPROGRESS = 15, /* Operation incomplete */
+} HAL_STATUS;
+
+typedef enum {
+ AH_FALSE = 0, /* NB: lots of code assumes false is zero */
+ AH_TRUE = 1,
+} HAL_BOOL;
+
+typedef enum {
+ HAL_CAP_REG_DMN = 0, /* current regulatory domain */
+ HAL_CAP_CIPHER = 1, /* hardware supports cipher */
+ HAL_CAP_TKIP_MIC = 2, /* handle TKIP MIC in hardware */
+ HAL_CAP_TKIP_SPLIT = 3, /* hardware TKIP uses split keys */
+ HAL_CAP_PHYCOUNTERS = 4, /* hardware PHY error counters */
+ HAL_CAP_DIVERSITY = 5, /* hardware supports fast diversity */
+ HAL_CAP_KEYCACHE_SIZE = 6, /* number of entries in key cache */
+ HAL_CAP_NUM_TXQUEUES = 7, /* number of hardware xmit queues */
+ HAL_CAP_VEOL = 9, /* hardware supports virtual EOL */
+ HAL_CAP_PSPOLL = 10, /* hardware has working PS-Poll support */
+ HAL_CAP_DIAG = 11, /* hardware diagnostic support */
+ HAL_CAP_COMPRESSION = 12, /* hardware supports compression */
+ HAL_CAP_BURST = 13, /* hardware supports packet bursting */
+ HAL_CAP_FASTFRAME = 14, /* hardware supoprts fast frames */
+ HAL_CAP_TXPOW = 15, /* global tx power limit */
+ HAL_CAP_TPC = 16, /* per-packet tx power control */
+} HAL_CAPABILITY_TYPE;
+
+/*
+ * "States" for setting the LED. These correspond to
+ * the possible 802.11 operational states and there may
+ * be a many-to-one mapping between these states and the
+ * actual hardware states for the LED's (i.e. the hardware
+ * may have fewer states).
+ */
+typedef enum {
+ HAL_LED_INIT = 0,
+ HAL_LED_SCAN = 1,
+ HAL_LED_AUTH = 2,
+ HAL_LED_ASSOC = 3,
+ HAL_LED_RUN = 4
+} HAL_LED_STATE;
+
+/*
+ * Transmit queue types/numbers. These are used to tag
+ * each transmit queue in the hardware and to identify a set
+ * of transmit queues for operations such as start/stop dma.
+ */
+typedef enum {
+ HAL_TX_QUEUE_INACTIVE = 0, /* queue is inactive/unused */
+ HAL_TX_QUEUE_DATA = 1, /* data xmit q's */
+ HAL_TX_QUEUE_BEACON = 2, /* beacon xmit q */
+ HAL_TX_QUEUE_CAB = 3, /* "crap after beacon" xmit q */
+ HAL_TX_QUEUE_PSPOLL = 4, /* power-save poll xmit q */
+} HAL_TX_QUEUE;
+
+#define HAL_NUM_TX_QUEUES 10 /* max possible # of queues */
+
+/*
+ * Transmit queue subtype. These map directly to
+ * WME Access Categories (except for UPSD). Refer
+ * to Table 5 of the WME spec.
+ */
+typedef enum {
+ HAL_WME_AC_BK = 0, /* background access category */
+ HAL_WME_AC_BE = 1, /* best effort access category*/
+ HAL_WME_AC_VI = 2, /* video access category */
+ HAL_WME_AC_VO = 3, /* voice access category */
+ HAL_WME_UPSD = 4, /* uplink power save */
+} HAL_TX_QUEUE_SUBTYPE;
+
+/*
+ * Transmit queue flags that control various
+ * operational parameters.
+ */
+typedef enum {
+ TXQ_FLAG_TXOKINT_ENABLE = 0x0001, /* enable TXOK interrupt */
+ TXQ_FLAG_TXERRINT_ENABLE = 0x0001, /* enable TXERR interrupt */
+ TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, /* enable TXDESC interrupt */
+ TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, /* enable TXEOL interrupt */
+ TXQ_FLAG_TXURNINT_ENABLE = 0x0008, /* enable TXURN interrupt */
+ TXQ_FLAG_BACKOFF_DISABLE = 0x0010, /* disable Post Backoff */
+ TXQ_FLAG_COMPRESSION_ENABLE = 0x0020, /* compression enabled */
+ TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040, /* enable ready time
+ expiry policy */
+ TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080, /* enable backoff while
+ sending fragment burst*/
+} HAL_TX_QUEUE_FLAGS;
+
+typedef struct {
+ u_int32_t tqi_ver; /* hal TXQ version */
+ HAL_TX_QUEUE_SUBTYPE tqi_subtype; /* subtype if applicable */
+ HAL_TX_QUEUE_FLAGS tqi_qflags; /* flags (see above) */
+ u_int32_t tqi_priority; /* (not used) */
+ u_int32_t tqi_aifs; /* aifs */
+ u_int32_t tqi_cwmin; /* cwMin */
+ u_int32_t tqi_cwmax; /* cwMax */
+ u_int16_t tqi_shretry; /* rts retry limit */
+ u_int16_t tqi_lgretry; /* long retry limit (not used)*/
+ u_int32_t tqi_cbrPeriod;
+ u_int32_t tqi_cbrOverflowLimit;
+ u_int32_t tqi_burstTime;
+ u_int32_t tqi_readyTime;
+} HAL_TXQ_INFO;
+
+/* token to use for aifs, cwmin, cwmax */
+#define HAL_TXQ_USEDEFAULT ((u_int32_t) -1)
+
+/*
+ * Transmit packet types. This belongs in ah_desc.h, but
+ * is here so we can give a proper type to various parameters
+ * (and not require everyone include the file).
+ *
+ * NB: These values are intentionally assigned for
+ * direct use when setting up h/w descriptors.
+ */
+typedef enum {
+ HAL_PKT_TYPE_NORMAL = 0,
+ HAL_PKT_TYPE_ATIM = 1,
+ HAL_PKT_TYPE_PSPOLL = 2,
+ HAL_PKT_TYPE_BEACON = 3,
+ HAL_PKT_TYPE_PROBE_RESP = 4,
+} HAL_PKT_TYPE;
+
+/* Rx Filter Frame Types */
+typedef enum {
+ HAL_RX_FILTER_UCAST = 0x00000001, /* Allow unicast frames */
+ HAL_RX_FILTER_MCAST = 0x00000002, /* Allow multicast frames */
+ HAL_RX_FILTER_BCAST = 0x00000004, /* Allow broadcast frames */
+ HAL_RX_FILTER_CONTROL = 0x00000008, /* Allow control frames */
+ HAL_RX_FILTER_BEACON = 0x00000010, /* Allow beacon frames */
+ HAL_RX_FILTER_PROM = 0x00000020, /* Promiscuous mode */
+ HAL_RX_FILTER_PROBEREQ = 0x00000080, /* Allow probe request frames */
+ HAL_RX_FILTER_PHYERR = 0x00000100, /* Allow phy errors */
+ HAL_RX_FILTER_PHYRADAR = 0x00000200, /* Allow phy radar errors*/
+} HAL_RX_FILTER;
+
+typedef enum {
+ HAL_PM_UNDEFINED = 0,
+ HAL_PM_AUTO = 1,
+ HAL_PM_AWAKE = 2,
+ HAL_PM_FULL_SLEEP = 3,
+ HAL_PM_NETWORK_SLEEP = 4
+} HAL_POWER_MODE;
+
+/*
+ * NOTE WELL:
+ * These are mapped to take advantage of the common locations for many of
+ * the bits on all of the currently supported MAC chips. This is to make
+ * the ISR as efficient as possible, while still abstracting HW differences.
+ * When new hardware breaks this commonality this enumerated type, as well
+ * as the HAL functions using it, must be modified. All values are directly
+ * mapped unless commented otherwise.
+ */
+typedef enum {
+ HAL_INT_RX = 0x00000001, /* Non-common mapping */
+ HAL_INT_RXDESC = 0x00000002,
+ HAL_INT_RXNOFRM = 0x00000008,
+ HAL_INT_RXEOL = 0x00000010,
+ HAL_INT_RXORN = 0x00000020,
+ HAL_INT_TX = 0x00000040, /* Non-common mapping */
+ HAL_INT_TXDESC = 0x00000080,
+ HAL_INT_TXURN = 0x00000800,
+ HAL_INT_MIB = 0x00001000,
+ HAL_INT_RXPHY = 0x00004000,
+ HAL_INT_RXKCM = 0x00008000,
+ HAL_INT_SWBA = 0x00010000,
+ HAL_INT_BMISS = 0x00040000,
+ HAL_INT_BNR = 0x00100000, /* Non-common mapping */
+ HAL_INT_GPIO = 0x01000000,
+ HAL_INT_FATAL = 0x40000000, /* Non-common mapping */
+ HAL_INT_GLOBAL = 0x80000000, /* Set/clear IER */
+
+ /* Interrupt bits that map directly to ISR/IMR bits */
+ HAL_INT_COMMON = HAL_INT_RXNOFRM
+ | HAL_INT_RXDESC
+ | HAL_INT_RXEOL
+ | HAL_INT_RXORN
+ | HAL_INT_TXURN
+ | HAL_INT_TXDESC
+ | HAL_INT_MIB
+ | HAL_INT_RXPHY
+ | HAL_INT_RXKCM
+ | HAL_INT_SWBA
+ | HAL_INT_BMISS
+ | HAL_INT_GPIO,
+ HAL_INT_NOCARD = 0xffffffff /* To signal the card was removed */
+} HAL_INT;
+
+typedef enum {
+ HAL_RFGAIN_INACTIVE = 0,
+ HAL_RFGAIN_READ_REQUESTED = 1,
+ HAL_RFGAIN_NEED_CHANGE = 2
+} HAL_RFGAIN;
+
+/*
+ * Channels are specified by frequency.
+ */
+typedef struct {
+ u_int16_t channel; /* setting in Mhz */
+ u_int16_t channelFlags; /* see below */
+} HAL_CHANNEL;
+
+#define CHANNEL_RAD_INT 0x0001 /* Radar interference detected on channel */
+#define CHANNEL_CW_INT 0x0002 /* CW interference detected on channel */
+#define CHANNEL_BUSY 0x0004 /* Busy, occupied or overlap with adjoin chan */
+#define CHANNEL_TURBO 0x0010 /* Turbo Channel */
+#define CHANNEL_CCK 0x0020 /* CCK channel */
+#define CHANNEL_OFDM 0x0040 /* OFDM channel */
+#define CHANNEL_2GHZ 0x0080 /* 2 GHz spectrum channel. */
+#define CHANNEL_5GHZ 0x0100 /* 5 GHz spectrum channel */
+#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed in the channel */
+#define CHANNEL_DYN 0x0400 /* dynamic CCK-OFDM channel */
+#define CHANNEL_XR 0x0800 /* XR channel */
+#define CHANNEL_AR 0x8000 /* Software use: radar detected */
+
+
+#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM)
+#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK)
+#define CHANNEL_PUREG (CHANNEL_2GHZ|CHANNEL_OFDM)
+#ifdef notdef
+#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_DYN)
+#else
+#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM)
+#endif
+#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define CHANNEL_108G (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
+#define CHANNEL_ALL \
+ (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_5GHZ|CHANNEL_2GHZ|CHANNEL_TURBO)
+#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL &~ CHANNEL_TURBO)
+
+typedef struct {
+ u_int32_t ackrcv_bad;
+ u_int32_t rts_bad;
+ u_int32_t rts_good;
+ u_int32_t fcs_bad;
+ u_int32_t beacons;
+} HAL_MIB_STATS;
+
+typedef u_int16_t HAL_CTRY_CODE; /* country code */
+typedef u_int16_t HAL_REG_DOMAIN; /* regulatory domain code */
+
+enum {
+ CTRY_DEBUG = 0x1ff, /* debug country code */
+ CTRY_DEFAULT = 0 /* default country code */
+};
+
+enum {
+ HAL_MODE_11A = 0x001,
+ HAL_MODE_TURBO = 0x002,
+ HAL_MODE_11B = 0x004,
+ HAL_MODE_PUREG = 0x008,
+#ifdef notdef
+ HAL_MODE_11G = 0x010,
+#else
+ HAL_MODE_11G = 0x008,
+#endif
+ HAL_MODE_108G = 0x020,
+ HAL_MODE_ALL = 0xfff
+};
+
+typedef struct {
+ int rateCount; /* NB: for proper padding */
+ u_int8_t rateCodeToIndex[32]; /* back mapping */
+ struct {
+ u_int8_t valid; /* valid for rate control use */
+ u_int8_t phy; /* CCK/OFDM/XR */
+ u_int16_t rateKbps; /* transfer rate in kbs */
+ u_int8_t rateCode; /* rate for h/w descriptors */
+ u_int8_t shortPreamble; /* mask for enabling short
+ * preamble in CCK rate code */
+ u_int8_t dot11Rate; /* value for supported rates
+ * info element of MLME */
+ u_int8_t controlRate; /* index of next lower basic
+ * rate; used for dur. calcs */
+ u_int16_t lpAckDuration; /* long preamble ACK duration */
+ u_int16_t spAckDuration; /* short preamble ACK duration*/
+ } info[32];
+} HAL_RATE_TABLE;
+
+typedef struct {
+ u_int rs_count; /* number of valid entries */
+ u_int8_t rs_rates[32]; /* rates */
+} HAL_RATE_SET;
+
+typedef enum {
+ HAL_ANT_VARIABLE = 0, /* variable by programming */
+ HAL_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
+ HAL_ANT_FIXED_B = 2, /* fixed to 11b frequencies */
+} HAL_ANT_SETTING;
+
+typedef enum {
+ HAL_M_STA = 1, /* infrastructure station */
+ HAL_M_IBSS = 0, /* IBSS (adhoc) station */
+ HAL_M_HOSTAP = 6, /* Software Access Point */
+ HAL_M_MONITOR = 8 /* Monitor mode */
+} HAL_OPMODE;
+
+typedef struct {
+ u_int8_t kv_type; /* one of HAL_CIPHER */
+ u_int8_t kv_pad;
+ u_int16_t kv_len; /* length in bits */
+ u_int8_t kv_val[16]; /* enough for 128-bit keys */
+ u_int8_t kv_mic[8]; /* TKIP MIC key */
+} HAL_KEYVAL;
+
+typedef enum {
+ HAL_CIPHER_WEP = 0,
+ HAL_CIPHER_AES_OCB = 1,
+ HAL_CIPHER_AES_CCM = 2,
+ HAL_CIPHER_CKIP = 3,
+ HAL_CIPHER_TKIP = 4,
+ HAL_CIPHER_CLR = 5, /* no encryption */
+
+ HAL_CIPHER_MIC = 127 /* TKIP-MIC, not a cipher */
+} HAL_CIPHER;
+
+enum {
+ HAL_SLOT_TIME_9 = 9,
+ HAL_SLOT_TIME_20 = 20,
+};
+
+/*
+ * Per-station beacon timer state. Note that the specified
+ * beacon interval (given in TU's) can also include flags
+ * to force a TSF reset and to enable the beacon xmit logic.
+ * If bs_cfpmaxduration is non-zero the hardware is setup to
+ * coexist with a PCF-capable AP.
+ */
+typedef struct {
+ u_int32_t bs_nexttbtt; /* next beacon in TU */
+ u_int32_t bs_nextdtim; /* next DTIM in TU */
+ u_int32_t bs_intval; /* beacon interval+flags */
+#define HAL_BEACON_PERIOD 0x0000ffff /* beacon interval period */
+#define HAL_BEACON_ENA 0x00800000 /* beacon xmit enable */
+#define HAL_BEACON_RESET_TSF 0x01000000 /* clear TSF */
+ u_int32_t bs_dtimperiod;
+ u_int16_t bs_cfpperiod; /* CFP period in TU */
+ u_int16_t bs_cfpmaxduration; /* max CFP duration in TU */
+ u_int32_t bs_cfpnext; /* next CFP in TU */
+ u_int16_t bs_timoffset; /* byte offset to TIM bitmap */
+ u_int16_t bs_bmissthreshold; /* beacon miss threshold */
+ u_int32_t bs_sleepduration; /* max sleep duration */
+} HAL_BEACON_STATE;
+
+/*
+ * Per-node statistics maintained by the driver for use in
+ * optimizing signal quality and other operational aspects.
+ */
+typedef struct {
+ u_int32_t ns_avgbrssi; /* average beacon rssi */
+ u_int32_t ns_avgrssi; /* average data rssi */
+ u_int32_t ns_avgtxrssi; /* average tx rssi */
+} HAL_NODE_STATS;
+
+#define HAL_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */
+
+struct ath_desc;
+
+/*
+ * Hardware Access Layer (HAL) API.
+ *
+ * Clients of the HAL call ath_hal_attach to obtain a reference to an
+ * ath_hal structure for use with the device. Hardware-related operations
+ * that follow must call back into the HAL through interface, supplying
+ * the reference as the first parameter. Note that before using the
+ * reference returned by ath_hal_attach the caller should verify the
+ * ABI version number.
+ */
+struct ath_hal {
+ u_int32_t ah_magic; /* consistency check magic number */
+ u_int32_t ah_abi; /* HAL ABI version */
+#define HAL_ABI_VERSION 0x04112900 /* YYMMDDnn */
+ u_int16_t ah_devid; /* PCI device ID */
+ u_int16_t ah_subvendorid; /* PCI subvendor ID */
+ HAL_SOFTC ah_sc; /* back pointer to driver/os state */
+ HAL_BUS_TAG ah_st; /* params for register r+w */
+ HAL_BUS_HANDLE ah_sh;
+ HAL_CTRY_CODE ah_countryCode;
+
+ u_int32_t ah_macVersion; /* MAC version id */
+ u_int16_t ah_macRev; /* MAC revision */
+ u_int16_t ah_phyRev; /* PHY revision */
+ /* NB: when only one radio is present the rev is in 5Ghz */
+ u_int16_t ah_analog5GhzRev;/* 5GHz radio revision */
+ u_int16_t ah_analog2GhzRev;/* 2GHz radio revision */
+
+ const HAL_RATE_TABLE *__ahdecl(*ah_getRateTable)(struct ath_hal *,
+ u_int mode);
+ void __ahdecl(*ah_detach)(struct ath_hal*);
+
+ /* Reset functions */
+ HAL_BOOL __ahdecl(*ah_reset)(struct ath_hal *, HAL_OPMODE,
+ HAL_CHANNEL *, HAL_BOOL bChannelChange,
+ HAL_STATUS *status);
+ HAL_BOOL __ahdecl(*ah_phyDisable)(struct ath_hal *);
+ void __ahdecl(*ah_setPCUConfig)(struct ath_hal *);
+ HAL_BOOL __ahdecl(*ah_perCalibration)(struct ath_hal*, HAL_CHANNEL *);
+ HAL_BOOL __ahdecl(*ah_setTxPowerLimit)(struct ath_hal *, u_int32_t);
+
+ /* Transmit functions */
+ HAL_BOOL __ahdecl(*ah_updateTxTrigLevel)(struct ath_hal*,
+ HAL_BOOL incTrigLevel);
+ int __ahdecl(*ah_setupTxQueue)(struct ath_hal *, HAL_TX_QUEUE,
+ const HAL_TXQ_INFO *qInfo);
+ HAL_BOOL __ahdecl(*ah_setTxQueueProps)(struct ath_hal *, int q,
+ const HAL_TXQ_INFO *qInfo);
+ HAL_BOOL __ahdecl(*ah_getTxQueueProps)(struct ath_hal *, int q,
+ HAL_TXQ_INFO *qInfo);
+ HAL_BOOL __ahdecl(*ah_releaseTxQueue)(struct ath_hal *ah, u_int q);
+ HAL_BOOL __ahdecl(*ah_resetTxQueue)(struct ath_hal *ah, u_int q);
+ u_int32_t __ahdecl(*ah_getTxDP)(struct ath_hal*, u_int);
+ HAL_BOOL __ahdecl(*ah_setTxDP)(struct ath_hal*, u_int, u_int32_t txdp);
+ u_int32_t __ahdecl(*ah_numTxPending)(struct ath_hal *, u_int q);
+ HAL_BOOL __ahdecl(*ah_startTxDma)(struct ath_hal*, u_int);
+ HAL_BOOL __ahdecl(*ah_stopTxDma)(struct ath_hal*, u_int);
+ HAL_BOOL __ahdecl(*ah_updateCTSForBursting)(struct ath_hal *,
+ struct ath_desc *, struct ath_desc *,
+ struct ath_desc *, struct ath_desc *,
+ u_int32_t, u_int32_t);
+ HAL_BOOL __ahdecl(*ah_setupTxDesc)(struct ath_hal *, struct ath_desc *,
+ u_int pktLen, u_int hdrLen,
+ HAL_PKT_TYPE type, u_int txPower,
+ u_int txRate0, u_int txTries0,
+ u_int keyIx, u_int antMode, u_int flags,
+ u_int rtsctsRate, u_int rtsctsDuration);
+ HAL_BOOL __ahdecl(*ah_setupXTxDesc)(struct ath_hal *, struct ath_desc*,
+ u_int txRate1, u_int txTries1,
+ u_int txRate2, u_int txTries2,
+ u_int txRate3, u_int txTries3);
+ HAL_BOOL __ahdecl(*ah_fillTxDesc)(struct ath_hal *, struct ath_desc *,
+ u_int segLen, HAL_BOOL firstSeg,
+ HAL_BOOL lastSeg, const struct ath_desc *);
+ HAL_STATUS __ahdecl(*ah_procTxDesc)(struct ath_hal *, struct ath_desc*);
+ void __ahdecl(*ah_getTxIntrQueue)(struct ath_hal *, u_int32_t *);
+
+ /* Receive Functions */
+ u_int32_t __ahdecl(*ah_getRxDP)(struct ath_hal*);
+ void __ahdecl(*ah_setRxDP)(struct ath_hal*, u_int32_t rxdp);
+ void __ahdecl(*ah_enableReceive)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_stopDmaReceive)(struct ath_hal*);
+ void __ahdecl(*ah_startPcuReceive)(struct ath_hal*);
+ void __ahdecl(*ah_stopPcuReceive)(struct ath_hal*);
+ void __ahdecl(*ah_setMulticastFilter)(struct ath_hal*,
+ u_int32_t filter0, u_int32_t filter1);
+ HAL_BOOL __ahdecl(*ah_setMulticastFilterIndex)(struct ath_hal*,
+ u_int32_t ndx);
+ HAL_BOOL __ahdecl(*ah_clrMulticastFilterIndex)(struct ath_hal*,
+ u_int32_t ndx);
+ u_int32_t __ahdecl(*ah_getRxFilter)(struct ath_hal*);
+ void __ahdecl(*ah_setRxFilter)(struct ath_hal*, u_int32_t);
+ HAL_BOOL __ahdecl(*ah_setupRxDesc)(struct ath_hal *, struct ath_desc *,
+ u_int32_t size, u_int flags);
+ HAL_STATUS __ahdecl(*ah_procRxDesc)(struct ath_hal *, struct ath_desc *,
+ u_int32_t phyAddr, struct ath_desc *next);
+ void __ahdecl(*ah_rxMonitor)(struct ath_hal *,
+ const HAL_NODE_STATS *);
+ void __ahdecl(*ah_procMibEvent)(struct ath_hal *,
+ const HAL_NODE_STATS *);
+
+ /* Misc Functions */
+ HAL_STATUS __ahdecl(*ah_getCapability)(struct ath_hal *,
+ HAL_CAPABILITY_TYPE, u_int32_t capability,
+ u_int32_t *result);
+ HAL_BOOL __ahdecl(*ah_setCapability)(struct ath_hal *,
+ HAL_CAPABILITY_TYPE, u_int32_t capability,
+ u_int32_t setting, HAL_STATUS *);
+ HAL_BOOL __ahdecl(*ah_getDiagState)(struct ath_hal *, int request,
+ const void *args, u_int32_t argsize,
+ void **result, u_int32_t *resultsize);
+ void __ahdecl(*ah_getMacAddress)(struct ath_hal *, u_int8_t *);
+ HAL_BOOL __ahdecl(*ah_setMacAddress)(struct ath_hal *, const u_int8_t*);
+ HAL_BOOL __ahdecl(*ah_setRegulatoryDomain)(struct ath_hal*,
+ u_int16_t, HAL_STATUS *);
+ void __ahdecl(*ah_setLedState)(struct ath_hal*, HAL_LED_STATE);
+ void __ahdecl(*ah_writeAssocid)(struct ath_hal*,
+ const u_int8_t *bssid, u_int16_t assocId);
+ HAL_BOOL __ahdecl(*ah_gpioCfgOutput)(struct ath_hal *, u_int32_t gpio);
+ HAL_BOOL __ahdecl(*ah_gpioCfgInput)(struct ath_hal *, u_int32_t gpio);
+ u_int32_t __ahdecl(*ah_gpioGet)(struct ath_hal *, u_int32_t gpio);
+ HAL_BOOL __ahdecl(*ah_gpioSet)(struct ath_hal *,
+ u_int32_t gpio, u_int32_t val);
+ void __ahdecl(*ah_gpioSetIntr)(struct ath_hal*, u_int, u_int32_t);
+ u_int32_t __ahdecl(*ah_getTsf32)(struct ath_hal*);
+ u_int64_t __ahdecl(*ah_getTsf64)(struct ath_hal*);
+ void __ahdecl(*ah_resetTsf)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_detectCardPresent)(struct ath_hal*);
+ void __ahdecl(*ah_updateMibCounters)(struct ath_hal*,
+ HAL_MIB_STATS*);
+ HAL_RFGAIN __ahdecl(*ah_getRfGain)(struct ath_hal*);
+ u_int __ahdecl(*ah_getDefAntenna)(struct ath_hal*);
+ void __ahdecl(*ah_setDefAntenna)(struct ath_hal*, u_int);
+ HAL_BOOL __ahdecl(*ah_setSlotTime)(struct ath_hal*, u_int);
+ u_int __ahdecl(*ah_getSlotTime)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_setAckTimeout)(struct ath_hal*, u_int);
+ u_int __ahdecl(*ah_getAckTimeout)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_setCTSTimeout)(struct ath_hal*, u_int);
+ u_int __ahdecl(*ah_getCTSTimeout)(struct ath_hal*);
+
+ /* Key Cache Functions */
+ u_int32_t __ahdecl(*ah_getKeyCacheSize)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_resetKeyCacheEntry)(struct ath_hal*, u_int16_t);
+ HAL_BOOL __ahdecl(*ah_isKeyCacheEntryValid)(struct ath_hal *,
+ u_int16_t);
+ HAL_BOOL __ahdecl(*ah_setKeyCacheEntry)(struct ath_hal*,
+ u_int16_t, const HAL_KEYVAL *,
+ const u_int8_t *, int);
+ HAL_BOOL __ahdecl(*ah_setKeyCacheEntryMac)(struct ath_hal*,
+ u_int16_t, const u_int8_t *);
+
+ /* Power Management Functions */
+ HAL_BOOL __ahdecl(*ah_setPowerMode)(struct ath_hal*,
+ HAL_POWER_MODE mode, int setChip,
+ u_int16_t sleepDuration);
+ HAL_POWER_MODE __ahdecl(*ah_getPowerMode)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_initPSPoll)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_enablePSPoll)(struct ath_hal *,
+ u_int8_t *, u_int16_t);
+ HAL_BOOL __ahdecl(*ah_disablePSPoll)(struct ath_hal *);
+
+ /* Beacon Management Functions */
+ void __ahdecl(*ah_beaconInit)(struct ath_hal *,
+ u_int32_t nexttbtt, u_int32_t intval);
+ void __ahdecl(*ah_setStationBeaconTimers)(struct ath_hal*,
+ const HAL_BEACON_STATE *);
+ void __ahdecl(*ah_resetStationBeaconTimers)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_waitForBeaconDone)(struct ath_hal *,
+ HAL_BUS_ADDR);
+
+ /* Interrupt functions */
+ HAL_BOOL __ahdecl(*ah_isInterruptPending)(struct ath_hal*);
+ HAL_BOOL __ahdecl(*ah_getPendingInterrupts)(struct ath_hal*, HAL_INT*);
+ HAL_INT __ahdecl(*ah_getInterrupts)(struct ath_hal*);
+ HAL_INT __ahdecl(*ah_setInterrupts)(struct ath_hal*, HAL_INT);
+};
+
+/*
+ * Check the PCI vendor ID and device ID against Atheros' values
+ * and return a printable description for any Atheros hardware.
+ * AH_NULL is returned if the ID's do not describe Atheros hardware.
+ */
+extern const char *__ahdecl ath_hal_probe(u_int16_t vendorid, u_int16_t devid);
+
+/*
+ * Attach the HAL for use with the specified device. The device is
+ * defined by the PCI device ID. The caller provides an opaque pointer
+ * to an upper-layer data structure (HAL_SOFTC) that is stored in the
+ * HAL state block for later use. Hardware register accesses are done
+ * using the specified bus tag and handle. On successful return a
+ * reference to a state block is returned that must be supplied in all
+ * subsequent HAL calls. Storage associated with this reference is
+ * dynamically allocated and must be freed by calling the ah_detach
+ * method when the client is done. If the attach operation fails a
+ * null (AH_NULL) reference will be returned and a status code will
+ * be returned if the status parameter is non-zero.
+ */
+extern struct ath_hal * __ahdecl ath_hal_attach(u_int16_t devid, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS* status);
+
+/*
+ * Return a list of channels available for use with the hardware.
+ * The list is based on what the hardware is capable of, the specified
+ * country code, the modeSelect mask, and whether or not outdoor
+ * channels are to be permitted.
+ *
+ * The channel list is returned in the supplied array. maxchans
+ * defines the maximum size of this array. nchans contains the actual
+ * number of channels returned. If a problem occurred or there were
+ * no channels that met the criteria then AH_FALSE is returned.
+ */
+extern HAL_BOOL __ahdecl ath_hal_init_channels(struct ath_hal *,
+ HAL_CHANNEL *chans, u_int maxchans, u_int *nchans,
+ HAL_CTRY_CODE cc, u_int16_t modeSelect,
+ HAL_BOOL enableOutdoor, HAL_BOOL enableExtendedChannels);
+
+/*
+ * Return bit mask of wireless modes supported by the hardware.
+ */
+extern u_int __ahdecl ath_hal_getwirelessmodes(struct ath_hal*, HAL_CTRY_CODE);
+
+/*
+ * Return rate table for specified mode (11a, 11b, 11g, etc).
+ */
+extern const HAL_RATE_TABLE * __ahdecl ath_hal_getratetable(struct ath_hal *,
+ u_int mode);
+
+/*
+ * Calculate the transmit duration of a frame.
+ */
+extern u_int16_t __ahdecl ath_hal_computetxtime(struct ath_hal *,
+ const HAL_RATE_TABLE *rates, u_int32_t frameLen,
+ u_int16_t rateix, HAL_BOOL shortPreamble);
+
+/*
+ * Convert between IEEE channel number and channel frequency
+ * using the specified channel flags; e.g. CHANNEL_2GHZ.
+ */
+extern u_int __ahdecl ath_hal_mhz2ieee(u_int mhz, u_int flags);
+extern u_int __ahdecl ath_hal_ieee2mhz(u_int ieee, u_int flags);
+
+/*
+ * Return a version string for the HAL release.
+ */
+extern char ath_hal_version[];
+/*
+ * Return a NULL-terminated array of build/configuration options.
+ */
+extern const char* ath_hal_buildopts[];
+#endif /* _ATH_AH_H_ */
diff -N -u -r src.preview/sys/contrib/dev/ath/ah_desc.h src/sys/contrib/dev/ath/ah_desc.h
--- src.preview/sys/contrib/dev/ath/ah_desc.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/ah_desc.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,180 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+ * Communications, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR 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 DAMAGES.
+ *
+ * $Id: ah_desc.h,v 1.1.1.2 2004/12/08 18:04:16 sam Exp $
+ */
+
+#ifndef _DEV_ATH_DESC_H
+#define _DEV_ATH_DESC_H
+
+/*
+ * Transmit descriptor status. This structure is filled
+ * in only after the tx descriptor process method finds a
+ * ``done'' descriptor; at which point it returns something
+ * other than HAL_EINPROGRESS.
+ *
+ * Note that ts_antenna may not be valid for all h/w. It
+ * should be used only if non-zero.
+ */
+struct ath_tx_status {
+ u_int16_t ts_seqnum; /* h/w assigned sequence number */
+ u_int16_t ts_tstamp; /* h/w assigned timestamp */
+ u_int8_t ts_status; /* frame status, 0 => xmit ok */
+ u_int8_t ts_rate; /* h/w transmit rate index */
+#define HAL_TXSTAT_ALTRATE 0x80 /* alternate xmit rate used */
+ int8_t ts_rssi; /* tx ack RSSI */
+ u_int8_t ts_shortretry; /* # short retries */
+ u_int8_t ts_longretry; /* # long retries */
+ u_int8_t ts_virtcol; /* virtual collision count */
+ u_int8_t ts_antenna; /* antenna information */
+};
+
+#define HAL_TXERR_XRETRY 0x01 /* excessive retries */
+#define HAL_TXERR_FILT 0x02 /* blocked by tx filtering */
+#define HAL_TXERR_FIFO 0x04 /* fifo underrun */
+
+/*
+ * Receive descriptor status. This structure is filled
+ * in only after the rx descriptor process method finds a
+ * ``done'' descriptor; at which point it returns something
+ * other than HAL_EINPROGRESS.
+ *
+ * If rx_status is zero, then the frame was received ok;
+ * otherwise the error information is indicated and rs_phyerr
+ * contains a phy error code if HAL_RXERR_PHY is set. In general
+ * the frame contents is undefined when an error occurred thought
+ * for some errors (e.g. a decryption error), it may be meaningful.
+ *
+ * Note that the receive timestamp is expanded using the TSF to
+ * a full 16 bits (regardless of what the h/w provides directly).
+ *
+ * rx_rssi is in units of dbm above the noise floor. This value
+ * is measured during the preamble and PLCP; i.e. with the initial
+ * 4us of detection. The noise floor is typically a consistent
+ * -96dBm absolute power in a 20MHz channel.
+ */
+struct ath_rx_status {
+ u_int16_t rs_datalen; /* rx frame length */
+ u_int16_t rs_tstamp; /* h/w assigned timestamp */
+ u_int8_t rs_status; /* rx status, 0 => recv ok */
+ u_int8_t rs_phyerr; /* phy error code */
+ int8_t rs_rssi; /* rx frame RSSI */
+ u_int8_t rs_keyix; /* key cache index */
+ u_int8_t rs_rate; /* h/w receive rate index */
+ u_int8_t rs_antenna; /* antenna information */
+ u_int8_t rs_more; /* more descriptors follow */
+};
+
+#define HAL_RXERR_CRC 0x01 /* CRC error on frame */
+#define HAL_RXERR_PHY 0x02 /* PHY error, rs_phyerr is valid */
+#define HAL_RXERR_FIFO 0x04 /* fifo overrun */
+#define HAL_RXERR_DECRYPT 0x08 /* non-Michael decrypt error */
+#define HAL_RXERR_MIC 0x10 /* Michael MIC decrypt error */
+
+enum {
+ HAL_PHYERR_UNDERRUN = 0, /* Transmit underrun */
+ HAL_PHYERR_TIMING = 1, /* Timing error */
+ HAL_PHYERR_PARITY = 2, /* Illegal parity */
+ HAL_PHYERR_RATE = 3, /* Illegal rate */
+ HAL_PHYERR_LENGTH = 4, /* Illegal length */
+ HAL_PHYERR_RADAR = 5, /* Radar detect */
+ HAL_PHYERR_SERVICE = 6, /* Illegal service */
+ HAL_PHYERR_TOR = 7, /* Transmit override receive */
+ /* NB: these are specific to the 5212 */
+ HAL_PHYERR_OFDM_TIMING = 17, /* */
+ HAL_PHYERR_OFDM_SIGNAL_PARITY = 18, /* */
+ HAL_PHYERR_OFDM_RATE_ILLEGAL = 19, /* */
+ HAL_PHYERR_OFDM_LENGTH_ILLEGAL = 20, /* */
+ HAL_PHYERR_OFDM_POWER_DROP = 21, /* */
+ HAL_PHYERR_OFDM_SERVICE = 22, /* */
+ HAL_PHYERR_OFDM_RESTART = 23, /* */
+ HAL_PHYERR_CCK_TIMING = 25, /* */
+ HAL_PHYERR_CCK_HEADER_CRC = 26, /* */
+ HAL_PHYERR_CCK_RATE_ILLEGAL = 27, /* */
+ HAL_PHYERR_CCK_SERVICE = 30, /* */
+ HAL_PHYERR_CCK_RESTART = 31, /* */
+};
+
+/* value found in rs_keyix to mark invalid entries */
+#define HAL_RXKEYIX_INVALID ((u_int8_t) -1)
+/* value used to specify no encryption key for xmit */
+#define HAL_TXKEYIX_INVALID ((u_int) -1)
+
+/* XXX rs_antenna definitions */
+
+/*
+ * Definitions for the software frame/packet descriptors used by
+ * the Atheros HAL. This definition obscures hardware-specific
+ * details from the driver. Drivers are expected to fillin the
+ * portions of a descriptor that are not opaque then use HAL calls
+ * to complete the work. Status for completed frames is returned
+ * in a device-independent format.
+ */
+struct ath_desc {
+ /*
+ * The following definitions are passed directly
+ * the hardware and managed by the HAL. Drivers
+ * should not touch those elements marked opaque.
+ */
+ u_int32_t ds_link; /* phys address of next descriptor */
+ u_int32_t ds_data; /* phys address of data buffer */
+ u_int32_t ds_ctl0; /* opaque DMA control 0 */
+ u_int32_t ds_ctl1; /* opaque DMA control 1 */
+ u_int32_t ds_hw[4]; /* opaque h/w region */
+ /*
+ * The remaining definitions are managed by software;
+ * these are valid only after the rx/tx process descriptor
+ * methods return a non-EINPROGRESS code.
+ */
+ union {
+ struct ath_tx_status tx;/* xmit status */
+ struct ath_rx_status rx;/* recv status */
+ } ds_us;
+} __packed;
+
+#define ds_txstat ds_us.tx
+#define ds_rxstat ds_us.rx
+
+/* flags passed to tx descriptor setup methods */
+#define HAL_TXDESC_CLRDMASK 0x0001 /* clear destination filter mask */
+#define HAL_TXDESC_NOACK 0x0002 /* don't wait for ACK */
+#define HAL_TXDESC_RTSENA 0x0004 /* enable RTS */
+#define HAL_TXDESC_CTSENA 0x0008 /* enable CTS */
+#define HAL_TXDESC_INTREQ 0x0010 /* enable per-descriptor interrupt */
+#define HAL_TXDESC_VEOL 0x0020 /* mark virtual EOL */
+
+/* flags passed to rx descriptor setup methods */
+#define HAL_RXDESC_INTREQ 0x0020 /* enable per-descriptor interrupt */
+#endif /* _DEV_ATH_AR521XDMA_H */
diff -N -u -r src.preview/sys/contrib/dev/ath/ah_devid.h src/sys/contrib/dev/ath/ah_devid.h
--- src.preview/sys/contrib/dev/ath/ah_devid.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/ah_devid.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+ * Communications, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR 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 DAMAGES.
+ *
+ * $Id: ah_devid.h,v 1.1.1.3 2004/12/08 18:04:16 sam Exp $
+ */
+
+#ifndef _DEV_ATH_DEVID_H_
+#define _DEV_ATH_DEVID_H_
+
+#define ATHEROS_VENDOR_ID 0x168c /* Atheros PCI vendor ID */
+/*
+ * NB: all Atheros-based devices should have a PCI vendor ID
+ * of 0x168c, but some vendors, in their infinite wisdom
+ * do not follow this so we must handle them specially.
+ */
+#define ATHEROS_3COM_VENDOR_ID 0xa727 /* 3Com 3CRPAG175 vendor ID */
+#define ATHEROS_3COM2_VENDOR_ID 0x10b7 /* 3Com 3CRDAG675 vendor ID */
+
+/* AR5210 (for reference) */
+#define AR5210_DEFAULT 0x1107 /* No eeprom HW default */
+#define AR5210_PROD 0x0007 /* Final device ID */
+#define AR5210_AP 0x0207 /* Early AP11s */
+
+/* AR5211 */
+#define AR5211_DEFAULT 0x1112 /* No eeprom HW default */
+#define AR5311_DEVID 0x0011 /* Final ar5311 devid */
+#define AR5211_DEVID 0x0012 /* Final ar5211 devid */
+#define AR5211_LEGACY 0xff12 /* Original emulation board */
+#define AR5211_FPGA11B 0xf11b /* 11b emulation board */
+
+/* AR5212 */
+#define AR5212_DEFAULT 0x1113 /* No eeprom HW default */
+#define AR5212_DEVID 0x0013 /* Final ar5212 devid */
+#define AR5212_FPGA 0xf013 /* Emulation board */
+#define AR5212_DEVID_IBM 0x1014 /* IBM minipci ID */
+#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */
+#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */
+#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */
+
+/* AR5212 compatible devid's also attach to 5212 */
+#define AR5212_DEVID_0014 0x0014
+#define AR5212_DEVID_0015 0x0015
+#define AR5212_DEVID_0016 0x0016
+#define AR5212_DEVID_0017 0x0017
+#define AR5212_DEVID_0018 0x0018
+#define AR5212_DEVID_0019 0x0019
+#define AR5212_AR2413 0x001a /* AR2413 aka Griffin-lite */
+
+/* AR5213 */
+#define AR5213_SREV_1_0 0x0055
+#define AR5213_SREV_REG 0x4020
+
+#define AR_SUBVENDOR_ID_NOG 0x0e11 /* No 11G subvendor ID */
+#define AR_SUBVENDOR_ID_NEW_A 0x7065 /* Update device to new RD */
+#endif /* _DEV_ATH_DEVID_H */
diff -N -u -r src.preview/sys/contrib/dev/ath/freebsd/ah_if.m src/sys/contrib/dev/ath/freebsd/ah_if.m
--- src.preview/sys/contrib/dev/ath/freebsd/ah_if.m 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/freebsd/ah_if.m 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,90 @@
+#
+# Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+# Communications, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that the following conditions are met:
+# 1. The materials contained herein are unmodified and are used
+# unmodified.
+# 2. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following NO
+# ''WARRANTY'' disclaimer below (''Disclaimer''), without
+# modification.
+# 3. Redistributions in binary form must reproduce at minimum a
+# disclaimer similar to the Disclaimer below and any redistribution
+# must be conditioned upon including a substantially similar
+# Disclaimer requirement for further binary redistribution.
+# 4. Neither the names of the above-listed copyright holders nor the
+# names of any contributors may be used to endorse or promote
+# product derived from this software without specific prior written
+# permission.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+# FOR 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 DAMAGES.
+#
+# $Id: ah_if.m,v 1.1.1.2 2004/12/08 18:04:16 sam Exp $
+#
+
+
+METHOD const char* ath_hal_probe {
+ u_int16_t vendorID;
+ u_int16_ deviceID;
+};
+
+METHOD struct ath_hal* ath_hal_attach {
+ u_int16_t deviceID;
+ HAL_SOFTC sc;
+ HAL_BUS_TAG st;
+ HAL_BUS_HANDLE sh;
+ HAL_STATUS* error;
+};
+
+METHOD u_int ath_hal_init_channels {
+ struct ath_hal* ah;
+ HAL_CHANNEL* chans;
+ u_int maxchans;
+ u_int* nchans;
+ HAL_CTRY_CODE cc;
+ u_int16_t modeSelect;
+ int enableOutdoor;
+};
+
+METHOD u_int ath_hal_getwirelessmodes {
+ struct ath_hal* ah;
+ HAL_CTRY_CODE cc;
+};
+
+METHOD const HAL_RATE_TABLE* ath_hal_getratetable {
+ struct ath_hal* ah;
+ u_int mode;
+};
+
+METHOD u_int16_t ath_hal_computetxtime {
+ struct ath_hal* ah;
+ const HAL_RATE_TABLE* rates;
+ u_int32_t frameLength;
+ u_int16_t rateIndex;
+ HAL_BOOL shortPreamble;
+};
+
+METHOD u_int ath_hal_mhz2ieee {
+ u_int mhz;
+ u_int flags;
+};
+
+METHOD u_int ath_hal_ieee2mhz {
+ u_int ieee;
+ u_int flags;
+};
diff -N -u -r src.preview/sys/contrib/dev/ath/freebsd/ah_osdep.c src/sys/contrib/dev/ath/freebsd/ah_osdep.c
--- src.preview/sys/contrib/dev/ath/freebsd/ah_osdep.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/freebsd/ah_osdep.c 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,419 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+ * Communications, Inc. All rights reserved.
+ *
+ * DragonFly Port - Copyright (c) 2005 Andrew Atrens
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR 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 DAMAGES.
+ *
+ * $Id: ah_osdep.c,v 1.3 2004/12/08 18:18:39 sam Exp $
+ */
+#include "opt_ah.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+
+#include <machine/stdarg.h>
+
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <contrib/dev/ath/ah.h>
+
+extern void ath_hal_printf(struct ath_hal *, const char*, ...)
+ __printflike(2,3);
+extern void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
+ __printflike(2, 0);
+extern const char* ath_hal_ether_sprintf(const u_int8_t *mac);
+extern void *ath_hal_malloc(size_t);
+extern void ath_hal_free(void *);
+#ifdef AH_ASSERT
+extern void ath_hal_assert_failed(const char* filename,
+ int lineno, const char* msg);
+#endif
+#ifdef AH_DEBUG
+extern void HALDEBUG(struct ath_hal *ah, const char* fmt, ...);
+extern void HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...);
+#endif /* AH_DEBUG */
+
+/* NB: put this here instead of the driver to avoid circular references */
+SYSCTL_NODE(_hw, OID_AUTO, ath, CTLFLAG_RD, 0, "Atheros driver parameters");
+SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD, 0, "Atheros HAL parameters");
+
+#ifdef AH_DEBUG
+static int ath_hal_debug = 0;
+SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RW, &ath_hal_debug,
+ 0, "Atheros HAL debugging printfs");
+TUNABLE_INT("hw.ath.hal.debug", &ath_hal_debug);
+#endif /* AH_DEBUG */
+
+SYSCTL_STRING(_hw_ath_hal, OID_AUTO, version, CTLFLAG_RD, ath_hal_version, 0,
+ "Atheros HAL version");
+
+int ath_hal_dma_beacon_response_time = 2; /* in TU's */
+SYSCTL_INT(_hw_ath_hal, OID_AUTO, dma_brt, CTLFLAG_RW,
+ &ath_hal_dma_beacon_response_time, 0,
+ "Atheros HAL DMA beacon response time");
+int ath_hal_sw_beacon_response_time = 10; /* in TU's */
+SYSCTL_INT(_hw_ath_hal, OID_AUTO, sw_brt, CTLFLAG_RW,
+ &ath_hal_sw_beacon_response_time, 0,
+ "Atheros HAL software beacon response time");
+int ath_hal_additional_swba_backoff = 0; /* in TU's */
+SYSCTL_INT(_hw_ath_hal, OID_AUTO, swba_backoff, CTLFLAG_RW,
+ &ath_hal_additional_swba_backoff, 0,
+ "Atheros HAL additional SWBA backoff time");
+
+void*
+ath_hal_malloc(size_t size)
+{
+ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
+}
+
+void
+ath_hal_free(void* p)
+{
+ return free(p, M_DEVBUF);
+}
+
+void
+ath_hal_vprintf(struct ath_hal *ah, const char* fmt, __va_list ap)
+{
+ vprintf(fmt, ap);
+}
+
+void
+ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
+{
+ __va_list ap;
+ __va_start(ap, fmt);
+ ath_hal_vprintf(ah, fmt, ap);
+ __va_end(ap);
+}
+
+const char*
+ath_hal_ether_sprintf(const u_int8_t *mac)
+{
+ static char buffer[256];
+ sprintf(buffer,"%6D",mac,":");
+ return &buffer[0];
+}
+
+#ifdef AH_DEBUG
+void
+HALDEBUG(struct ath_hal *ah, const char* fmt, ...)
+{
+ if (ath_hal_debug) {
+ __va_list ap;
+ __va_start(ap, fmt);
+ ath_hal_vprintf(ah, fmt, ap);
+ __va_end(ap);
+ }
+}
+
+void
+HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...)
+{
+ if (ath_hal_debug >= level) {
+ __va_list ap;
+ __va_start(ap, fmt);
+ ath_hal_vprintf(ah, fmt, ap);
+ __va_end(ap);
+ }
+}
+#endif /* AH_DEBUG */
+
+#ifdef AH_DEBUG_ALQ
+/*
+ * ALQ register tracing support.
+ *
+ * Setting hw.ath.hal.alq=1 enables tracing of all register reads and
+ * writes to the file /tmp/ath_hal.log. The file format is a simple
+ * fixed-size array of records. When done logging set hw.ath.hal.alq=0
+ * and then decode the file with the arcode program (that is part of the
+ * HAL). If you start+stop tracing the data will be appended to an
+ * existing file.
+ *
+ * NB: doesn't handle multiple devices properly; only one DEVICE record
+ * is emitted and the different devices are not identified.
+ */
+#include <sys/alq.h>
+#include <sys/pcpu.h>
+#include <contrib/dev/ath/ah_decode.h>
+
+static struct alq *ath_hal_alq;
+static int ath_hal_alq_emitdev; /* need to emit DEVICE record */
+static u_int ath_hal_alq_lost; /* count of lost records */
+static const char *ath_hal_logfile = "/tmp/ath_hal.log";
+static u_int ath_hal_alq_qsize = 64*1024;
+
+static int
+ath_hal_setlogging(int enable)
+{
+ int error;
+
+ if (enable) {
+ error = suser(curthread);
+ if (error == 0) {
+ error = alq_open(&ath_hal_alq, ath_hal_logfile,
+ curthread->td_ucred,
+ sizeof (struct athregrec), ath_hal_alq_qsize);
+ ath_hal_alq_lost = 0;
+ ath_hal_alq_emitdev = 1;
+ printf("ath_hal: logging to %s enabled\n",
+ ath_hal_logfile);
+ }
+ } else {
+ if (ath_hal_alq)
+ alq_close(ath_hal_alq);
+ ath_hal_alq = NULL;
+ printf("ath_hal: logging disabled\n");
+ error = 0;
+ }
+ return (error);
+}
+
+static int
+sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS)
+{
+ int error, enable;
+
+ enable = (ath_hal_alq != NULL);
+ error = sysctl_handle_int(oidp, &enable, 0, req);
+ if (error || !req->newptr)
+ return (error);
+ else
+ return (ath_hal_setlogging(enable));
+}
+SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW,
+ 0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging");
+SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW,
+ &ath_hal_alq_qsize, 0, "In-memory log size (#records)");
+SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW,
+ &ath_hal_alq_lost, 0, "Register operations not logged");
+
+static struct ale *
+ath_hal_alq_get(struct ath_hal *ah)
+{
+ struct ale *ale;
+
+ if (ath_hal_alq_emitdev) {
+ ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
+ if (ale) {
+ struct athregrec *r =
+ (struct athregrec *) ale->ae_data;
+ r->op = OP_DEVICE;
+ r->reg = 0;
+ r->val = ah->ah_devid;
+ alq_post(ath_hal_alq, ale);
+ ath_hal_alq_emitdev = 0;
+ } else
+ ath_hal_alq_lost++;
+ }
+ ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
+ if (!ale)
+ ath_hal_alq_lost++;
+ return ale;
+}
+
+void
+ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
+{
+ if (ath_hal_alq) {
+ struct ale *ale = ath_hal_alq_get(ah);
+ if (ale) {
+ struct athregrec *r = (struct athregrec *) ale->ae_data;
+ r->op = OP_WRITE;
+ r->reg = reg;
+ r->val = val;
+ alq_post(ath_hal_alq, ale);
+ }
+ }
+#if _BYTE_ORDER == _BIG_ENDIAN
+ if (reg >= 0x4000 && reg < 0x5000)
+ bus_space_write_4(ah->ah_st, ah->ah_sh, reg, htole32(val));
+ else
+#endif
+ bus_space_write_4(ah->ah_st, ah->ah_sh, reg, val);
+}
+
+u_int32_t
+ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(ah->ah_st, ah->ah_sh, reg);
+#if _BYTE_ORDER == _BIG_ENDIAN
+ if (reg >= 0x4000 && reg < 0x5000)
+ val = le32toh(val);
+#endif
+ if (ath_hal_alq) {
+ struct ale *ale = ath_hal_alq_get(ah);
+ if (ale) {
+ struct athregrec *r = (struct athregrec *) ale->ae_data;
+ r->op = OP_READ;
+ r->reg = reg;
+ r->val = val;
+ alq_post(ath_hal_alq, ale);
+ }
+ }
+ return val;
+}
+
+void
+OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v)
+{
+ if (ath_hal_alq) {
+ struct ale *ale = ath_hal_alq_get(ah);
+ if (ale) {
+ struct athregrec *r = (struct athregrec *) ale->ae_data;
+ r->op = OP_MARK;
+ r->reg = id;
+ r->val = v;
+ alq_post(ath_hal_alq, ale);
+ }
+ }
+}
+#elif defined(AH_DEBUG) || defined(AH_REGOPS_FUNC)
+/*
+ * Memory-mapped device register read/write. These are here
+ * as routines when debugging support is enabled and/or when
+ * explicitly configured to use function calls. The latter is
+ * for architectures that might need to do something before
+ * referencing memory (e.g. remap an i/o window).
+ *
+ * NB: see the comments in ah_osdep.h about byte-swapping register
+ * reads and writes to understand what's going on below.
+ */
+
+void
+ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
+{
+#if _BYTE_ORDER == _BIG_ENDIAN
+ if (reg >= 0x4000 && reg < 0x5000)
+ bus_space_write_4(ah->ah_st, ah->ah_sh, reg, htole32(val));
+ else
+#endif
+ bus_space_write_4(ah->ah_st, ah->ah_sh, reg, val);
+}
+
+u_int32_t
+ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(ah->ah_st, ah->ah_sh, reg);
+#if _BYTE_ORDER == _BIG_ENDIAN
+ if (reg >= 0x4000 && reg < 0x5000)
+ val = le32toh(val);
+#endif
+ return val;
+}
+#endif /* AH_DEBUG || AH_REGOPS_FUNC */
+
+#ifdef AH_ASSERT
+void
+ath_hal_assert_failed(const char* filename, int lineno, const char *msg)
+{
+ printf("Atheros HAL assertion failure: %s: line %u: %s\n",
+ filename, lineno, msg);
+ panic("ath_hal_assert");
+}
+#endif /* AH_ASSERT */
+
+/*
+ * Delay n microseconds.
+ */
+void
+ath_hal_delay(int n)
+{
+ DELAY(n);
+}
+
+u_int32_t
+ath_hal_getuptime(struct ath_hal *ah)
+{
+ struct timeval bt;
+ getmicrouptime(&bt);
+ return (bt.tv_sec * 1000) + (bt.tv_usec / 1000);
+}
+
+void
+ath_hal_memzero(void *dst, size_t n)
+{
+ bzero(dst, n);
+}
+
+void *
+ath_hal_memcpy(void *dst, const void *src, size_t n)
+{
+ return memcpy(dst, src, n);
+}
+
+/*
+ * Module glue.
+ */
+
+static int
+ath_hal_modevent(module_t mod, int type, void *unused)
+{
+ const char *sep;
+ int i;
+
+ switch (type) {
+ case MOD_LOAD:
+ printf("ath_hal: %s (", ath_hal_version);
+ sep = "";
+ for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
+ printf("%s%s", sep, ath_hal_buildopts[i]);
+ sep = ", ";
+ }
+ printf(")\n");
+ return 0;
+ case MOD_UNLOAD:
+ return 0;
+ }
+ return EINVAL;
+}
+
+static moduledata_t ath_hal_mod = {
+ "ath_hal",
+ ath_hal_modevent,
+ 0
+};
+DECLARE_MODULE(ath_hal, ath_hal_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
+MODULE_VERSION(ath_hal, 1);
diff -N -u -r src.preview/sys/contrib/dev/ath/freebsd/ah_osdep.h src/sys/contrib/dev/ath/freebsd/ah_osdep.h
--- src.preview/sys/contrib/dev/ath/freebsd/ah_osdep.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/freebsd/ah_osdep.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+ * Communications, Inc. All rights reserved.
+ * DragonFly Port - Copyright (c) 2005 Andrew Atrens
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR 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 DAMAGES.
+ *
+ * $Id: ah_osdep.h,v 1.1.1.4 2004/12/08 18:04:17 sam Exp $
+ */
+#ifndef _ATH_AH_OSDEP_H_
+#define _ATH_AH_OSDEP_H_
+/*
+ * Atheros Hardware Access Layer (HAL) OS Dependent Definitions.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+
+typedef void* HAL_SOFTC;
+typedef bus_space_tag_t HAL_BUS_TAG;
+typedef bus_space_handle_t HAL_BUS_HANDLE;
+typedef bus_addr_t HAL_BUS_ADDR;
+
+/*
+ * Delay n microseconds.
+ */
+extern void ath_hal_delay(int);
+#define OS_DELAY(_n) ath_hal_delay(_n)
+
+#define OS_INLINE __inline
+#define OS_MEMZERO(_a, _n) ath_hal_memzero((_a), (_n))
+extern void ath_hal_memzero(void *, size_t);
+#define OS_MEMCPY(_d, _s, _n) ath_hal_memcpy(_d,_s,_n)
+extern void *ath_hal_memcpy(void *, const void *, size_t);
+
+#define abs(_a) __builtin_abs(_a)
+
+struct ath_hal;
+extern u_int32_t ath_hal_getuptime(struct ath_hal *);
+#define OS_GETUPTIME(_ah) ath_hal_getuptime(_ah)
+
+/*
+ * Register read/write; we assume the registers will always
+ * be memory-mapped. Note that register accesses are done
+ * using target-specific functions when debugging is enabled
+ * (AH_DEBUG) or we are explicitly configured this way. The
+ * latter is used on some platforms where the full i/o space
+ * cannot be directly mapped.
+ */
+#if defined(AH_DEBUG) || defined(AH_REGOPS_FUNC) || defined(AH_DEBUG_ALQ)
+#define OS_REG_WRITE(_ah, _reg, _val) ath_hal_reg_write(_ah, _reg, _val)
+#define OS_REG_READ(_ah, _reg) ath_hal_reg_read(_ah, _reg)
+
+extern void ath_hal_reg_write(struct ath_hal *ah, u_int reg, u_int32_t val);
+extern u_int32_t ath_hal_reg_read(struct ath_hal *ah, u_int reg);
+#else
+/*
+ * The hardware registers are native little-endian byte order.
+ * Big-endian hosts are handled by enabling hardware byte-swap
+ * of register reads and writes at reset. But the PCI clock
+ * domain registers are not byte swapped! Thus, on big-endian
+ * platforms we have to byte-swap thoese registers specifically.
+ * Most of this code is collapsed at compile time because the
+ * register values are constants.
+ */
+#define AH_LITTLE_ENDIAN 1234
+#define AH_BIG_ENDIAN 4321
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define OS_REG_WRITE(_ah, _reg, _val) do { \
+ if ( (_reg) >= 0x4000 && (_reg) < 0x5000) \
+ bus_space_write_4((_ah)->ah_st, (_ah)->ah_sh, \
+ (_reg), htole32(_val)); \
+ else \
+ bus_space_write_4((_ah)->ah_st, (_ah)->ah_sh, \
+ (_reg), (_val)); \
+} while (0)
+#define OS_REG_READ(_ah, _reg) \
+ (((_reg) >= 0x4000 && (_reg) < 0x5000) ? \
+ le32toh(bus_space_read_4((_ah)->ah_st, (_ah)->ah_sh, \
+ (_reg))) : \
+ bus_space_read_4((_ah)->ah_st, (_ah)->ah_sh, (_reg)))
+#else /* _BYTE_ORDER == _LITTLE_ENDIAN */
+#define OS_REG_WRITE(_ah, _reg, _val) \
+ bus_space_write_4((_ah)->ah_st, (_ah)->ah_sh, (_reg), (_val))
+#define OS_REG_READ(_ah, _reg) \
+ ((u_int32_t) bus_space_read_4((_ah)->ah_st, (_ah)->ah_sh, (_reg)))
+#endif /* _BYTE_ORDER */
+#endif /* AH_DEBUG || AH_REGFUNC || AH_DEBUG_ALQ */
+
+#ifdef AH_DEBUG_ALQ
+extern void OS_MARK(struct ath_hal *, u_int id, u_int32_t value);
+#else
+#define OS_MARK(_ah, _id, _v)
+#endif
+
+#endif /* _ATH_AH_OSDEP_H_ */
diff -N -u -r src.preview/sys/contrib/dev/ath/public/i386-elf.hal.o.uu src/sys/contrib/dev/ath/public/i386-elf.hal.o.uu
--- src.preview/sys/contrib/dev/ath/public/i386-elf.hal.o.uu 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/public/i386-elf.hal.o.uu 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,3518 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting, Atheros
+ * Communications, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT,
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+ * FOR 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 DAMAGES.
+ *
+ * $Id: i386-elf.hal.o.uu,v 1.1.1.1 2004/12/08 18:04:43 sam Exp $
+ */
+#define ATH_HAL_VERSION "0.9.14.9"
+begin 644 hal.o
+M?T5,1@$!`0D```````````$``P`!```````````````4"`(``````#0`````
+M`"@`#@`+``^W5"0$@_I7#X2^````@_I7?T6#^A)_&(/Z$0^-HP```(/Z!P^$
+ME````.FM````D(/Z&@^$FP```(/Z&G\. at _H3#X2-````Z9````"#^E)T>^F&
+M````B?:!^A(1``!T9('Z$A$``'\H@?H4$```=&2!^A00``!_#+ at J````@_I8
+M=%_K6('Z!Q$``'0RZTZ)]K@]````@?H3\```=$2!^A/P``!_"H'Z$Q$``'0G
+MZRVX40```('Z&_$``'0EZQZX90```,.X<@```,.)]KA_````PXGVN)(```##
+MB?:X`````,.)]HM4)`2+1"0(9H'ZC!9T$V:!^B>G=`RY`````&:!^K<0=0X/
+MM\!0Z/'^__^#Q`2)P8G(PY!75E.+?"04BW0D&(M<)!R+3"0 at BT0D$`^WT('Z
+M!P(```^$L@```('Z!P(``'\N at _H2?QF#^A$/C80```"#^@</A),```#II@``
+M`(GV at _H3=%B#^AIT3NF5````D('Z$A$``'1<@?H2$0``?Q2!^A00``!T,('Z
+M!Q$``'1<ZW*)]H'Z$_```'0A@?H3\```?PJ!^A,1``!T$>M6@?H;\0``=![K
+M3+ at 3````@^P,45-65P^WP%#H_/___XG"@\0 at ZSN#[`Q14U97#[?`4.C\____
+MB<*#Q"#K))"#[`Q14U97#[?`4.C\____B<*#Q"#K#)"Z`````,<!`0```(72
+M=$MFBX*@`0``9HE""&:+ at J(!``!FB4(*BX*D`0``B4(<9HN"J`$``&:)0B!F
+MBX*J`0``9HE"(F:+ at JP!``!FB4(D9HN"K@$``&:)0B:)T%M>7\-55U93@^P,
+MBVPD)(M\)"B+="0LNP````"+5"0 at BT(4BP0H(?@Y\'4(N`$```#K')"#[`QJ
+M"NC\____@\000X'[YP,``'[2N`````"#Q`Q;7E]=PY!64XM,)`R+="00NP``
+M``"X`````#GP<Q&-%`")R(/@`0G0T>E#.?-R[UM>PU=64XM,)!2+="08BU0D
+M'`^WPHT$0(U$@2`/MU@&#[9`!8/X`G1F at _@"?PF%P'09Z>@```"#^`-T?X/X
+M!`^$GP```.G5````D+_`````@WPD(`!T%`^WPHT$0(!\@2D`=`=FOV``C78`
+MC03U`````(T$@(T$@(T$@,'@`[H`````]_.-1#@*Z98```"0C12=`````+C3
+M36(0]^+!Z@:-3/(5B<B)T[H`````]_.-!(4D````ZVR-=@"-%-T`````N---
+M8A#WXL'J!HU,\A6)R(G3N@````#W\XT$A18```#K0(T4G0````"XTTUB$/?B
+MP>H&C4SR%8G(B=:Z`````/?VC02%`````('[YP,``'<'!;T```#K"H/`7.L%
+MN``````/M\!;7E_#BTPD"+H"````]D$"('5)#[=!`B70````N@,````]P```
+M`'0T#[=!`B70````N at 0````]T````'0?N@$```#V00(0=10/MT$"P>@+@^`!
+M at _@!&=+WTH/B!8G0PY"+5"0$BT0D"*F`````=$6X#@```('ZM`D```^$I```
+M`('ZLPD``'<4@>IG"0``N,W,S,SWXHG0P>@"PY"!ZM`)``"XS<S,S/?BB=#!
+MZ`2#P`_#B?;VQ`%T$X'JB!,``+C-S,S,]^*)T,'H`L.X#@```('ZM`D``'1+
+M@?JS"0``=Q.!ZF<)``"XS<S,S/?BB=#!Z`+#@?J'$P``=Q:!ZM`)``"XS<S,
+MS/?BB=#!Z`2#P`_#@>J($P``N,W,S,SWXHG0P>@"PXUV`(M4)`2+1"0(J8``
+M``!T);BT"0``@_H.=%N#^@UW"HT$D at 5G"0``PY"-!)*-!(6D"```PY#VQ`%T
+M"XT$D at 6($P``PXGVN+0)``"#^@YT)H/Z#7<)C022!6<)``##@_H:=PN-!)*-
+M!(6D"```PXT$D at 6($P``PXUV`(M,)`B+1"0$BY#\!P``A=)T0O9"`A!T"(T$
+MB<'@!,.0#[="`B5``0``/4`!``!U"(T$B<'@`\.0#[="`B70````/<````!U
+M#(T$B8T$0<'@`L.)]HT$B8T$0='@PXUV`(M,)`B+1"0$BY#\!P``A=)T5O9"
+M`A!T$+C-S,S,]^&)T,'H!L.-=@`/MT(")4`!```]0`$``'40N,W,S,SWX8G0
+MP>@%PXUV``^W0@(ET````#W`````=1"XHXLNNO?AB=#!Z`7#C78`N*.++KKW
+MX8G0P>@$PXUV`%575E.#[`2+?"0<@'\$`'5QNP````")]L9$'P3_0X/['W[U
+MNP````"#/P!^58UV`(T$6XUTAR"*1 at B*3 at L/MM"(7!<$"D8)#[;`B%P'!`^V
+MZ6H`56H.5_]T)"CH_/___X/$%&:)1 at QJ`55J#E?_="0HZ/S___^#Q!1FB48.
+M0SD??ZZ#Q`1;7E]=PXGV5E.+3"0,BU0D$(M<)!2+="08C8&T`0``@_H/#X<?
+M`0``_R25``````^W@=0!``")!K@`````Z0T!``"X#0```.D#`0``N`T```#I
+M^0```+ at -````Z>\````/MT`*B0:X`````.G?````#[=`"(D&N`````#ISP``
+M``^V0`*#X`&#^`$9P(/@#>F[````BD`!P.@'#[;`@_@!&<#WT(/@#>FC````
+MB@#`Z`*#X`&#^`$9P(/@#>F.````B@#`Z`.#X`&#^`$9P(/@#>M\B@#`Z`2#
+MX`&#^`$9P(/@#>MJBX'(`0``B0:X`````.M;@_L!=!:X`````(/[`7), at _L"
+M=!>#^P-T(NLO#[^!S`$``(D&N`````#K,`^W@<X!``")!K@`````ZR"+@=`!
+M``")!K@`````ZQ&X#0```.L*B?:X#````(UV`%M>PY"+5"00BT0D%(-\)`@/
+M=1V#?"0,`W46 at _H$=Q&+1"0$B9#0`0``N`$```##D(7`=`;'``P```"X````
+M`,-55U93BVPD%(M<)""+3"0<OP````"#^P=V/HGVBT0D&`^W%+@/MW2X`HG0
+MP>`0"?")`8/!!(/K!(M%%(L$$(D!@\$$@\($@^L$.?)W!8/[`W?F1X/[!W?$
+MB<@K1"0<6UY?7<.04XM$)`B+5"0,BTPD&(M<)!R%TG0'@_H-=!;K,`6@`0``
+MB0''`Q````"X`0```.LA_S/_,?]T)!A0Z%[___^)`[@!````@\00ZP>)]K@`
+M````6\.04XM<)`R+3"00N`````"#>P0`#X0M`0``BP&)`XM!!(E#"(M!"(E#
+M#(M!#(E#$(-Y$/]T%(M!$#W_````=@6X_P```(E#%.L(QT,4`@```)"#>13_
+M=#"+412!^@`$``!V!;H`!```QT,8`0```#E3&',:N`$```"0T>"#R`$YT'+W
+MB4,8ZP:+012)0QB#>1C_=#"+41B!^@`$``!V!;H`!```QT,<`0```#E3'',>
+MN`$```"0T>"#R`$YT'+WB4,<ZPK'0QS_`P``C78`9H-Y'`!T%6:+01QF at _@/
+M=@6X#P```&:)0R#K!F;'0R`*`&:#>1X`=!=FBT$>9H/X#W8%N`\```!FB4,B
+MZPB)]F;'0R(*`(M!((E#)(M!)(E#*(M!*(E#+(M!+(E#,(-Y!`1U$(-[!`%U
+M"L=#.`$```"-=@"X`0```%O#D(M,)`B+5"0,N`````"#>@0`=%N+0 at R)00B+
+M`HD!BT((B4$$BT(,B4$(BT(0B4$,BT(4B4$0BT(8B4$4BT(<B4$89HM"(&:)
+M01QFBT(B9HE!'HM")(E!((M"*(E!)(M"+(E!*(M",(E!++@!````PY!55U93
+M@^P4BUPD-(M,)"R+5"0PQT0D#$````"+1"0H9H$X`3!V",=$)`Q6````O@``
+M```/M^H/M_F-=@"+5"0,#[<$<HG!#Z_-NF0````IPHG0#Z_'`<&X'X7K4??I
+MB00DB50D!(M$)`3!^`7!^1\IR&:)`X/#`D:#_ at I^OX/$%%M>7UW#C78`BU0D
+M"`^WPF:!^O\`=$2+1"0$9H$X`C!W*V:#^CYV$0^WPHT$@`4B%0``#[?`PXGV
+M#[?"C02`C80`[!,```^WP,.-=@`/M\*-!(`%P!(```^WP,.0BU0D"`^WPF:!
+M^O\`=!^+1"0$9H$X`C!W"XV"8`D```^WP,.0C8+\"```#[?`PXGV55=64X/L
+M#(ML)""+="0D9H$^_S]V&F:#?BP`=!.Z`0```&:#?A8`#X13`@``C78`9H$^
+M`C!V9[]0`0``NP````!F@[YV`0````^$+`(``)"#[`2-1"0.4`^WQU!'5?^5
+MA`$``(/$$(7`#X2]`0``9@^V1"0+9HF$7F(!``!F#[9$)`IFB81>9`$``(/#
+M`@^WAG8!```YV'^WZ:4!``"#[`2-1"0.4&@``0``OP$!``!5_Y6$`0``@\00
+MN@````"%P`^$N0$``&:+1"0*B<)FP>H)9HF68@$``&;!Z`*#X']FB89D`0``
+M#[=$)`K!X`6#X']FB89F`0``@^P$C40D#E`/M\=01U7_E80!``"#Q!"Z````
+M`(7`#X1C`0``9HM$)`J)PF;!Z at MF"99F`0``9L'H!(/@?V:)AF@!```/MT0D
+M"L'@`X/@?V:)AFH!``"#[`2-1"0.4`^WQU!'5?^5A`$``(/$$+H`````A<`/
+MA`T!``!FBT0D"HG"9L'J#68)EFH!``!FP>@&@^!_9HF&;`$```^W1"0*T>"#
+MX']FB89N`0``@^P$C40D#E`/M\=01U7_E80!``"#Q!"Z`````(7`#X2X````
+M9HM4)`J)T&;!Z`]F"89N`0``B=!FP>@(@^!_9HF&<`$``&;1ZH/B?V:)EG(!
+M```/MT0D"L'@!H/@?V:)AG0!``"#[`2-1"0.4`^WQU!5_Y6$`0``@\00N@``
+M``"%P'18ZPF)]KH`````ZTUFBT0D"F;!Z`IF"89T`0``NP````!F@[YV`0``
+M`'0I#[>^=@$``(UV``^WA%YB`0``4%;H$?W__X/$"&:)A%YB`0``0SG??^&Z
+M`0```(G0@\0,6UY?7<.)]E575E.#[!B+1"0PBWPD-&:+4!1FB50D$HE$)!0/
+MM\*-%("-%)"-1``#P>@"`<+!X@)2Z/S___^)P8/$$+@`````A<D/A*4```")
+M#P^W5"0&C402`R7\_P<``<B)1PAFBVPD!F:);P2^`````(/Z`'YXC78`BQ^+
+M3PB-!+:-!(:+;"0(9HM4=0!FB12!9HD4<[D`````C02VC02&C1R%`````(GV
+MC02)C02#B<(#5PAFB4H$`T<(9L=`!@``08/Y`W[BBU<(C02VC02&P>`"9L=$
+M$`8$`(M7"&;'1!!"`P!&#[=$)`8Y\'^+N`$```"#Q`Q;7E]=PXGV55=64X/L
+M!(ML)""+5"0<9HM"%F:)109FQP0DK=YFQT0D`JW>N@````"Y``````^WV(GF
+MD(G8T_BH`70*@_H!?REFB0Q60D&#^0-^Z(M4)!QFBT(49HE%!+@`````9H-]
+M!``/A-4!``#K"K@`````Z<D!``"_`````&:#?00`#X2T`0``C11_C127BT0D
+M'(T44(U:&(MU"(T$OXT$A\'@`F:+4AAFB10PBW4(9HM3$F:)5#`"N0````"-
+M!+^-!(>-%(4`````B?:-!(F-!((#10AFQT`&``!!@_D#?NMF at 7PD`JW>=68/
+MMPPDC12_C127C02)P>`"C120`U4(@\($9L="`@0`9HM#`F:)0 at 1F`T,&9HE"
+M!F8#0PIFB4((9 at -##F:)0 at IFBT,$9HE"#&:+0PAFB4(.9HM##&:)0A!FBT,0
+M9HE"$NGA````B?:-!+^-!(>--(4`````#[<$)(T$@(T$A at -%"&:+4P)FB5`(
+M#[=$)`*-!("-!(8#10AFQT`(%``/MT0D`HT$@(T$A at -%"&;'0`HC``^W1"0"
+MC02`C02&`T4(9L=`##\`#[<,)(T$B8T4A at -5"(/"!&;'0@($`&:+0 at 1F`T,&
+M9HE"!F8#0PIFB4((9 at -##F:)0 at IFBT,$9HE"#&:+0PAFB4(.9HM##&:)0A!F
+MBT,09HE"$@^W3"0"C02)C12&`U4(@\($9L="`@,`9HM#%&:)0 at QFBT,69HE"
+M#F:+0QAFB4(01P^W100Y^`^/3/[__[@!````@\0$6UY?7<.-=@!55U93@>Q<
+M`0``OU`!``#'1"0(`````,=$)`0`````@WPD"`$/A-X```"#?"0(`7\/@WPD
+M"`!T&.EC`0``C78`@WPD"`(/A`D!``#I4`$``(N$)'0!``!F at W@6``^$/@0`
+M`(-\)`0)#X\_`0``@^P$C40D$E!71_^T)'P!``"+E"2``0``_Y*$`0``@\00
+MA<`/A!X$``"`?"0.``^$"P$``(M<)`0/MD0D#O]$)`10_[0D>`$``.CU^/__
+M@\0(9HF$7#`!``!F#[9$)`]FA<`/A-<```"+7"0$#[;`_T0D!%#_M"1X`0``
+MZ,/X__^#Q`AFB81<,`$``(-\)`0)#XYJ____Z:0```"+C"1T`0``9H-Y&``/
+MA(8#``"[`````)"+A"1T`0``9H&\6%0!``#_`'099HN$6%0!``"+3"0$9HF$
+M3#`!``!!B4PD!$.#^P)^SNM8BX0D=`$``&:#>!H`#X0Z`P``NP````"0BY0D
+M=`$``&:!O%I.`0``_P!T&6:+A%I.`0``BTPD!&:)A$PP`0``08E,)`1#@_L"
+M?L[K#+@`````Z0H#``")]H/L"&@<`0``C40D'%#H_/___XM$)!1FB40D-+L`
+M````@\00.UPD!`^-7`(``(UL)`Z-=@!FBX1<,`$``&:)1%P0C11;C1239HE$
+M5"B#[`155T?_M"1\`0``BY0D@`$``/^2A`$``(/$$(7`#X27`@``C0Q;C0R+
+MC4Q,(&:+1"0.#[;09L'H!X/@`<'@"&8IPF:)40QFBT0D#HG"9L'J"&;!Z`_!
+MX`AF*<)FB5$0@^P$55='_[0D?`$``(N,)(`!``#_D80!``"#Q!"%P`^$-@(`
+M`(T,6XT,BXV,3%`!``!FBT0D#@^VT&;!Z`>#X`'!X`AF*<)FB9'D_O__9HM$
+M)`Z)PF;!Z at AFP>@/P>`(9BG"9HF1Z/[__X/L!%571_^T)'P!``"+E"2``0``
+M_Y*$`0``@\00A<`/A,P!``"-%%N-%).-5%0 at 9HM$)`Z#X!]FB4(.9HM$)`YF
+MP>@%@^`?9HE"$F:+1"0.9L'H"H/@'V:)0A:#[`155T?_M"1\`0``BXPD@`$`
+M`/^1A`$``(/$$(7`#X1Q`0``C0Q;C0R+C4Q,,&:+1"0.#[;09L'H!X/@`<'@
+M"&8IPF:)40QFBT0D#HG"9L'J"&;!Z`_!X`AF*<)FB5$.@^P$55='_[0D?`$`
+M`(N4)(`!``#_DH0!``"#Q!"%P`^$$`$``(T$6XT$@XVT1%`!``"-CN#^__]F
+MBT0D#@^VT&;!Z`>#X`'!X`AF*<)FB5$0BX0D=`$``&:!.`)`=AIFBT$(9HE!
+M"F8/MD0D#X/@/V:)AMK^___K,HT$6XT$@XV$1%`!``!FBU0D#HG19L'I"&;!
+MZ at _!X at AF*=%FB8CJ_O__9L>`VO[__P$`0SM<)`0/C*O]__^+5"0(BXPD=`$`
+M`&:+1%%F9HE$)":#[`2-!%*-A(%0"0``4(U$)!A0_[0D?`$``.A7^/__@\00
+MA<!T1(M4)`B-!%*+C"1T`0``C82!4`D``%"-1"044/^T)'@!``#H(?G__X/$
+M#(7`=!:)]O]$)`B#?"0(`@^.:/O__[@!````@<1<`0``6UY?7<.055=64XM\
+M)!2+1"08B<5FB4<(#[=7"KX`````]L(!=`6^`0```(G0T>B#X`&#^`%F@][_
+MB=#!Z`*#X`&#^`%F@][_B=#!Z`.#X`&#^`%F@][_NP````!F.>MS*I`/M\.+
+M5"0<9HL,0F:)#$>-%("-%)*-%%"-%%=FB4H,9HER#D-F.>MRUUM>7UW#B?95
+M5U93@^P\BVPD4(M\)%R^`````(-\)&``=&^0@^P$C40D$E`/M\=01U7_E80!
+M``"#Q!"%P`^$/04``(!\)`X`=$@/M]X/MD0D#D90_W0D6.AC]/__@\0(9HE$
+M7!!F#[9$)`]FA<!T(@^WW@^VP$90_W0D6. at _]/__@\0(9HE$7!`/M\8[1"1@
+M<I*-1"004`^WQE#_="1 at Z-C^__^+?"1LT>\#?"1H9L=$)!@``(/$#(M$)%AF
+M at W@(``^&M`0``(UT)`Z0#[=4)`R-!)*-!("-!$*+5"18C5Q"#&:#>P(`#X2_
+M````@^P$5@^WQU!'5?^5A`$``(/$$(7`#X1X!```9HM$)`Z#X!]FB4,,9HM$
+M)`YFP>@%@^!_9HE#!&:+1"0.9L'H#&:)0SR#[`16#[?'4$=5_Y6$`0``@\00
+MA<`/A#0$``!FBT0D#H/@/V:)0Q1FBT0D#F;!Z`:#X`]FB4-$9HM$)`YFP>@*
+M9HE#'(/L!%8/M\=01U7_E80!``"#Q!"%P`^$\`,``&:+1"0.@^`/9HE#3&:+
+M1"0.9L'H!(/@/V:)0R1F at WL"`0^&Y0```&:+1"0.9L'H"H/@'V:)0PYFBT0D
+M#F;!Z`]FB4,&@^P$5@^WQU!'5?^5A`$``(/$$(7`#X21`P``#[=$)`Z#X#_1
+MX&8)0P9FBT0D#F;!Z`:#X`]FB4,^9HM$)`YFP>@*9HE#%H/L!%8/M\=01U7_
+ME80!``"#Q!"%P`^$2P,``&:+1"0.@^`/9HE#1F:+1"0.9L'H!(/@/V:)0QYF
+MBT0D#F;!Z`J#X`]FB4-.9HM$)`YFP>@.9HE#)H/L!%8/M\=01U7_E80!``"#
+MQ!"%P`^$]P(```^W1"0.@^`/P>`"9 at E#)NM2B?9F at WL"`75)9HM$)`YFP>@*
+M@^`/9HE#5&:+1"0.9L'H#F:)0RR#[`16#[?'4$=5_Y6$`0``@\00A<`/A*4"
+M```/MT0D#H/@#\'@`F8)0RR)]F:#>P("#X:]````9HM$)`YFP>@$@^`?9HE#
+M$&:+1"0.9L'H"6:)0PB#[`16#[?'4$=5_Y6$`0``@\00A<`/A%$"``!FBT0D
+M#H/@#V:)0T!FBT0D#F;!Z`2#X#]FB4,89HM$)`YFP>@*@^`/9HE#2&:+1"0.
+M9L'H#F:)0R"#[`16#[?'4$=5_Y6$`0``@\00A<`/A/T!```/MT0D#H/@#\'@
+M`F8)0R!FBT0D#F;!Z`2#X`]FB4-09@^V1"0/@^`_9HE#*.LGC78`9H-[`@)U
+M'6:+1"0.9L'H!(/@#V:)0U9F#[9$)`^#X#]FB4,N9H-[`@,/AC4!``!FBT0D
+M#F;!Z`YFB4,2@^P$5@^WQU!'5?^5A`$``(/$$(7`#X1U`0``#[=$)`Z#X`?!
+MX`)F"4,29HM$)`YFP>@#@^!_9HE#"F:+1"0.9L'H"H/@#V:)0T)FBT0D#F;!
+MZ`YFB4,:@^P$5@^WQU!'5?^5A`$``(/$$(7`#X0>`0``#[=$)`Z#X`_!X`)F
+M"4,:9HM$)`YFP>@$@^`/9HE#2F8/MD0D#X/@/V:)0R)FBT0D#F;!Z`YFB4-2
+M@^P$5@^WQU!'5?^5A`$``(/$$(7`#X3*````#[=$)`Z#X`/!X`)F"4-29HM$
+M)`YFP>@"@^`_9HE#*F8/MD0D#X/@#V:)0UIFBT0D#F;!Z`QFB4,R@^P$5@^W
+MQU!'5?^5A`$``(/$$(7`='H/MT0D#H/@`\'@!&8)0S+K39!F at WL"`W5%9HM$
+M)`YFP>@.9HE#6(/L!%8/M\=01U7_E80!``"#Q!"%P'0]#[=$)`Z#X`/!X`)F
+M"4-89HM$)`YFP>@"@^`_9HE#,(GV9O]$)`R+5"0,BT0D6&8Y4`@/AU'[__^X
+M`0```(/$/%M>7UW#55=64X/L#(M4)"1FBT((BVPD(&:)10AFBT4*9HE$)`AF
+MQT0D!@``J`%T!V;'1"0&`0"+1"0(9M'H@^`!@_@!9H-<)`;_BT0D"&;!Z`*#
+MX`&#^`%F at UPD!O^+1"0(9L'H`X/@`8/X`6:#7"0&_V;'1"0*``"+5"0D9H-Z
+M"``/AL<```"0#[=4)`J+;"0D9HM,50"+1"0 at 9HD,4(T$DHT$@(T$0HM4)""-
+M!$)FB4@,9HML)`9FB6 at 0OP````"[``````^W="0*C02VC02`C01&T>")!"0/
+MM\N-!$F+%"2-!,*+;"0 at C10H9HE:$@^W1"0(T_BH`7069L="%`0`1V:#_P%U
+M*&;'0A0%`.L at D`^WTXT44HT$MHT$@(T$1M'@C130BT0D(&;'1`(4``!#9H/[
+M`W:B9O]$)`IFBVPD"HM4)"1F.6H(#X<Z____@\0,6UY?7<.)]E575E.#["1F
+MQT0D&*W>C40D&&;'0`*MWF;'0`2MWF;'0`:MWL=$)!``````9L=$)!0``(M$
+M)$`/MU`*NP,```"-="08#[=$)!2)V2G!B=#3^*@!=!2)V&8K1"04BTPD$&:)
+M!$Y!B4PD$&;_1"049H-\)!0#=LZ+5"0\9HM""(M,)$!FB4$(9L=$)!8``&:#
+M>0@`#X;_````#[=4)!:-!)*-!("-!$+1X(M,)#R-%`B-:@QFBU(,BTPD0&:)
+M5`@,9L=$)!0``(-\)!``#X2N````#[=4)!:-!)*-!("-!$+1X(E$)`R-=@`/
+MMU0D%`^W1%08C01`BTPD#(T$P8M,)$"-=`@2#[]$50S!X`)FB48.9HM$501F
+MB48$OP$```!F at WX"`79&#[=$)!2)1"0(9HM6`F:)5"0&D`^WSXM$)`B-'(@/
+MOT1=-&:+5$X,C01"9HE$3 at YFBT1.`F8#1%T,9HE$3 at 1'9CE\)`9WS6;_1"04
+M#[=$)!0[1"00#X)I____9O]$)!9FBTPD%HM4)$!F.4H(#X<!____N`$```"#
+MQ"1;7E]=PU575E.![`P%``"+M"0D!0``9L=$)`@$`(U$)`AFQT`"!@!FQT`$
+M"0!FQT`&#`"#[`AH[`0``(U$)!Q0Z/S___\/M[[0````@\009H-^&`!T?XVL
+M)+0!``!FBT9H9HF$)+X!``"#[`QJ!%=55O^T)#P%``#H$/?__X/$(+H`````
+MA<`/A+D```"-GO0*``!FBT9H9HE#"E53Z&O\__]35?^T)#`%``#HL?W__X/$
+M%+H`````A<`/A(8````/MT4.#[=41`8/MT4(#Z_"C7P'`I!F at WX:`'1EC:PD
+M6`,``&:+1FIFB80D8@,``(/L#&H$5U56_[0D/`4``.B*]O__@\0 at N@````"%
+MP'0WC9Z8#```9HM&:F:)0PI54^CI^___4U7_M"0P!0``Z"_]__^#Q!2Z````
+M`(7`=`B-=@"Z`0```(G0@<0,!0``6UY?7<.)]E575E.#[!R+?"0PBT0D-&:!
+M./\_=AIF at W@L`743@^P(4%?HQ?#__X/$$.DJ`P``D(M4)#1F at 3K_3W9-9H-Z
+M+`)U1H/L"%)7Z&3^__^#Q!#I!0,``+@`````Z?L"``"X`````.GQ`@``N```
+M``#IYP(``+@`````Z=T"``"X`````.G3`@``B?;'1"00`````(M,)#1F at 3D#
+M,!GV@^:P@<90`0``@WPD$`%T3H-\)!`!?PZ#?"00`'03Z9\```")]H-\)!`"
+M=&3ID0```(/&!8M$)#1FBX!V`0``9HE$)!B+7"0T@<-X`0``BU0D-('"8@$`
+M`(E4)`SK;XM,)#1F at WD8``^$/0(``(/&-V:+ at 8`#``!FB40D&(G+@<,J!```
+M@<&(`P``B4PD#.L]BU0D-&:#>AH`#X0+`@``@\9&9HN*@`,``&:)3"08B=.!
+MPXX#``"!PH(#``")5"0,ZPNX`````.GR`0``D,=$)!0`````9H-\)!@`#X3)
+M`0``C6PD&HM4)!2+3"0,9HL$46:)`X/L!%561E?_EX0!``"#Q!"%P`^$K?[_
+M_V:+1"0:9L'H"F:)0P1FBT0D&F;!Z`2#X#]FB4,"#[=$)!K!X`*#X#]FB4,>
+M@^P$559&5_^7A`$``(/$$(7`#X1S_O__9HM$)!IFP>@.9 at E#'F8/MD0D&X/@
+M/V:)0R!FBT0D&F;!Z`*#X#]FB4,B#[=$)!K!X`2#X#]FB4,D@^P$559&5_^7
+MA`$``(/$$(7`#X0L_O__9HM$)!IFP>@,9 at E#)&:+1"0:9L'H!H/@/V:)0R9F
+MBT0D&H/@/V:)0RB#[`155D97_Y>$`0``@\00A<`/A/7]__]FBT0D&F;!Z`IF
+MB4,J9HM$)!IFP>@$@^`_9HE#+`^W1"0:P>`"@^`_9HE#+H/L!%561E?_EX0!
+M``"#Q!"%P`^$N_W__V:+1"0:9L'H#F8)0RYF#[9$)!N#X#]FB4,P9HM$)!IF
+MP>@"@^`_9HE#,HU#"%`/MT,$4`^W0P)0_W0D0. at 2Y___N@````"#Q!`/MT,&
+MB<&#^`!^&HUV``^_1%,>C02`C02`T>!FB413'D(YT7_I@\,T_T0D%`^W1"08
+M.T0D%`^/._[___]$)!"#?"00`@^.//W__[@!````@\0<6UY?7<.-=@!55U93
+M@^P<BWPD-+T`````9H$__S]V"0^W1R*-<*OK$&:!/P,P&?:#YK"!QE`!``"#
+M_0%T,X/]`7\&A>UT"NMX at _T"=$OK<9"#QE7'1"00"````(V?R`0``(V'Q at 0`
+M`(E$)`SK7XUV`&:#?Q@`#X31`0``@\9EQT0D$`(```"-GSH%``"-ES@%``")
+M5"0,ZS1F at W\:``^$J0$``(/&:<=$)!`#````C9\:!0``C8<8!0``B40D#.L,
+MN`````#ID0$``(GVBU0D#&;'`@``QT0D%`````"+1"00.40D%`^-80$``)"#
+M[`2-1"0>4%9&_W0D/(M4)$#_DH0!``"#Q!"%P`^$3`$``&:!/P(P=@YF#[9$
+M)!MFB4,(ZP^)]F:+1"0:9L'H"6:)0PAF at WL(``^$^@```(7M=10/MT,(4%?H
+M]>7__X/$"&:)0PCK$@^W0PA05^@UYO__@\0(9HE#"&:!/P(P=B-FBT0D&F;!
+MZ`*#X#]FB4,&#[=$)!K!X`2#X#]FB4,$ZR&)]F:+1"0:9L'H`X/@/V:)0P8/
+MMT0D&L'@`X/@/V:)0P2#[`2-1"0>4%9&_W0D/(M4)$#_DH0!``"#Q!"%P`^$
+MB0```&:!/P(P=BMFBT0D&F;!Z`QF"4,$9HM$)!IFP>@&@^`_9HE#`F:+1"0:
+M@^`_9HD#ZRR09HM$)!IFP>@-9 at E#!&:+1"0:9L'H!X/@/V:)0P)FBT0D&F;1
+MZ(/@/V:)`XM$)`QF_P"#PPK_1"04BU0D$#E4)!0/C*'^__^018/]`@^.POW_
+M_[@!````@\0<6UY?7<.055=64X/L#(ML)""+="0D@<90!0``BT0D)&:!./\_
+M=@D/MW at B@\<:ZW>_OP$``(M4)"1F at 3H",'=GZUVX`````.FY`P``N`````#I
+MKP,``+@`````Z:4#``"X`````.F;`P``N`````#ID0,``+@`````Z8<#``"X
+M`````.E]`P``N`````#I<P,``+@`````Z6D#``"-=@"_;P$``(UV`,=$)`0`
+M````BTPD)&:#N00!````#X0_`P``B?:+1"0$BU0D)&:#O$(&`0```'499H$Z
+M`C!V!H/'".L$D(/'!X/&0.GY`@``D(M,)"1F at 3D",`^&K0```+L`````@^P$
+MC40D#E!71U7_E80!``"#Q!"%P`^$(____V:+1"0*B<)FP>H(9HD4WB7_````
+M9HE$W at B#PP*#^P=^P[L`````B?:#[`2-5"0.4E='5?^5A`$``(/$$(7`#X3I
+M_O__9@^V1"0+@^`_9HE$W@)FBT0D"F;!Z`Z#X`&)1-X$9HM$)`J#X#]FB43>
+M"F:+1"0*9L'H!H/@`8E$W at R#PP*#^P=^H>G9`0``@^P$C4PD#E%71U7_E80!
+M``"#Q!"%P`^$C_[__V:+1"0*B<)FP>H)9HD69L'H`H/@?V:)1@@/MT0D"L'@
+M!8/@?V:)1A"#[`2-1"0.4%='5?^5A`$``(/$$(7`#X15_O__9HM$)`J)PF;!
+MZ at MF"5809L'H!(/@?V:)1A@/MT0D"L'@`X/@?V:)1B"#[`2-5"0.4E='5?^5
+MA`$``(/$$(7`#X0:_O__9HM$)`J)PF;!Z at UF"58 at 9L'H!H/@?V:)1B@/MT0D
+M"M'@@^!_9HE&,(/L!(U,)`Y15T=5_Y6$`0``@\00A<`/A.#]__]FBU0D"HG0
+M9L'H#V8)1C")T&;!Z`B#X']FB48X9L'J`H/B/V:)5@(/MT0D"L'@!(/@/V:)
+M1 at J#[`2-1"0.4%='5?^5A`$``(/$$(7`#X28_?__9HM4)`J)T&;!Z`QF"48*
+MB=!FP>@&@^`_9HE&$H/B/V:)5AJ#[`2-5"0.4E='5?^5A`$``(/$$(7`#X1C
+M_?__9HM$)`J)PF;!Z at IFB58B9L'H!(/@/V:)1BH/MT0D"L'@`H/@/V:)1C*#
+M[`2-3"0.45='5?^5A`$``(/$$(7`#X0H_?__9HM$)`J)PF;!Z at YF"58R9L'H
+M"(/@/V:)1CJ[`````(GV at SS>`'1*BU0D!(M,)"0/MX11!@$``(/@!W0%@_@#
+M=1@/MP3>4/]T)"CH*N'__X/$"&:)!-[K&9`/MP3>4/]T)"CH9N'__X/$"&:)
+M!-Z-=@!#@_L'?JJ#QD"-=@#_1"0$BU0D)`^W@@0!```[1"0$#X_#_/__N`$`
+M``"#Q`Q;7E]=PXGV55=64X/L#(ML)""+="0D9L=&*`\`9L=&*@\`9H$^`C!V
+M$L<$)(0```!FQX8$`0``(`#K$,<$)&P```!FQX8$`0``$`"#[`2-1"0.4(M$
+M)`C_,%7_E80!``"#Q!#'1"0$`````(7`#X0T#0``9HM4)`J)T&;!Z`]FB48&
+MB=!FP>@.@^`!9HE&"HG09L'H"X/@!V:)1 at R)T&;!Z`2#X']FB48.9H$^_S]V
+M#XG09L'H`X/@`6:)1 at CK!F;'1@@!`&:+5"0*B=!FP>@"@^`!9HE&&HG09M'H
+M@^`!9HE&&(/B`6:)5A:+!"2+6`2#[`2-1"0.4%-#5?^5A`$``(/$$,=$)`0`
+M````A<`/A),,``!FBU0D"HG09L'H"(A&'(A6'6:!/O\_#X;7````@^P$C40D
+M#E!30U7_E80!``"#Q!#'1"0$`````(7`#X13#```9HM4)`J)T&;!Z`YFB48L
+MB=!FP>@-@^`!B8;(````B=!FP>@,@^`!B8;,````@>+_#P``9HE6+H/L!(U$
+M)`Y04T-5_Y6$`0``@\00QT0D!`````"%P`^$^`L``&:+1"0*B<*!XO\/``!F
+MB58B9L'H#H/@`8A&(6:!/O]/=C:#PP*#[`2-1"0.4%-5_Y6$`0``@\00QT0D
+M!`````"%P`^$L`L``&:+1"0*9L'H!&:)AM````"_`````(L$)(M<N`B#[`2-
+M1"0.4%-#5?^5A`$``(/$$(7`#X13"0``9@^V1"0+@^!_9HE$?C!FBT0D"F;!
+MZ`*#X#]FB41^-@^W1"0*P>`$@^`_9HE$?G*#[`2-1"0.4%-#5?^5A`$``(/$
+M$(7`#X05"0``9HM$)`IFP>@,9 at E$?G)FBT0D"F;!Z`:#X#]FB41^>&:+1"0*
+M@^`_9HE$?GZ#[`2-1"0.4%-#5?^5A`$``(/$$(7`#X3:"```9HM$)`IFP>@*
+M9HF$?H0```!FBT0D"F;!Z`2#X#]FB81^B@````^W1"0*P>`"@^`_9HF$?I``
+M``"#[`2-1"0.4%-#5?^5A`$``(/$$(7`#X23"```9HM$)`IFP>@.9 at F$?I``
+M``!F#[9$)`N#X#]FB81^E@```&:+1"0*9L'H`H/@/V:)A'Z<````#[=$)`K!
+MX`2#X#]FB81^H@```(/L!(U$)`Y04T-5_Y6$`0``@\00A<`/A#L(``!FBT0D
+M"F;!Z`QF"81^H@```&:+1"0*9L'H!H/@/V:)A'ZH````9HM$)`J#X#]FB81^
+MK@```(/L!(U$)`Y04T-5_Y6$`0``@\00A<`/A/<'``!F#[9$)`N(1#=4 at _\!
+M=%"#_P%_"X7_=`[I_@```(GV at _\"=%SK>6:+1"0*B<)FP>H%@^('9HF6\```
+M`&;!Z`*#X`=FB8;R````#[=$)`K1X(/@!V:)ANP```#K0XUV`&:+5"0*B=!F
+MP>@$@^`'9HF&]````(/B!V:)EO8```#K'V:+5"0*B=!FP>@$@^`'9HF&^```
+M`(/B!V:)EOH```"%_W5X@^P$C40D#E!30U7_E80!``"#Q!"%P`^$10<``&:+
+M5"0*B=!FP>@/9 at F&[````(G09L'H#(/@!V:)ANX```")T&;!Z`F#X`=FB8;H
+M````B=!FP>@&@^`'9HF&Z@```(G09L'H`X/@!V:)AN0```"#X@=FB9;F````
+M@^P$C40D#E!30U7_E80!``"#Q!"%P`^$V at 8``&8/MD0D"V:)1'X\9@^V1"0*
+M9HE$?D*#[`2-1"0.4%-#5?^5A`$``(/$$(7`#X2U!@``9@^V1"0+9HE$?DAF
+M#[9$)`IFB41^3H/L!(U$)`Y04T-5_Y6$`0``@\00A<`/A)`&``!F#[9$)`N(
+M1#=79@^V1"0*9HE$?EKV1'Y:@'0*#0#___]FB41^6H/L!(U$)`Y04T-5_Y6$
+M`0``@\00A<`/A%L&``!FBT0D"F;!Z`4E_P```&:)1'Y at 9HM$)`IFT>B#X`]F
+MB41^9F:+1"0*@^`!9HE$?FQF at 3[_/W8OA?]T!X/_`G04ZR1FBT0D"F;!Z`V#
+MX`%FB48DZQ)FBT0D"F;!Z`V#X`%FB48FB?9F at 3X",`^&E0```(/L!(U$)`Y0
+M4T-5_Y6$`0``@\00A<`/A-L%``!FBT0D"F;!Z`:#X']FB81^M````(/_`702
+M at _\!?P:%_W1+ZU6#_P)T(^M.9HM$)`J)PH/B!V:)EOP```!FP>@#@^`'9HF&
+M``$``.LM9HM$)`J)PH/B!V:)EOX```!FP>@#@^`'9HF&`@$``.L,9HM$)`J#
+MX#]FB4829H$^`S`/AID```!FBT0D"F;!Z`UFB81^N@```(/L!(U$)`Y04T-5
+M_Y6$`0``@\00A<`/A#<%```/MT0D"L'@`X/@.&8)A'ZZ````@_\"=2!FBU0D
+M"HG09L'H`XA&(&:!/@5`=@N)T&;!Z`MFB48JD(7_=3YF at 3[_/P^&S0,``&:+
+M5"0*B=!FP>@(@^`_9HF&1@$``&;!Z at .#XA]FB99*`0``ZPYFQX1^N@````H`
+MQD8@#V:!/O\_#X:/`P``@_\!=""#_P%_#87_#X25`@``Z7@#``"#_P(/A)L`
+M``#I:@,``(/L!(U$)`Y04T-5_Y6$`0``@\00A<`/A'X$```/MD0D"E!6Z';9
+M__^#Q`AFB894`0``#[9$)`M05NA at V?__@\0$9HF&5@$``(U$)`Y04U7_E80!
+M``"#Q!"%P`^$1P0```^V1"0*4%;H,MG__X/$"&:)AE@!``!F at 3X`0`^&Z0(`
+M`&8/MD0D"X/@/V:)AL(```#IU`(``(/L!(U$)`Y04T-5_Y6$`0``@\00A<`/
+MA`($```/MD0D"E!6Z.#8__^#Q`AFB89.`0``#[9$)`M05NC*V/__@\0$9HF&
+M4`$``(U$)`Y04T-5_Y6$`0``@\00A<`/A,H#``!FBT0D"HG"@^)_9HE6$&;!
+MZ`>#X#]FB484@^P$C40D#E!30U7_E80!``"#Q!"%P`^$H@,```^V1"0*4%;H
+M9MC__X/$"&:)AE(!``!F at 3X`0'809@^V1"0+@^`_9HF&Q````(/L!(U$)`Y0
+M4T-5_Y6$`0``@\00A<`/A&8#``!FBU0D"HG09L'H"(/@/V:)AD@!``!FP>H#
+M@^(?9HF63`$``&:!/@%`#X;'`0``@^P$C40D#E!30U7_E80!``"#Q!"%P`^$
+M*0,``&:+5"0*9@^VPF:)1BAF at 3[_3P^&DP$``(G09L'H"(/@?V:)AM8```")
+MT&;!Z`]FB8;:````@^P$C40D#E!30U7_E80!``"#Q!"%P`^$Y0(```^W1"0*
+M@^`?T>!F"8;:````9HM4)`J)T&;!Z`6#X#]FB8;B````9L'J"XB6W0```(/L
+M!(U$)`Y04U7_E80!``"#Q!"%P`^$IP(```^W1"0*@^`'P>`%"(;=````9HM$
+M)`IFP>@#B(;?````Z>H```")]F:!/@!`#X;=````@^P$C40D#E!30U7_E80!
+M``"#Q!"%P`^$9@(``&:+5"0*B="#X#]FB8;`````9H$^_T\/AJ4```")T&;!
+MZ`:#X']FB8;4````B=!FP>@-9HF&V````(/L!(U$)`Y04T-5_Y6$`0``@\00
+MA<`/A!X"```/MT0D"H/@!\'@`V8)AM@```!FBU0D"HG09L'H`X/@/V:)AN``
+M``!FP>H)B);<````@^P$C40D#E!35?^5A`$``(/$$(7`#X3?`0``#[=$)`J#
+MX`'!X`<(AMP```!FBT0D"F;1Z(B&W@```)!'@_\"#XX']___9H$^`C`/A^,!
+M``"#[`2-1"0.4&CL````5?^5A`$``(/$$,=$)`0`````A<`/A'`"``!FBT0D
+M"HG"@^('9HF6_````&;!Z`.#X`=FB88``0``@^P$C40D#E!H[0```%7_E80!
+M``"#Q!#'1"0$`````(7`#X0J`@``Z5(!``#'1"0$`````.D8`@``QT0D!```
+M``#I"P(``,=$)`0`````Z?X!``#'1"0$`````.GQ`0``QT0D!`````#IY`$`
+M`,=$)`0`````Z=<!``#'1"0$`````.G*`0``QT0D!`````#IO0$``,=$)`0`
+M````Z;`!``#'1"0$`````.FC`0``QT0D!`````#IE@$``,=$)`0`````Z8D!
+M``#'1"0$`````.E\`0``QT0D!`````#I;P$``,=$)`0`````Z6(!``#'1"0$
+M`````.E5`0``QT0D!`````#I2`$``,=$)`0`````Z3L!``#'1"0$`````.DN
+M`0``QT0D!`````#I(0$``,=$)`0`````Z10!``#'1"0$`````.D'`0``QT0D
+M!`````#I^@```,=$)`0`````Z>T```#'1"0$`````.G@````QT0D!`````#I
+MTP```&:+1"0*B<*#X@=FB9;^````9L'H`X/@!V:)A@(!``!FQX9@`0``!`!F
+MQX9>`0```0!FQX9<`0```0!FQX9:`0````"+!"2+6!2_`````&:#O at 0!````
+M=$6-=@"#[`2-1"0.4%-#5?^5A`$``(/$$(7`=(!F#[9$)`MFB81^!@$``&8/
+MMD0D"F:)A'X(`0``@\<"#[>&!`$``#GX?[YF at 3X",'<F9L=&6LK_9L=&7/__
+M9L=&7O__=Q)FQT9"#P!FQT9$'`!FQT9&'`#'1"0$`0```)"+1"0$@\0,6UY?
+M7<-64X/L#(MT)!B+7"0<4U;H0/+__X/$$+H`````A<!T5(/L"%-6Z(+3__^#
+MQ!"Z`````(7`=#Z#[`A35NA,Z/__@\00N@````"%P'0H@^P(4U;HFNO__X/$
+M$+H`````A<!T$H/L"%-6Z.#M__^)PH/$$(UV`(G0@\0$6U[#BT0D!`^W at -0!
+M```E_[\``,.-=@!3BUPD#+D`````B?8/O]&-!%)F.9P`(`L``'4$B=#K#$%F
+M at _DJ=N6X_____UO#B?93BUPD#+D`````B?8/O]&-!%)F.1S%X````'4$B=#K
+M#$%F at _EL=N6X_____UO#B?975E.+7"00BW0D%(M\)!A3Z'?___^#Q`2)P;@`
+M````9H7)>&B!X?\/``!T-KH`````C78`C035`````"G09CD,Q>`0``!U%87V
+M=`-FB0Z%_W0"B1>X`0```.LQD$*#^@IVTK@`````@[NP`0``!G4<A?9T"6:A
+MX!```&:)!H7_=`;'!P````"X`0```%M>7\-75E.+="00BT0D%(M\)!AFA<!U
+M,&H05NCT_O__B<-6Z-C^__^#Q`QFA<!T.@^WP%!6Z-K^__^#Q`AF at _C_=">)
+MP^LCD`^WP%!6Z/+^__^8C01`#[<$Q>(```!05NBO_O__B<.#Q!#WQX````!T
+M$@^_PXT$0`^WA``D"P``ZQ")]@^_PXT$0`^WA``B"P``6UY?PXGVBU0D"+ at H
+M````]L(0=1*X!0```/?"@````'4%N!0```##C78`BU0D"/;&`707B=#!Z`2#
+MX`&#^`$9P(/@#H/``\.-=@"X`````/?"@````'02B=#!Z`2#X`&#^`$9P/?0
+M@\`(PXM4)`CVQ@%T$[A`#@``]L(0=26X0`P``,.-=@"X`````/?"@````'0/
+MN.`.``#VPA!U!;C`#P``PXUV`%575E.#[""+1"0X9HE$)!Z+5"0\9HE4)!S'
+M1"04!!8``(%\)!08%@``#X,P`0``9HM$)!Z+3"049H4!#X0+`0``#[=9`E/_
+M="0XZ'7___^#Q`B)1"084_]T)#CH)/___X/$"(E$)`Q3_W0D..CO_O__@\0(
+M9HE$)!*]`````#ML)`P/C<0```"^`````(U$+0")P@'HC02`BTPD&&:#?$$"
+M``^$E@````^W1"02B40D"(E4)`2)%"2-!"J-!("-%':-!!"+5"08C01"9HM(
+M!F8Y2`AR3HM\)`B+1"0$`>B-!("-%':-!!"+5"08C1Q"D&8[3"0<=0V+3"04
+M#[=!`NMCC78`#[?1C8$P]O__9CW<`'8%C00ZZP.-0A2)P68Y0PASS4:+%"2-
+M!"J-!("+3"08#[=$00(Y\`^/>O___T4[;"0,#XP_____C78`@T0D%`2!?"04
+M&!8```^"T/[__[@`````@\0 at 6UY?7<.+1"0(@_@@=R?_)(48%@``N$`!``##
+MN*````##N,````##N%`!``##N-````##B?:X`````,.)]E575E.+="04#[=<
+M)!Q35N@,_O__@\0(B<535NC`_?__@\0(B<=3#[=$)!Q05NCV_/__B<&Z````
+M`(/$##GZ?1F-!%*-!(#1X&8Y#"AU!@'HZPR)]D(Y^GSGN+`0``!;7E]=PY`/
+MMT0D#%`/MT0D#%#_="0,Z(?___\/MP"#Q`S#4_]T)`CHFOO__X/$!(G!9H7`
+M>22)PX'C_W\``+H`````C78`C0129CD<Q>````!T0T*#^FQV[9`/M\&#Z$"#
+M^`MW.?\DA9P6``"XB`$``.LPN(@!``#K*;B+`0``ZR*XB@$``.L;N(P!``#K
+M%+B-`0``ZPT/M\/K"(UV`+@`````6\.0:@!J`/]T)`SHA_O__X/$#,.-=@`/
+MMT0D!(/X"'\. at _@'?1&#^`-T#.L2B?8]F`$``'4)D+@!````PXGVN`````##
+MB?:+3"0(N@````"-=@"-!%+!X`-F.8C@````=0F+ at .P```##B?9"@_IL=N*X
+M`````,-H0`$```^W1"0,4/]T)`SHG/O__P^WP%#H at ____X/$$(7`#Y3`#[;`
+MPXUV`%575E.#[`2+="085NA/____@\0$A<!T=&:+KM0!``"Z`````(T$U0``
+M``")P2G0P>`#9CFHX!```'5!NP````!F@[CL$````'0RO_`0``")SHUV`(G(
+M*="-!$.#/(<`=`B+!(?V``)U:$.)\8GP*=`/MP3%[!```#G8?]A"@_H*=J*X
+M`````.F\````5NCN^?__@\0$B<-FA<!Y2HG!@>'_?P``N@````"-=@"-!%+!
+MX`-F.8C@````=0F#N/``````=11"@_IL=N*X`````.MWN`$```#K<+@!````
+MZVFX`0```.MB:%`!``!6Z(O[__^#Q`B)!"1H4`$``%;H.OO__X/$"(G'#[?#
+M4%;H at _G__YB-!$!FBZP`(@L``+H`````@\0(.?I]%XUV`(T$4HT$@(L,)&8Y
+M+$%TI$(Y^GSLN`````"-=@"#Q`1;7E]=PXM,)`BZ`````&:%R746_W0D!.B9
+M_O__@\0$PXN`\````,.)]HT$4L'@`V8YB.````!TZ$*#^FQVZ[@`````PY!3
+MBUPD#+D`````B?:-!$F-%,4`````9CF:X````'4-N/````"+1`($ZPV)]D&#
+M^6QVVK@`````6\.-=@!55U93@^P$BWPD',<$)`````"+1"0 at 9HMH`H'E\`$`
+M`+X`````C78`C01VC1R%`````&8YNR`7``!U-?]T)!CH</C__X/$!&8Y at R(7
+M``!T"F:#NR(7````=1:-!'9F.2R%)!<``'4)QP0D`0```.L&1H/^$':R at SPD
+M`'1:C01VP>`"@[@H%P```'1+BX at H%P``QP0D`````+X`````9H-Y`@!T,@^W
+M60*+5+$$9H,Z`'0?B?9FBP*+?"0 at 9CL'=0BX`0```.L2D(/"`F:#.@!UXT8Y
+M\W_2BP0D@\0$6UY?7<.-=@!75E.+?"04_W0D$.C`]___@\0$B<:Z`````(GV
+MC035`````"G09CDTA0`"``!U,;D`````C035`````"G0C1R%`````(T$RV8Y
+MN`0"``!U"(N`"`(``.L308/Y`G;FB?9"@_H&=K:X`````%M>7\.0BU0D!+@!
+M````]H+5`0``0'4>N`````"#NK`!```&=!!J`&H`4NBJ]___@\0,C78`PXUV
+M`%.+7"0,N`$```!FA=MT;?]T)`CH%/?__X/$!(G!9H7`>14/M\.)RH'B_W\`
+M`#G0#Y3`#[;`ZT5F/?\!=`JZ`````&:%P'41N`$```#K+K@!````ZR>-=@"-
+M!%+!X`-F.9C@````=0EF.8CB````=-Y"@_IL=N*X`````)!;PXGV_W0D!.BC
+M]O__@\0$B<&Z`````&:%P'DL@>'_?P``B?:-!%)F.0S%X````'0(0H/Z;';M
+MZR*X`0```,.X`0```,.-=@"-!%)F.8P`(`L``'3J0H/Z*G;MN`````##C78`
+M55=64X/L/(M$)&!FB40D-(U$)#A0C40D.E#_="18Z)WV__^#Q`RZ`````(7`
+M#X2K`@``BT0D.(T4Q0`````IPL'B`XN"Y!```(M,)%")@=@!``"#?"1D`'4,
+M@<)@$P``B50D,.L8BU0D.(T$U0`````IT(T$Q>`0``")1"0PQT0D+`````"#
+M[`S_="1<BU0D8/^2@`$``(E$)#C'1"0T`````(/$$(M,)#!F at WD,``^$%P(`
+M``^W1"0TB40D#(GVBU0D)(M,)#"+;)$0#[=U`,=$)"``````BT4$9H,X``^$
+MT0$```^W1"0TB40D$(M4)`R)5"0<P>H#B50D&(M,)!S!Z0*)3"04A70D*`^$
+MC@$``(M<)!"%WG4B5O]T)%3HS/C__X/$"*F`````#X1N`0``]L,L#X1E`0``
+MD(M$)%@Y1"0L#X."`0``BT4$BU0D(`^W/%`/M\=0#[?&4/]T)%CH'O?__P^W
+MV(/$#/?#@````'0DB=@ET````#W0````=!:!XP_^___V1"08`70%@,O`ZP2`
+MRZ"0A=L/A``!``"`Y_WWQ at P```!T68'_J`D``'0:@?^H"0``=PJ!_Z,)``!T
+M"NL/@?^T"0``=0>X`0```.L%N`$```"%P'0J@?^T"0``=0:`XS^`RZ`/M\=0
+M_W0D5.B$_/__@\0(A<!T"(#/`NL#@,\"BTPD+(M$)%1FB3R(9HE<B`)!B4PD
+M+(M4)%0/MT2*_B70````/<````!U*O9$)!0!=".+1"18.<$/@X<```"`XS^`
+MRZ!FB3R*9HE<B@)!B4PD+(UV`(M4)"R+3"14#[=$D?XE4`$``#U0`0``=2OV
+M1"0<`70DBT0D6#G"<TB!XZ_^__^!RT`!``!FB3R19HE<D0)"B50D+(GV_T0D
+M((M%!(M4)"!F at SQ0``^%4O[___]$)"2+3"0P#[=!##M$)"0/C_3]__^+1"1<
+MBU0D+(D0A=(/E<`/MM")T(/$/%M>7UW#BU0D!(M,)`AFBP)F.P%U&`^W4@*!
+MXO`!```/MT$")?`!```IPNL)D`^W$@^W`2G"B=##D%575E.#["R+?"1`BUPD
+M4(M$)%1FB40D(F;'1"0:6!M7Z%_\__^#Q`2Z`````(7`#X2C`P``5^A1]___
+M9HF'U@$``%?HR/?__X/$"(7`=`K'A]P!```!````9H._U@$```!U(0^WPU!7
+MZ)?[__^#Q`BZ`````(7`#X1;`P``9HF?U@$``(/L"`^WA]8!``!05^C\____
+MB40D+%?H,?O__X/$%(7`=$*#[`C_="1D9HM$)"XC1"0H#[?`4/]T)%S_="1<
+M_W0D7%?H&/S__X/$(+H`````A<`/A/P"``"+5"1,BRKI?`(``)"#?"18`'41
+M9H'[2`-U"F;'1"0:71:-=@"]`````+X$%@``@?X8%@``#X--`@``B?9FBUPD
+M(F:%'@^$+@(```^W!H5$)!P/A"$"``"-1"0J4(U$)"Q0#[=&`E!7_Y=X`0``
+M@\00A<`/A``"```/MT8"4`^WA]8!``!05^BE]?__B40D(`^W7@)35^A2\___
+M@\0(9HE$)!Y3#[>'U@$``%!7Z./U__]FB40D*,=$)"0`````@\08BT0D%&:#
+M>`(`#X2H`0``BU0D#(T$4HM<)!2-!$-FBU@&9CE8"`^"<P$``(U$)"2)1"0$
+M9CE<)"@/AT4!``!F.UPD*@^'.@$``&8[7"0:#X<O`0``9H'[M`EU#&:!?@+`
+M``^$'`$```^WPXM4)%P]J`D``'07/:@)``!W"3VC"0``=`GK"SVT"0``=02)
+MT.L%N`$```"%P`^$Y@```#ML)$@/@Q\!``!FB5PD)(U4)"1FBT8"9HE"`F:!
+M^[0)=0 at D/PR at 9HE"`HU4)"2)5"0(9H%B`O_]4@^W1"044%?H_??__X/$#(7`
+M=`R+1"0(9H%(`@`"ZU,/MP:H#'1,#[?#/:@)``!T%SVH"0``=PD]HPD``'0)
+MZPX]M`D``'4'N`$```#K!;@!````A<!T&P^WPU!7Z(SX__^#Q`B%P'0*BU0D
+M!&:!2@(``HM$)"2+5"1$B02J10^W1*K^)5`!```]4`$``'4>]D0D(@%T%SML
+M)$AS5(M$)`1F at V`"[XM$)"2)!*I%9 at -<)!*+5"0,C012BU0D%&8Y7$((#X.5
+M_O___T0D#(M<)!0/MT,".T0D#`^'6_[__XUV`(/&!('^&!8```^"M?W__X7M
+M=%5H@$4``&H$5?]T)%#H;`8``(/$$(/]0'8%O4````")K_@'``"Y`````#GI
+M<RB-!$F-!,>+7"1$9HL4BV:)D/@!``!FBU2+`F:)D/H!``!!.>ERVHGVBT0D
+M3(DH9HN'U@$``&:)1QB%[0^5P`^VT(UV`(G0@\0L6UY?7<.)]E575E.+3"04
+MBUPD&`^W>P*!Y_`!``"+D?P'``"%TG0<9HL"9CL#=10/MT(")?`!```Y^'1=
+MZP6)RNM7D(VQ^`$``(N1^`<``(72=$$/MQN0B=#1^(T$0(T,Q@^W`8G=*<6)
+MZ'4<#[=!`B7P`0``.?ATQ0^W00(E\`$``(G]*<6)Z(7`?@2-<1A*T?IUP[H`
+M````B=!;7E]=PXUV`%575E.#[`R+1"0D9HL`9HE$)`J+5"0 at xxxxx@$````/
+MA?D```!2Z(7N__^#Q`1FB40D"+@`````9H-\)`@`>!*+1"0()?\/``#K!XG0
+MZ2(!``!FB40D"&:%P`^$O@```+\`````C78`C03]`````"GXBUPD"&8Y',7@
+M$```#X61````BVPD)`^W70)3_W0D). at 7\/__@\0(B<93_W0D).C([___@\0(
+MB40D!+L`````.<-]8+D`````C00;B<(!V(T$@&:#?$8"`'0_B10DB?:-!!J-
+M!("-%$F-!!"-!$:-4`9FBVPD"F8Y:`9W"F8Y:@(/@U3___]!BQ0DC00:C02`
+M#[=$1@(YR'_&0SM<)`1\HXUV`$>#_PH/ADK___^+5"0D#[="`E"+7"0D#[>#
+MU@$``%!3Z%/Q__^)QK\`````@\0,9H-X`@!T)0^W2`*)]HT$?XT41HU"!F:+
+M;"0*9CEJ!G<&9CEJ"',*1SGY?^&X`````(/$#%M>7UW#_W0D"/]T)`CH=_[_
+M_X/$"+H`````A<!T&P^V4`71XHM$)`PHT`^^T(3`>0BZ`````(UV`(G0PY!5
+M5U93@^P<BWPD,(''Y`$```^V1P&#Z`.)1"00QT0D%`````"#^`(/CHD```"-
+M=@"+5"04C012`?AF#[90!6:)5"0:BE@'O@````"`>`8`=%&+1"04C2Q`A-MT
+M/(M4)#@X6 at 1R,XM$)#0/MP")1"0,@^P(BU0D/`^W0@)0#[=$)"90Z/S___^#
+MQ!`Y1"0,=0@/ML/K*8UV`$8/MD0]!CGP?[:#;"00`_]$)!2#?"00`@^/>O__
+M_XM4)#@/MD($@\0<6UY?7<.)]E93@^P$BUPD$(MT)!2#N]P!````=#.Z$@``
+M`/9&`H!U9[H`````9HL.C78`C012T>!F.XA`````<@EF.XA"````<CM"@_H&
+M=N-64^@T_?__@\0(N at 4```"%P'0L@[O@`0```'03@^P$4%93Z,C^__\/MM"#
+MQ!#K$`^V4`3K"@^VD$0```"-=@")T(/$!%M>PU575E.#[!"+1"0D9H.XU@$`
+M```/A1(!``!0Z(7K__^#Q`1FB40D#HM4)"AFBQ)FB50D#+@`````9H-\)`X`
+M>!1FBT0D#B7_#P``ZPB-!#GI]0```&:)1"0.9H7`#X3)````QT0D"`````")
+M]HM$)`C!X`,K1"0(9HML)`YF.2S%X!````^%D@```(M$)"@/MU@"4_]T)"CH
+M!.W__X/$"(G'4_]T)"CHM>S__X/$"(E$)`2^`````#G&?6&0NP````"-!#:)
+MP@'PC02`9H-\1P(`=$")%"2)]HT$,HT$@(T,`(T$6XT$00'XC5`&BVPD#&8Y
+M:`9W"F8Y:@(/@TS___]#BQ0DC00RC02`#[=$1P(YV'_%1CMT)`1\HHGV_T0D
+M"(-\)`@*#X9!____BU0D*`^W0@)0BVPD*`^WA=8!``!05>@Z[O__@\0,@\00
+M6UY?7<.-=@!3BUPD#%/_="0,Z)W^__\/ME`$#[=#`B7`````@\0(/<````!U
+M$HG0@^`/@_@!=0B#XO"#R@*)]HG06\-75E.+?"00BW0D%(/L#%?_EX`!``")
+MPX/$$*@"="H/M\905^B\\/__@\0(A<!U`X/C_0^WQE!7Z.CP__^#Q`B%P'4%
+M@^/?B?;VPP%T%P^WQE!7Z!'O__^#Q`B%P'4&@^/^C78`]L,(=!</M\905^C%
+M[O__@\0(A<!U!H/C]XUV`(G86UY?PXGVBU0D!(M$)`@/MT`"4`^W at M8!``!0
+M4NAUZO__N@````"#Q`RY[!<``&8Y!%%U!K@!````PT*#^@5V[K@`````PU57
+M5E.#[`R+;"0HBT0D((E$)`0!Z(D$)(M$)"1(B40D"'1#BSPDBT0D!#G'=B^)
+M]HG^*>Z#[`A75O]4)#R#Q!"%P'X9B?F)ZXH6B@&(!D:($4%+=?,I[SM\)`1W
+MTP$L)/],)`AUO8/$#%M>7UW#D)!55U93@>RH````BZPDO````&B4"0``Z/S_
+M__^)PX/$$+X"````A<`/A&@%``")QX/L!&@`"```:``8``!0Z/S___^+A"3$
+M````B4,,BX0DR````(E#$(N$),P```")0Q1FB:N@`0``9L>#H@$`````9L>#
+MS`$``#P`QX/0`0```````,>#Q`@```````#'@X0)````````QX.("0``____
+M_\>#C`D``/_____'@Y`)``#_____@\0(:@!3Z/S___^#Q!"^`P```(7`#X3%
+M!```QX.D`0```0```(M#%(N0($```&8/MM)FB9.H`0``BY`8F```9HF3J@$`
+M`&;'@ZX!`````,>`T)@``!8<``"^`````)"+1Q3'@("8``````$`1H/^`W;M
+MBT<4BX``G```P>@<@^P(:@10Z/S___]`9HF'K`$``(M7%(N"$$```(E$)!B#
+MR`&)@A!```"#Q`R-1"024&H]5^C\____@\00O@@```"%P`^$#`0``+X$````
+M9H%\)`ZE6@^%^@,``(/L!(U$)!)0:C]7Z/S___^#Q!"^"````(7`#X3:`P``
+M9HM$)`YFB8,""```@^P$C40D$E!HP0```%?H_/___X/$$+X(````A<`/A*L#
+M``!FBT0D#F;!Z`QFB8,`"```O at 4```!F at _@!#X6,`P``O0````"^`````(GV
+M@^P$C41T%%"-AL````!05^C\____@\00A<`/A%@#```/MT1T$#'%1H/^/W;3
+MO@<```"!_?__```/A4(#``"#[`2-1"024&B_````5^C\____@\00O@@```"%
+MP`^$'P,``&8/MD0D#F:)A]0!``"+1"049HF#!`@``&:+1"069HF#!@@``(M$
+M)!B(@P@(``!F#[9$)!F(@PD(``!FBT0D&HB#"P@``&8/MD0D&XB#"@@``&8/
+MMD0D'8B##@@``(M$)!R(@P\(``!F#[9$)!^(@Q`(``!FBT0D'HB#$0@``(I$
+M)""#X`&(@PP(``"+1"0 at 9M'H@^`'B(,-"```O@````"]"0```(T4]0`````I
+M\HT4E@':C8H2"```9HM$;!!FP>@*B((2"```9HM$;!!FP>@$@^`_B$$+#[=$
+M;!#!X`*#X#QFBU1L$F;!Z at X)T(A!`8I$;!.#X#^(00QFBT1L$F;!Z`*#X#^(
+M00(/MT1L$L'@!(/@,&:+5&P49L'J#`G0B$$-9HM$;!1FP>@&@^`_B$$#BD1L
+M%(/@/XA!#F:+1&P69L'H"HA!!&:+1&P69L'H!(/@/XA!#P^W1&P6P>`"@^`\
+M9HM4;!AFP>H."="(006*1&P9@^`_B$$09HM$;!AFP>@"@^`_B$$&#[=$;!C!
+MX`2#X#!FBU1L&F;!Z at P)T(A!$6:+1&P:9L'H!H/@/XA!!XI$;!J#X#^(01)F
+MBT1L'&;!Z`J(00AFBT1L'&;!Z`2#X#^(01,/MT1L','@`H/@/&:+5&P>9L'J
+M#@G0B$$)BD1L'X/@/XA!%&:+1&P>9L'H`H/@/XA!"@^W1&P>P>`$@^`P9HM4
+M;"!FP>H,"="(015FBT1L(&;!Z`:#X#^(01:*1&P@@^`_B$$79HM$;")FP>@*
+MB$$89HM$;")FP>@$@^`_B$$9#[=$;"+!X`*#X#QFBU1L)&;!Z at X)T(A!&HI$
+M;"6#X#^(01MFBT1L)&;!Z`*#X#^(01Q&@\4+ at _X$#X82_O__@^P,5^CW````
+MO0````"^`````(/$$(/L!(U$)!)0N!\````I\%!7Z/S___^#Q!"%P'1*#[=$
+M)`X!Q68/MD0D#XB$<Z,(``!FBT0D#HB$<Z0(``!&@_X"=KV%[70(@?W]_P(`
+M=0>^"0```.L at BT<4BU0D"(F0$$```(GXZT2^"````.L5O@@```"-=@"+1Q2+
+M5"0(B9`00```A=MT#(/L#%/H_/___X/$$(.\),``````=`F+A"3`````B3"X
+M`````('$G````%M>7UW#@^P8_W0D'.C\____@\0<P[@`````]D0D"0%T%XM$
+M)`QFQP``%(M$)!!FQP`V%;@!````PXM4)`2- at K0!``"#2`0!9L=`#``49L=`
+M#C85@(JT`0```H!@`7]FQT`(`P!FQT`*0`"X`0```,.05E.+3"0,BW0D$(M<
+M)!2+012)L"R```"#N;`!```!=#R+412)\"L%`````,'@`XF",(```(M1%(GP
+M*P4`````P>`#B8(T@```BU$4B?`#@80)``")@CB```#K*9"+013'@#"```#_
+M____BT$4QX`T@```_____XM!%,>`.(````$```"0@>/__X`!BT$4B9 at D@```
+M6U[#B?964X/L!(MT)!"[,@```(M6%(M"+*@$=0B+0 at BH`G0^D(/L#&H!Z/S_
+M__^#Q!!+=1R+1A2+5"04B5`$BT84QT`H"@```+@`````ZQ>0BU84BT(LJ`1U
+MRHM""*@"=<.X`0```(/$!%M>PXM4)`2+0A3'@"R`````````BTH4BX$$@```
+M#0``$``E__]?_XF!!(```(M"%,>`)(```/__``##5E.+="0,BTPD$&:#>1(`
+M=$>+5A2+@@2````E__]__PT``"``B8($@```BU84#[=!$(F"*(```(M6%`^W
+M01*)@DB```"+5A2+013!X`.)@C2```#K%XUV`(M6%(N"!(```"7__U__B8($
+M@```BU84BP&)@BR```"+7A2+ at R2````E``"`_P^W40@)PF:#>1@`=!$/MT$8
+M@\`$P>`0)0``?P`)PHF3)(```&:#OJ@!```#=B4/MT$:J`=T'8M.%(N1&(``
+M`(#F^,'@""4`!P``"<*)D1B```"06U[#D(M$)`2+0!2+@`A```"%P`^5P`^V
+MP,.)]E.+7"0,BTPD"(M!%(M0'(/Z_W40QP,`````N`````#K.8UV`(G0(X&L
+M"```);K8!0&)`_?"(`!P`'0'#0```$")`_;"!70#@PL!]\+`!0``=`.#"T"X
+M`0```%O#BT0D!(N`K`@``,.05U93BW0D$(M<)!2)\8N^K`@``(7_>0V+1A3'
+M0"0`````C78`B=J!XKK8!0'VPP%T`X/*!?;#0'0S@[FP"````'0#@\I`@[FT
+M"````'0#@,X!@[FX"````'0#@,J`@[F\"````'0&@,X$C78`BT84B5`@B9FL
+M"```A=MY#(M&%,=`)`$```")]HGX6UY?PY"0N$````##B?:+1"0(9H/X/W<?
+M#[?`P>`%BU0D!`-"%(N`')```+H!````J0"```!U!;H`````B=##C78`BTPD
+M!(M$)`BZ`````&:#^#\/AX$````/M\#!X`6)P at -1%,>"`)````````")P at -1
+M%,>"!)````````")P at -1%,>"")````````")P at -1%,>"#)````````")P at -1
+M%,>"$)````````")P at -1%,>"%)````````")P at -1%,>"&)`````````#013'
+M@!R0````````N@$```")T,.05U93BWPD$(M4)!B+="04N`````!F at _X_=VJ%
+MTG0X#[9:!<'C"`^V0 at 0)PP^V2@/!X1@/MD("P>`0"<$/MD(!P>`("<$/M@()
+MP='IB=C!X!\)P='KZPJ[`````+D`````#[?&P>`%B<(#5Q2)BAB0```#1Q2)
+MVH#.@(F0')```+@!````6UY?PU575E.#[!"+="0LBT0D*&:)1"0. at WPD-`$9
+MR??1@>&JJJJJN`````!F at WPD#C\/AU`!``"X`````(`^``^%0@$``+@`````
+M9H-^`@0/AC(!``#'!"0`````9H-^`@5V$&:#?@(.&=*#XOZ#P at .)%"0/MFX$
+M#[9&!<'@"`G%#[9&!L'@$`G%#[9&!\'@&`G%,<T/MD8)P>`(#[96"`G",<J!
+MXO__``")5"0(#[9^"@^V1 at O!X`@)QP^V1 at S!X!`)QP^V1 at W!X!@)QS'/#[9&
+M#\'@"`^V5 at X)PC'*@>+__P``B50D!`^V7A`/MD81P>`("<,/MD82P>`0"<,/
+MMD83P>`8"<,QRV:#?@(-=P:!X_\````/MTPD#HG(P>`%B<*+="0D`U84B:H`
+MD```B<(#5A2+="0(B;($D```B<*+="0D`U84B;H(D```B<(#5A2+="0$B;(,
+MD```B<*+="0D`U84B9H0D````T84BQ0DB9`4D```_W0D,%%6Z/S___^#Q`R-
+M=@"#Q!!;7E]=PX/L$&H&BT0D&`6C"```4/]T)"#H_/___X/$',.#[!!J!O]T
+M)!R+1"0<!:,(``!0Z/S___^X`0```(/$',.-=@!3@^P(BUPD$(M3%(M$)!2+
+MA((`8```:@)J`V@`;```4^C\____@\00N@````"%P'05BT,4BY``:```BT0D
+M&&:)$+H!````B="#Q`A;PXUV`%.+7"00BTPD"+H,````BT0D#&8Y@=0!``!T
+M&`^W at 0((``#!Z`>#X`&#^`$9TH/B^(/""X7;=`*)$[@`````6\.X`0```,.)
+M]HM$)`2`N`P(````#Y7`#[;`PXGV4X/L$(M<)!AJ`%/H_/___X/$#(7`#Y3`
+M#[;`4&H`4^C\____@\086\.-=@!3BT0D"(M8%(M,)`S1X;H#````T^+WTHN#
+M%$```"'"N`(```#3X`G"B9,40```N`$```!;PXUV`%.+1"0(BU at 4BTPD#-'A
+MN`,```#3X/?0BY,40```(=")@Q1```"X`0```%O#4XM,)`R+1"0(BU at 4BY,8
+M0```N/[____3P"'"BT0D$(/@`=/@"<*)DQA```"X`0```%O#D(M,)`BX____
+M_X/Y!7<5BT0D!(M`%(N`'$```(/@+]/H@^`!PU93@^P$BW0D$(M,)!2+1A2+
+MF!1```")RL'B#-'AN`,```#3X`G0#0"``0#WT"'#"=.`SX"#?"08`'0&@<L`
+M``$`BT84B9 at 40```@^P(BX:L"```#0````%05NC\____@\046U[#C78`4XM<
+M)`B+3"0,BT,4BY`00```A<ET"H/Y!'0-ZQ.-=@"#XI_K$8UV`(/BWX/*0.L&
+M@\H@@^*_BT,4B9`00```6\.-=@"+1"0$BT`4BX`$@```P>@7@^`!@_@!&<"#
+MP`+#BTPD!(M4)`B+012+@`2```"I``"``'0(@_H"=0C#B?:#^@%T#HM1%`T`
+M`(``B8($@```PU93@^P(BW0D%(M<)!QJ!O]T)!R-AL@(``!0Z/S___^+3A0/
+MMI;("```#[:&R0@``,'@"`G"#[:&R@@``,'@$`G"#[:&RP@``,'@&`G"B9$(
+M@```@\00BTX4#[:&S0@``,'@"`^VELP(```)PHG8)?\_``#!X!`)PHF1#(``
+M`&:%VW05@^P$:@!J`%;H_/___X/$$.L/C78`@^P,5NC\____@\00@\0$6U[#
+MB?93BT0D"(M(%(N!<(```(G"N`````"+B6R```"[``````G("=I;PXGVBT0D
+M!(M`%(N`;(```,.)]HM$)`2+4!2+ at B2````-`````8F")(```,.-=@"+5"0$
+MBT(4BX!DF```B<'!Z1.!X?\!``")R,'H"(7`=`:!\0#^__^+4A2+ at G"```"+
+MDFR````QT#'(PY"+1"0$#[>0J`$``(M`%(N`($```"7_````.<(/E,`/MM")
+MT,.+3"0$BT0D"(M1%(N2F(````$0BU$4BY*4@````5`$BU$4BY*<@````5`,
+MBU$4BY*0@````5`(BU$4BY*@@````5`0PXM4)`2+0A3'0"0`````BXJL"```
+M@,U`B8JL"```BT(4B4@@BT(4QT`D`0```,.)]E=64XM\)!"+="04B?N#_ at AV
+M%H/L"&C__P``5^C\____@\00.?!S$I#'@X@)``#_____N`````#K(X/L"%97
+MZ/S___^+5Q2)@A"```"#Q!")MX@)``"X`0```(GV6UY?PX/L%(M4)!B+0A2+
+M@!"````E__\``%!2Z/S___^#Q!S#55=64X/L%(ML)"AH_Q\``%7H_/___X/$
+M$#M$)"1S$<>%C`D``/____^X`````.L\BW44BYX4@```@>,`X/__@^P(_W0D
+M+%7H_/___R7_'P``"<.)GA2```"#Q!"+1"0DB86,"0``N`$```"0@\0,6UY?
+M7<.#[!2+5"08BT(4BX`4@```)?\?``!04NC\____@\0<PU575E.#[!2+;"0H
+M:/\?``!5Z/S___^#Q!`[1"0D<Q''A9`)``#_____N`````#K0(MU%(N>%(``
+M`('C__\`X(/L"/]T)"Q5Z/S____!X!`E``#_'PG#B9X4@```@\00BT0D)(F%
+MD`D``+@!````B?:#Q`Q;7E]=PX/L%(M4)!B+0A2+@!2````E``#_'\'H$%!2
+MZ/S___^#Q!S#D+@`````PXGVPXUV`,.-=@"#[`R+1"04BU0D&(/X`74, at _H!
+M&<#WT(/@#>L2_W0D'%)0_W0D'.C\____@\00@\0,PXGV@^P,BT0D$(M,)!2+
+M5"0<@_D+=1R#X@:)D,@!``"+0!2)D&B```"X`0```.L9C78`@^P,_W0D+%+_
+M="0L45#H_/___X/$((/$#,.)]H/L%/]T)"S_="0L_W0D+/]T)"S_="0L_W0D
+M+.C\____@\0LPU.+7"0(BTPD$(M3%(N"!(```"7__W__#0``!`")@@2```"#
+M?"0,`'01BU,4#[?!#0```P")@@1```!;PU93@^P$BW0D$(-\)!0`=&2+1A3'
+M@`1`````````@^P,:-`'``#H_/___[L*````@\00B?:+1A2+@!!```"I```!
+M`'0B@^P,:,@```#H_/___XM&%,>`!$````````"#Q!!+==#K!H7;=0J)]K@`
+M````ZQJ0BU84BX($@```)?__>_^)@@2```"X`0```(/$!%M>PY"+3"0$BU$4
+MBX($@```)?__?_\-```$`(F"!(```(-\)`@`=`V+013'@`1```````$`PXGV
+M5U93BU0D$(M<)!2+3"08BT0D'(G6OP$```"#^P)T)8/[`G<(@_L!=`KK.9"#
+M^P-T).LQ#[?`4%%2Z+[^__^#Q`SK*9"#[`A14NCJ_O__B<>#Q!#K%U%2Z'#_
+M__^#Q`CK"XUV`+@`````ZPF0B9[$"```B?A;7E_#BT0D!(N`Q`@``,.0N```
+M``##B?:+1"0$BU`4BX($@```)?__;_^)@@2```"X`0```,.)]HM$)`2+4!2+
+M@@2````E__]__PT``!``B8($@```N`$```##D%.#[`B+1"04 at _@!=`^[````
+M`(/X`G05ZPN-=@"[`````.L)D+@`````ZQ.0@^P(4_]T)!SH_/___XG8@\00
+M@\0(6\.0BT0D!(M`%(M`#,.0BT0D!(M0%(M$)`B)0 at S#D(M$)`2+0!3'0`@$
+M````PY!64X/L!(MT)!"+1A3'0`@@````NP````"+1A2+0`BH!'4*N`$```#K
+M'HUV`(/L#&H*Z/S___^#Q!!#@?OG`P``?M:X`````(/$!%M>PXUV`(M$)`2+
+M4!2+ at FB```"#X+^)@FB```##D(M$)`2+4!2+ at FB```"#R$")@FB```##D(M,
+M)`2+412+1"0(B8)0@```BU$4BT0D#(F"5(```,.04XM4)`B+3"0,N`````"#
+M^3]W0H/Y'W8 at BU(4BYI4@```@^D at N/[____3P"'8B8)4@```ZQN-=@"+4A2+
+MFE"```"X_O___]/`(=B)@E"```"X`0```%O#D%.+5"0(BTPD#+@`````@_D_
+M=T*#^1]V((M2%(N:5(```(/I(+@!````T^`)V(F"5(```.L;C78`BU(4BYI0
+M@```N`$```#3X`G8B8)0@```N`$```!;PY"+1"0$BT`4BX!,@```PXGVBU0D
+M"/;&`G0&@.;]@\H at BT0D!(M`%(F03(```,.-=@"+5"0,BTPD",=!"`````")
+MT"7_#P``B4$,N``````Y40QU(?9$)!`@=`>!20P`(```QT$4`````,=!$```
+M``"X`0```,.-=@!75E.+?"00BW0D%(GSBT0D'+H/````]D84`0^$!P$``/9`
+M%`%U%8M'%(M`#+H/````.T0D&`^$[````&:+0Q`E_P\``&:)1B"+2Q2!X0"`
+M_P_!Z0^+1Q2+@&R```")PL'J"H'B__\``(G0)?\?```YR',1C8(`X/__)?__
+M```)P>L$B?8)T8G()?]_``!FB48BQD8D`(M#%*@"=3BH!'0(QD8D`>LNB?;V
+M0Q00=`:`3B0(ZR#V0Q0(=`:`3B0$ZQ2`3B0"BT,4)>````#!Z`6(1B6)]HM#
+M$"4``/@'P>@3B$8FBT,4]L0!=`XE`'X``,'H"8A&)^L%D,9&)_^+0Q`E`(`'
+M`,'H#XA&*(M#$,'H#H/@`8A&*8M#$,'H#(/@`8A&*KH`````B=!;7E_#D)"0
+M55=64X/L#(M\)""+;"0LB7PD"+H,````BT0D*/9``P$/A/(%``"#?"0D!G0A
+M at WPD)`9W"8-\)"0!=PGK$8-\)"0(=`JZ#````.G*!0``BT<4BX`00```B<.#
+MXV"#[`C_="0P5^C\____@\00N@,```"%P`^$GP4``(M/%(MT)`@/MI:C"```
+M#[:&I`@``,'@"`G"#[:&I0@``,'@$`G"#[:&I@@``,'@&`G"B9$`@```@WPD
+M)`$/A)T```"#?"0D`7)8 at WPD)`9T$(-\)"0(#X3"````Z?D```"+3Q2+1"0(
+M#[:0J`@``,'B"`^V@*<(```)T`T``%$`B8$$@```BT<4QT`H`````(M'%,>`
+M$$```$`0``#IN````(M/%(MT)`@/MI:H"```P>((#[:&IP@```G0#0``4@")
+M at 02```"+1Q3'0"@!````BT<4QX`00```)!```.MZBT\4BT0D"`^VD*@(``#!
+MX@@/MH"G"```"=`-```4`(F!!(```(M'%,=`*`````"+1Q3'@!!````D$```
+MZSR+3Q2+="0(#[:6J`@``,'B"`^VAJ<(```)T`T``!``B8$$@```BT<4QT`H
+M`````(M'%,>`$$```$`0``"+5Q2+ at A!````)V(F"$$```(M/%(M$)`@/MI#(
+M"```#[:`R0@``,'@"`G"BUPD"`^V@\H(``#!X!`)P@^V@\L(``#!X!@)PHF1
+M"(```(M/%`^VD\T(``#!X@@/MH/,"```"=")@0R```"+1Q3'``````"+1Q3'
+M0`0`````BT<4QT`,`````(M'%(M0',=`(`````"+1Q3'0"0`````QX.L"```
+M`````(M'%(M0+,=`,`4```"+1Q3'0#0%````BT<4QT!$"````(M'%,=`2`@`
+M``"+1Q3'0%``````BT<4QT!,`````(M'%,>`#$````````"+1Q3'0$``````
+MBT<4QX`8@`````<``(M'%,>`2(````````"#[`AJ`%?H_/___XM'%,>`4(``
+M``````"#Q!"+1Q3'@%2`````````BT<4QX!8@````````(M'%,>`7(``````
+M``"+1Q3'@&"````!````BT<4QX!D@````0```(M'%,>`:(````````"+1Q3'
+M@"B`````````BT<4QX`L@````````(M'%,>`;(````````"+1Q3'@#"```#_
+M____BT<4QX`T@```_____XM'%,>`.(````$```"Y`````+X`(```D(L<SH7M
+M=`V- at P"`__\]_P\``'8*BU<4BT3.!(D$&D&!^:8```!VV8/L"/]T)#!7Z/S_
+M__^#Q!"Z`P```(7`#X0H`@``BT\4BY$HF```,/:+="0(#[:&"0@``,'@"`G"
+MB9$HF```BU\4#[:6"@@``(G0P>`8P>(0"=`/MHX+"```B<K!X@@)T`G(B8,T
+MF```BT\4BY%$F```@>)_P/__9HN&!`@``&;1Z"6`/P``"<*)D428``"+3Q2+
+MD4B8``"!XO\/_/\/MX8$"```P>`*)0#P`P`)PHF12)@``(M/%(N19)@``('B
+M_P_X_P^VA@@(``#!X`PE`/`'``G"B9%DF```BT\4BY$0F0``@^+\#[>&!`@`
+M`(/@`PG"B9$0F0``@^P(_W0D,%?HQ`P``(/$$+H#````A<`/A#`!``"+1Q3'
+M@!R8```!````@^P,:.@#``#H_/___XM7%(N"8)@``(/(`8F"8)@``(/$$&H`
+M:@%H8)@``%?H_/___X/$"/]T)#!7Z/S___^#Q!"[`````(7`=1.+1"0H9H-(
+M`@*Z`P```.G&````@^P(4U?H_/___X/$$$.#^P)^[8M4)`B`N at P(````=`R#
+M[`Q7Z/S___^#Q!"+5Q2+ at B2````E__]__HF")(```(M<)`B#NX@)``#_=!*#
+M[`C_LX@)``!7Z/S___^#Q!"+="0(@[Z,"0``_W02@^P(_[:,"0``5^C\____
+M@\00BT0D"(.XD`D``/]T$H/L"/^PD`D``%?H_/___X/$$(._R`$```!T#XM7
+M%(N'R`$``(F":(```(M4)"2)E[`!``"X`0```.L0BUPD,(,[`'0"B1.X````
+M`(/$#%M>7UW#BTPD!(M!%(N`!(```"7__P``BY&P`0``@_H!=#.#^@%R'H/Z
+M!G0)@_H(=#/#C78`BU$4#0``40")@@2```##D(M1%`T``%(`B8($@```PY"+
+M410-```4`(F"!(```,.+410-```0`(F"!(```,.)]H/L$&H*:@C_="0<Z#@#
+M``"#Q!S#4X/L"(M<)!!J`&H!:@)3Z/S___^#Q!"Z`````(7`=%"#[`1H($X`
+M`&H/4^@$`P``@\00N@````"%P'0T@^P,:.@#``#H_/___X/$#&@@3@``:A]3
+MZ-L"``#'!"0T"```Z/S___^Z`0```(/$$(UV`(G0@\0(6\.05E.#[`2+="00
+MBUPD%&H`:@%J`E;H_/___X/$$+H`````A<`/A)<```"+1A2Z`````(7;=`CV
+M0P(0=`*R`8F0!)@``(/L!&@@3@``:@]6Z&D"``"#Q!"Z`````(7`=&&#[`QH
+MZ`,``.C\____@\0,:"!.``!J'U;H0`(``(/$$+H`````A<!T.(/L#&@T"```
+MZ/S___]J`&H!:@)6Z/S___^#Q""Z`````(7`=!.#[`1J"FH`5N@"`@``B<*#
+MQ!"0B="#Q`1;7L-55U93@^P8BVPD+(M5%(N":(```(/(8(F":(```(M5%(NZ
+M)(```(GX)?__?_^)@B2```!HH`\``.C\____BU44BX((F```#0````B)@@B8
+M``#'!"0*````Z/S___^#Q`C_="0L5>@^"0``@\00N@````"%P`^$;@$``(/L
+M#&CH`P``Z/S___^+512+@@B8```E____]XF"")@``(/$!(M%%(N86)@``(NP
+M7)@``(N0:)@``(E4)!2)VH'*``#\`XF06)@``(M5%(GP)7\`P/\-@,`_`(F"
+M7)@``(M5%(M$)!0E'P#^_PV`$0``B8)HF```:A3H_/___XM5%(N"")@```T`
+M```(B8((F```QP0D"@```.C\____BT44QX#4F```(0```(M5%(N"")@``"7_
+M___WB8((F```QP0DZ`,``.C\____BU44BX)@F```@\@!B8)@F```@\00:@!J
+M`6A at F```5>C\____@\0(BT44B9A8F```BT44B;!<F```BT44BU0D$(F0:)@`
+M`/]T)"Q5Z/S___^#Q!"%P'4L@^P,:(@3``#H_/___X/$"/]T)"Q5Z/S___^#
+MQ!"%P'4+BT0D)&:#2`("B?:+112+D&B```"#XI^)D&B```"+112)N"2```"Z
+M`0```(G0@\0,6UY?7<.)]E=64XM\)!"+="04B?"%]G4%N/____^)PXM'%(FP
+M`$```(/L#/]T)"3H_/___X/F#X/C#U93:`!```!7Z/S___^)PH/$(/?&!```
+M`'4*BT<4QT`4`````(G06UY?PXUV`%93@^P$BTPD%(I$)!B(1"0#NP````"Z
+M"@````^VP(UP`8UV`(U$$@,Z1"0#=1J`/!$_=`P/M at 01Z9X```"-=@"[`0``
+M`.MQD(U$$@,/ML`YQG51A=)^38`\$3]T/X!\"O\_=#@/MAP1#[9,"O\IRXT$
+MFXT$@(T4Q0`````IPHV<$N<#``"XTTUB$/?CB=#!Z`:-'`@/ML/K0HUV`+L!
+M````ZQ60 at _L!=0^`/!$_=`D/M at 01ZR:-=@!*#XEE____N@````"`/!$_=`8/
+MM at 01ZPM"@_H*?NZX`0```(/$!%M>PXUV`%575E.#[`2+7"0<BVPD)(I4)""_
+M_____[[_____N0````")]H`\"S]T*C at 4"W1/.!0+<P*)SC at 4"W89B<^#_O]U
+M&HU$"0.(10`/MD0+"^F2````D$&#^0I^RNL%@_D*?BNX/P```(/^_W1Z at _D*
+M?AR-1#8#B$4`#[9$,POK9XU$"0.(10`/MD0+"^M9C40^`XA%``^VT@^V##,I
+MRHT4DHT4DHT4DHTLU0`````/M at 0[*<B)P8GHF??YB<4/MD0["P^V3#,+*<B)
+MZ@^OT('"YP,``+C336(0]^*)T,'H!@)$,PL/ML"#Q`1;7E]=PXUV`(M4)`B#
+M^CQV!;H\````BT0D!&:)D,P!``"X`0```,.055=64X/L$(ML)"2+5"0HBWPD
+M+(EL)`1FBX4&"```9L'H!(/@!XA'#XJ%!@@``(/@!XA'$&:+`BTR%```N0``
+M``!F/98`#X=,`@``NP````"+3"0$9@^VA`L."```9CF%U`$``'0&0X/[`W;D
+MN0````"#^P0/A!T"```/MPJ!Z3(4``"X9V9F9O?IP?H"B<C!^!^)T2G!@_D,
+M@]'_N*NJJJKWX8G1T>F-!,T`````*<B--(&+1"0$C;0&$@@``(I$'AF(1PZ*
+M1A8Z1!X9=@2*1!X9B$<)BD87.D0>&78$BD0>&8A'"(I&&#I$'AEV!(I$'AF(
+M1P>-1"0/4`^V1!X94%95Z.G]__^(PXU$)!Y0#[9'"5!65>C6_?__B$0D(X/$
+M((U$)`U0#[9'"%!65>B^_?__B$0D$HU$)!Q0#[9'!U!65>BI_?__B,*#Q""#
+MO=`!````#X3T````BX70`0``9HN,`$HE```/ME0D#P^WP8/``SG"?0?&1"0/
+M`^L$*$PD#P^V1"0/4%95Z'[\__^(1PZ-1"074`^V1PY05E7H3OW__XC#BD0D
+M*X/$'#I$)`YV!(I$)`Z(1"0.#[;`4%95Z$C\__^(1PF-1"074`^V1PE05E7H
+M&/W__XA$)!^*1"0K@\0<.D0D#78$BD0D#8A$)`T/ML!05E7H$/S__XA'"(U$
+M)!=0#[9'"%!65>C at _/__B$0D'HI$)"N#Q!PZ1"0,=@2*1"0,B$0D#`^VP%!6
+M5>C8^___B$<'C40D%U`/MD<'4%95Z*C\__^(PH/$'`^V1"0/T>!FB87.`0``
+MBD<.B$<*B$<+B$<,B$<-B- at HT(@'B- at J1"0"B$<!B- at J1"0#B$<"QD<&`,9'
+M!0#&1P0`QD<#`+D!````B<B#Q!!;7E]=PXUV`%=64X/L=(N\)(0```!J1&A@
+M)0``C40D#%#H_/___X/$#&H1:#@E``"-7"1<4^C\____4_^T))@```!7Z!S]
+M__^#Q!RZ`````(7`#X1@`@``BD0D7TBZ`````#P$#X=.`@``BD0D8$BZ````
+M`#P$#X<\`@``O@````"-=@`/M]Z#[`AJ!0^V1!Q<4.C\____B$0<8(/$$$9F
+M at _X&=M^^!P```(GV#[?>@^P(:@8/MD0<7%#H_/___XA$'&"#Q!!&9H/^#G;?
+M#[9$)%'!X`4EX`````^V5"10@^(?"=`)!"0/ME0D4\'B!X'B@`````^V1"12
+MP>`"@^!\"<**1"11P.@#@^`#"<()5"0$#[94)%3!X at 2!XO````"*1"13T.B#
+MX`\)P at E4)`@/ME0D5L'B!H'BP`````^V1"15T>"#X#X)PHI$)%3`Z`2#X`$)
+MP at E4)`P/ME0D5\'B`X'B^````(I$)%;`Z`*#X`<)P at E4)!`/ME0D6<'B!X'B
+M@`````^V1"18T>"#X'X)PHI$)%?`Z`6#X`$)P at E4)!0/ME0D6L'B!8'BX```
+M`(I$)%G0Z(/@'PG""50D&`^V5"1;P>(#@>+X````BD0D6L#H`X/@!PG""50D
+M'`^V5"1<T>*#XGZ*1"1;P.@%@^`!"<()5"0@#[9$)%W!X`4EX`````E$)"0/
+MME0D7L'B`X'B^````(I$)%W`Z`.#X`<)P at E4)"B*1"1>P.@%@^`!"40D+(/L
+M"&H##[9$)&M0Z/S____!X`<E@`````E$)#"#Q`AJ`P^V1"1K4.C\____T>B#
+MX`,)1"0T@\0(:@,/MD0D;%#H_/___\'@`H/@'`E$)#2^`````(/$$(GVBT<4
+M#[?6BQ24B9"<F```1F:#_@]VZHM'%`^WUHL4E(F0U)@``+H!````B?:)T(/$
+M<%M>7\.-=@!75E.+7"00BWPD%(/L"%=3Z/S___^)QH/$$+@`````A?9T3H/L
+M"&H%#[</@>D`%```N&=F9F;WZ8G0P?@"P?D?*<A0Z/S____1X(/(08M3%(F"
+MG)@``(/$$(M#%,>`P)@```````")L_P'``"X`0```%M>7\.-=@"+1"0$BT`4
+MBX!DF```P>@3)?\!``#VQ`%T!34`_O__F,.-=@!64X/L!(MT)!"+1A2+D&"8
+M``"#R@*)D&"8``!J`&H":&"8``!6Z/S___^#Q!"Z`````(7`=#N[`````)"#
+M[`QHZ`,``.C\____5NC\____F(/$%$.#^Q1_!X/XN'_>ZPRZ`````(/XN'\'
+MB?:Z`0```(G0@\0$6U[#C78`N`````##D)!3@^P(BUPD$(M4)!2X`````(/Z
+M`G\>@^P$_W0D'(T$4HT$@(V$@]`(``!04^C\____@\00@\0(6\.-=@!3@^P(
+MBUPD$(M4)!2X`````(/Z`G\>@^P$C012C02`C82#T`@``%#_="0 at 4^C\____
+M@\00@\0(6\.-=@!55U93@^P,BVPD((MT)"2)ZH/^`G06 at _X"=PF#_@%T'.LB
+MB?:#_ at -T"^L9D+\"````ZQF0OP$```#K$9"_`````.L)D+C_____ZVB0C01_
+MC02`C9R"T`@``+C_____ at WL$`'5/@^P(:CQ3Z/S___^)<P2#Q!"#?"0H`'4D
+MQT,,"P```,=#%`(```#'0QC_____9L=#(`H`9L=#(@H`ZQ*0@^P$_W0D+%=5
+MZ/S___^#Q!")^(/$#%M>7UW#D%.+3"0,BU0D"+L`````@_D"=TF-!$F-!("-
+MA(+0"```NP````"#>`0`=#''0`0`````N/[____3P"&"L`@``"&"M`@``"&"
+MN`@``"&"O`@``"&"P`@``+L!````B=A;PU575E.+="04BTPD&(GSBY;\!P``
+MN`````"#^0(/APX"``"-!$F-!("-O(;0"```N`````"#?P0`#X3R`0``N`$`
+M``"#?P0!#X7C`0``]D("$'1XBT84QX`0@```X`$``(M&%,>`%(`````(``B+
+M1A3'@""```#/C]T!BU84BT<4C01`C02`P>`0C8````\`#>`!``")@D"```"+
+M1A3'@$2```#``ZX%BU84BX)$F```@^"`@\@XB8)$F```BT84QX`$F```(R``
+M;^MZBT84QX`0@```:`$``(M&%,>`%(`````$``2+1A3'@""```"GC]T!BVX4
+MBU<4C022C01"C02"C03%,`(``,'@"PTP`@``B85`@```BT84QX!$@```F`/7
+M!(M6%(N"1)@``(/@@(/('(F"1)@``(M&%,>`!)@``"`0`&^X#P```(-_&/]T
+M`XM'&(MV%(G"P>(4#[='(L'@!"7P````"<(/MT<@@^`/"<*!R@`@"`")EAR`
+M``#V1PP!=`^X`0```-/@"8.P"```ZPVX_O___]/`(8.P"```]D<,`70/N`$`
+M``#3X`F#M`@``.L-N/[____3P"&#M`@``/9'#`)T#[@!````T^`)@[@(``#K
+M#;C^____T\`A@[@(``#V1PP$=`^X`0```-/@"8.\"```ZPVX_O___]/`(8.\
+M"```]D<,"'0/N`$```#3X`F#P`@``.L-N/[____3P"&#P`@``+@!````C78`
+M6UY?7<.-=@"+3"0$BT0D"(T$0(T$@+K_____@[R!U`@```%U!8M!%(L0B=##
+MC78`BU0D!(M$)`B+3"0,C01`C02`BX2"U`@``(/X`70. at _@!<AF#^`-W%.L*
+MB?:+0A2)".L1D(M"%(E(!.L(N`````##B?:X`0```,.)]E93@^P0BW0D'%;H
+M_/___XG#@\0()?___W]05NC\____BT84BY!D@```@\00 at WPD%`!T#;@E````
+M*=#1Z`'"ZQR#^@%V`TKK%(/L"%-6Z/S___^X`````(/$$.L;BT84B9!D@```
+M@^P(4U;H_/___[@!````@\00@\0$6U[#C78`BU0D!(M$)`B-!$"-!("+A(+4
+M"```@_@"=#J#^`)W"8/X`70,ZSJ)]H/X`W0/ZS&0BT(4QT`(`0```.LLBT(4
+MQT`(`@```(M"%,=`*`X```#K%HGVBT(4QT`H"@```.L(N`````##B?:X`0``
+M`,.)]HM,)`2+1"0(C01`C02`N@````"#O('4"````743BT$4BT`4)0!X``")
+MPL'J"XUV`(G0PY!64X/L!(MT)!"+1"04C01`C02`BX2&U`@``(/X`70'@_@"
+M=$WK7HM&%,=`"`@```"[`````(UV`(M&%(M`%/;$>'06@^P,:@KH_/___X/$
+M$$.!^^<#``!^WXM&%,=`"`````"!^^<#```/GL`/ML#K&&H`:@1J+%;H_/__
+M_X/$$.L'B?:X`````(/$!%M>PY"X`0```,.)]E=64XM4)""+?"0PBW0D.(M,
+M)!2-0OV[````#(/X`78%B=/!XQJ+1"08)?\/``"+5"0HP>(2"="+5"0<P>(,
+M@>(`\`,`"=`)V/?&`0```'0%#0````'WQA````!T!0T````@B<*#?"0T`'0&
+M@<H````"B5$(@___=!N)^,'@#24`X`<`B4$,B=`-````0(E!".L*B?;'00P`
+M````D/?&!````'03 at 4D(``!``(M$)$`E``#X_PE!#+@!````6UY?P[@`````
+MPXGV4XM,)!"+7"08BU0D#(-\)!0`=!2+0 at P)R(7;=0.`S!")0 at SK)XUV`(7;
+M=!"+1"0<BT`(B4((B4H,ZQ&0QT((`````(G(@,P0B4(,D,="%`````#'0A``
+M````N`$```!;PXUV`(M,)`B)RK@/````]D$4`0^$@````&:+010E_A\``&:)
+M02`/MT$29HE!(L9!)`"+01"H`74?J`)T!,9!)`'V0A`(=`2`220"]D(0!'0'
+M@$DD!(UV`(M"""4``#P`P>@2B$$EBT(4)0#@'P#!Z`V(02:+0A`E``\``,'H
+M"(A!)XM"$"7P````P>@$B$$HQD$J`+@`````PXGVPY"0D(/L#(M,)!"+013'
+M at -"8```6'```N@````"-=@"+013'@("8``````$`0H/Z!W[MBT$4BX``G```
+MP>@8B<+!Z at 2#X`_!X`0)T(/L"&H(4.C\____@\0<PY!55U93@^P8BVPD+&@4
+M&0``Z/S___^)PX/$$+X"````A<`/A"D$``")QX/L!&@`"```:,`E``!0Z/S_
+M__^+1"0TB4,,BT0D.(E#$(M$)#R)0Q1FB:N@`0``9L>#H@$`````9L>#S`$`
+M`#P`QX/0`0```````,>#W!@```````#'@]@8````````QX/X&```_____\>#
+M_!@``/_____'@P`9``#_____@\0(:@!3Z/S___^#Q!"^`P```(7`#X2/`P``
+M9H&[H`$``!OQ=2R+0Q3'@`"B````````BT,4QX!\F```&0```(/L#&CH`P``
+MZ/S___^#Q!")]HM'%(N`($```"7_````B<+!Z at 2)EZ0!``"#X`]FB8>H`0``
+M@^H"O at T```"#^@(/AR0#``"+1Q2+@!B8``!FB8>J`0``@^P,5^A'`P``@\00
+MO at X```"%P`^$^P(``(._I`$```-V$HM'%,>``)@```<```#K$(UV`(M'%,>`
+M`)@``$<```"#[`QHT`<``.C\____B3PDZ!;^__]FB8>L`0``#[?`)?````"#
+MQ!"^#0```(/X$`^%G@(``(/L!(U$)`Y0:,$```!7Z/S___^#Q!"^"````(7`
+M#X1[`@``O at 4```!F at 7PD"O\O#X9I`@``9HM$)`IFB8,`"```BT<4BX`00```
+M@^`8P>@#O at H```"#^`(/A4`"``"#[`2-1"0.4&H_5^C\____@\00O@@```"%
+MP`^$(`(``&:+1"0*9HF#`@@``+T`````O@````")]H/L!(U$)`Y0C8;`````
+M4%?H_/___X/$$(7`#X3@`0``#[=$)`HQQ4:!_C\#``!VT+X'````@?W__P``
+M#X7'`0``9L>#=@D```H`9L>#@`L```,`O@````"-!':-!(9FQX2#?@D```L`
+M1H/^"7;JO@````"ZP"T``&:+!')FB81SB`L``&:)A'.""P``C01VC02&C02#
+M9L>`,`P```L`9L>`E`L```L`1H/^`G;+@^P(C8,`"```4%?H_/___X/$$+X(
+M````A<`/A#L!``"#OZ0!```#=FMF@[L8"````'1ABT<4QX``F```!T```(/L
+M#&C0!P``Z/S___^)/"3H7OS__V:)AZX!``"+1Q3'@`"8```'````QP0DT`<`
+M`.C\____#[>'K@$``"7P````@\00O at T```"#^"`/A<D```#K"6;'@Q@(````
+M`(/L!(U$)`Y0:+\```!7Z/S___^#Q!"^"````(7`#X2;````9HM$)`IFB8,$
+M"```9HF'U`$``(/L#%?H]P$``(D\).C\____O0````"^`````(/$$(/L!(U$
+M)`Y0N!\````I\%!7Z/S___^#Q!"%P'0[#[=$)`H!Q68/MD0D"XB$<U at 6``!F
+MBT0D"HB$<UD6``!&@_X"=KV%[70*B?B!_?W_`@!U.[X)````ZQ*^"````.L+
+MC78`O@@```"-=@"%VW0,@^P,4^C\____@\00 at WPD,`!T!HM$)#"),+@`````
+M@\0,6UY?7<.)]H/L&/]T)!SH_/___X/$',-55U93@^PLBW0D0,=$)`@`@```
+MQT0D#""8``#'1"0055555<=$)!2JJJJJQT0D&&9F9F;'1"0<F9F9F;\`````
+MC6PD"(T$O0````"+'"B+5A2+%!J)%`2Y`````(G(P>`0B<()RHM&%(D4&(M&
+M%(L$&#G0=`>X`````.MA08'Y_P```'[7N0````"+5(P0BT84B108BT84BP08
+M.<)T"K@`````ZSB-=@!!@_D#?MR-!+T`````BTX4BQ0HBP0$B0011X/_`0^.
+M>?___X/L#&IDZ/S___^X`0```(/$$(/$+%M>7UW#C78`BU0D#(M,)!"+1"0(
+M]L0!=!-FQP(X$V;'`=07N`$```##C78`J8````!T(8M$)`1F@[@8"````'03
+M9L<""`EFQP&L"K@!````PXUV`+@`````PXGV5E.#[`2+="00C9ZT`0``9H.^
+MU`$```%U$X/L!(U$)`10:A!6Z/S___^#Q!#'0P0`````9H.^%@@```!T&\=#
+M!`$```!F@[X&"````'4*QT,$`P```(UV`&:#OA@(````=`2#2P0$9L=#$`@)
+M9L=#$JP*9L=###@39L=##M07@`L#@$L!@(!+`@%FQT,("@!FQT,*@`"X`0``
+M`(/$!%M>PU=64XM,)!"+="04BUPD&(G/BT$4B;`H@```BX&P`0``@_@!=`^#
+M^`%R)H/X!G0A at _@(=42+013'@"R```#__P``BT$4QX`P@```__\'`.LHBU$4
+MB?`K!0````#!X`.)@BR```"+412)\"L%`````,'@`XF",(```(M1%(U&`8._
+MV!@```!T"(GP`X?8&```B8(T@```@>/__X`!BT$4B9@@@```6UY?PU93@^P$
+MBW0D$+L`````B?:#[`AJ`E;H_/___X/$$(7`=!:#[`QJ"NC\____@\000X'[
+MYP,``'[8@?OG`P``#Y[`#[;`@\0$6U[#B?:+5"0$BT(4QX`H@````````(M*
+M%(N!!(````T```0`)?__S_^)@02```"+0A3'@""```#__P``PU93BW0D#(M<
+M)!!F at WL2`'0_BU84BX($@```#0``$`")@@2```"+5A0/MT,0B8(D@```BU84
+M#[=#$HF".(```(M6%(M#%,'@`XF",(```.L4BU84BX($@```)?__[_^)@@2`
+M``"+5A2+`XF"*(```(M.%(N!((```"4``(#_#[=3"`G"9H-[&`!T$0^W0QB#
+MP`3!X!`E``!_``G"B9$@@```BTX4BY$8@```,/8/MT,:P>`()0#_```)PHF1
+M&(```(M.%(N1!$```('B``#__XM#'(/H`\'@`R7__P``"<*)D01```!;7L.+
+M1"0$BT`4BX`(0```A<`/E<`/ML##B?:+3"0(BT0D!(M`%(N0P````(/Z_W4.
+MQP$`````N`````##B?:)T"6ZV`4!B0'WP@``"`!T!PT```!`B0'VP at 5T`X,)
+M`??"P`4``'0#@PE`]L(@=`:!"0```$"X`0```,.+1"0$BX!D%@``PY!75E.+
+M="00BUPD%(GQB[YD%@``A?]Y$8M&%,=`)`````"+1A2+0"20B=J!XKK8!0'V
+MPT!T,X.Y:!8```!T`X/*0(.Y;!8```!T`X#.`8.Y<!8```!T`X#*@(.Y=!8`
+M``!T!H#.!(UV`/;#`70#@\H']\,```!`=`:!R@``"`"+1A2)D*````")F606
+M``"%VWD+BT84QT`D`0```)")^%M>7\.0D+B`````PXGVBT0D"&:#^']W'P^W
+MP,'@!8M4)`0#0A2+@!R(``"Z`0```*D`@```=06Z`````(G0PXUV`(M,)`2+
+M1"0(N@````!F at _A_#X>!````#[?`P>`%B<(#413'@@"(````````B<(#413'
+M@@2(````````B<(#413'@@B(````````B<(#413'@@R(````````B<(#413'
+M at A"(````````B<(#413'@A2(````````B<(#413'@AB(`````````T$4QX`<
+MB````````+H!````B=##D%=64XM\)!"+5"08BW0D%+@`````9H/^?W=JA=)T
+M.`^V6 at 7!XP@/MD($"<,/MDH#P>$8#[9"`L'@$`G!#[9"`<'@"`G!#[8""<'1
+MZ8G8P>`?"<'1Z^L*NP````"Y``````^WQL'@!8G"`U<4B8H8B````T<4B=J`
+MSH")D!R(``"X`0```%M>7\-55U93@^P0BWPD+(M$)"AFB40D#H-\)#0!&<GW
+MT8'AJJJJJK@`````9H-\)`Y_#X=\`0``#[8'@_@!=!2#^`%_!X7`=!3K39"#
+M^`5T/.M%D,<$)`4```#K1[@`````9H-_`@0/AD<!``#'!"0`````9H-_`@5V
+M*6:#?P(.&=*#XOZ#P at .)%"3K%\<$)`<```#K#HGVN`````#I$@$``(GV#[9O
+M!`^V1P7!X`@)Q0^V1P;!X!`)Q0^V1P?!X!@)Q3'-#[9'"<'@"`^V5P@)PC'*
+M@>+__P``B50D"`^V=PH/MD<+P>`("<8/MD<,P>`0"<8/MD<-P>`8"<8QS@^V
+M1P_!X`@/ME<."<(QRH'B__\``(E4)`0/ME\0#[9'$<'@"`G##[9'$L'@$`G#
+M#[9'$\'@&`G#,<MF at W\"#7<&@>/_````#[=,)`Z)R,'@!8G"BWPD)`-7%(FJ
+M`(@``(G"`U<4BWPD"(FZ!(@``(G"BWPD)`-7%(FR"(@``(G"`U<4BW0D!(FR
+M#(@``(G"`U<4B9H0B````T<4BSPDB;@4B```_W0D,%'_="0LZ/S___^#Q`R#
+MQ!!;7E]=PX/L$&H&BT0D&`58%@``4/]T)"#H_/___X/$',.#[!!J!O]T)!R+
+M1"0<!5 at 6``!0Z/S___^X`0```(/$',.-=@!3@^P(BUPD$(M3%(M$)!2)@@!@
+M``"+0Q3'@`A@```!````:@)J`V@,8```4^C\____@\00N@````"%P'05BT,4
+MBY`$8```BT0D&&:)$+H!````B="#Q`A;PXUV`%.+7"00BTPD"+H,````BT0D
+M#&8Y@=0!``!T&`^W at 0((``#!Z`>#X`&#^`$9TH/B^(/""X7;=`*)$[@`````
+M6\.+5"0$N`````!F@[H6"````'0.9H.Z!@@```$9P(/@`D!F@[H8"````'0#
+M@\@$PY!3@^P(BUPD$&:#NPH(````=$:#[`2-1"0*4&H/4^C\____@\00N@``
+M``"%P'16#[=4)`:)T(/@','X`HF#!!D``(/B`M'ZB9,(&0``QX,0&0```0``
+M`.L>QX,(&0```````,>#!!D```````#'@Q`9````````9H.["@@````/E<`/
+MMM")T(/$"%O#D%.#[!"+7"08:@!3Z/S___^#Q`R%P`^4P`^VP%!J`%/H_/__
+M_X/$"/^S!!D``%/H_/___XM3%(N"`)@``(#DWXF"`)@``(/$"/^S!!D``%/H
+M_/___XF##!D``(/$##N#"!D```^5P`^VP%#_LP09``!3Z/S___^#Q!A;PY!3
+MBT0D"(M8%(N3%$```(M,)`S1X;@#````T^`)PHF3%$```+@!````6\.)]E.+
+M1"0(BU at 4BY,40```BTPD#-'AN`,```#3X/?0(<*)DQ1```"X`0```%O#4XM,
+M)`R+1"0(BU at 4BY,80```N/[____3P"'"BT0D$(/@`=/@"<*)DQA```"X`0``
+M`%O#D(M,)`BX_____X/Y!7<5BT0D!(M`%(N`'$```(/@+]/H@^`!PX/L#(M,
+M)!"+012+D!1```"!XOQ__O^`SH"#?"08`'0&@<H```$`BT$4B9`40```@^P(
+MBX%D%@``#0````%04>C\____@\0<PXM$)`2+2!2+ at 1!````EG__Q_XM4)`B#
+MX@<+!)7 at +0``B8$00```PY!64X/L"(M<)!2+="0<:@;_="0<C8->%@``4.C\
+M____BTL4#[:37A8```^V at U\6``#!X`@)P@^V at V`6``#!X!`)P@^V at V$6``#!
+MX!@)PHF1"(```(M+%`^V at V,6``#!X`@/MI-B%@``"<*!YO\_``#!YA`)\HF1
+M#(```(/$%%M>PU.+1"0(BT at 4BX%0@```B<*X`````(N)3(```+L`````"<@)
+MVEO#B?:+1"0$BT`4BX!,@```PXGVBT0D!(M0%(N"((````T````!B8(@@```
+MPXUV`(M4)`2+0A2+@&28``")P<'I$X'A_P$``(G(P>@(A<!T!H'Q`/[__XM2
+M%(N"4(```(N23(```#'0,<C#D%.+5"0(BT(4BX`@0```)?\```")P8/A#[L`
+M````P>@$.8*D`0``=0QF.8JH`0``=0.S`9")V%O#BTPD!(M$)`B+412+DI"`
+M```!$(M1%(N2C(````%0!(M1%(N2E(````%0#(M1%(N2B(````%0"(M1%(N2
+MF(````%0$,.#[!2+1"08BU`4QX)4F0```0```(N09!8``(#.0%)0Z/S___^#
+MQ!S#5U93BWPD$(MT)!2)^X/^"'86@^P(:/__``!7Z/S___^#Q!`Y\',.D(FS
+M^!@``+@`````ZR.#[`A65^C\____BU<4B8)P$```@\00B;?X&```N`$```")
+M]EM>7\.#[!2+5"08BT(4BX!P$```)?__``!04NC\____@\0<PU575E.#[!2+
+M;"0H:/\?``!5Z/S___^#Q!`[1"0D<Q''A?P8``#_____N`````#K/(MU%(N>
+M%(```('C`.#__X/L"/]T)"Q5Z/S___\E_Q\```G#B9X4@```@\00BT0D)(F%
+M_!@``+@!````D(/$#%M>7UW#@^P4BU0D&(M"%(N`%(```"7_'P``4%+H_/__
+M_X/$',-55U93@^P4BVPD*&C_'P``5>C\____@\00.T0D)',1QX4`&0``____
+M_[@`````ZT"+=12+GA2```"!X___`."#[`C_="0L5>C\____P>`0)0``_Q\)
+MPXF>%(```(/$$(M$)"2)A0`9``"X`0```(GV@\0,6UY?7<.#[!2+5"08BT(4
+MBX`4@```)0``_Q_!Z!!04NC\____@\0<PY"X`````,.)]L.-=@##C78`BT0D
+M!(M`%(N`')P``"7_````PY"+1"0$BT`4BX!8@```@^`'PXUV`(M$)`2+4!2+
+M1"0(@^`'B8)8@```PXUV`%575E.+?"04BVPD&(G[BT0D'`^W0`(EX`$``#W`
+M````="H]P````'\+/:````!T%.LBB?:^`````#U``0``="#K$HGVO@$```#K
+M%9"^`@```.L-D+@`````Z;L```")]@^WC'-X"```#[>$<WX(``#!X`8)P0^W
+MA'.$"```P>`,"<$/MX1SB@@``,'@$@G!#[>$<Y`(``#!X!@)P0^WE'.6"```
+M#[>$<YP(``#!X`8)P@^WA'.B"```P>`,"<(/MX1SJ`@``,'@$@G"#[>$<ZX(
+M``#!X!@)PH/]`70/@_T!<AJ#_0)T">L+C78`B<KK#(G1ZPBX`````.L>D(FK
+MW!@``(M'%(F(8)D``(M'%(F09)D``+@!````6UY?7<.)]H/L#(M$)!2+5"08
+M at _@!=12#^@%V![`- at _H%=1JX`````.L3D/]T)!Q24/]T)!SH_/___X/$$(/$
+M#,.)]H/L#(M$)!"+3"04BU0D'(/Y"W4<@^(&B9#(`0``BT`4B9!(@```N`$`
+M``#K&8UV`(/L#/]T)"Q2_W0D+%%0Z/S___^#Q""#Q`S#B?:#[!3_="0L_W0D
+M+/]T)"S_="0L_W0D+/]T)"SH_/___X7`#Y7`#[;`@\0LPU.+7"0(BTPD$(M3
+M%(N"!(```"7__]__#0``!`")@@2```"#?"0,`'01BU,4#[?!#0```@")@@1`
+M``!;PU93@^P$BW0D$(-\)!0`=&"+1A3'@`1`````````@^P,:@KH_/___[L*
+M````@\00D(M&%(N`$$```*D```$`="*#[`QHR````.C\____BT84QX`$0```
+M`````(/$$$MUT.L&A=MU"HGVN`````#K&I"+5A2+@@2````E___[_XF"!(``
+M`+@!````@\0$6U[#D(M,)`2+412+@@2````-```$`(F"!(```(-\)`@`=`V+
+M013'@`1```````$`PXUV`%.+7"0(BTPD$(M3%(N"!(````T```0`B8($@```
+M at WPD#`!T$8M3%`^WP0T```(`B8($0```6\.05U93BU0D$(M<)!2+3"08BT0D
+M'(G6OP$```"#^P)T*8/[`G<(@_L!=`_K39"#^P-T*(/[!'0OZT`/M\!045+H
+MB?[__X/$#.LX@^P(45+HMO[__XG'@\00ZR=14N at X____@\0(ZQL/M\!045+H
+M6/___X/$#.L+C78`N`````#K"9")GM08``")^%M>7\.+1"0$BX#4&```PY"X
+M`````,.)]K@`````PXGVN`````##D)!3@^P(BT0D%(/X`G0G at _@"=PJ#^`%T
+M#>LCC78`@_@$=`OK&9"[`````.L9D+L`````ZQ&0NP````#K"9"X`````.L3
+MD(/L"%/_="0<Z/S___^)V(/$$(/$"%O#D(M$)`2+0!2+0`S#D(M$)`2+4!2+
+M1"0(B4(,PY"+1"0$BT`4QT`(!````,.0@^P,BU0D$(M"%,=`""````!J`&H$
+M:@A2Z/S___^%P`^5P`^VP(/$',.-=@"+1"0$BU`4BX)(@```@^#?B8)(@```
+MPY"+1"0$BU`4BX)(@```@\@@B8)(@```PY"+3"0$BU$4BT0D"(F"0(```(M1
+M%(M$)`R)@D2```##D%.+5"0(BTPD#+@`````@_D_=T*#^1]V((M2%(N:1(``
+M`(/I(+C^____T\`AV(F"1(```.L;C78`BU(4BYI`@```N/[____3P"'8B8)`
+M@```N`$```!;PY!3BU0D"(M,)`RX`````(/Y/W="@_D?=B"+4A2+FD2```"#
+MZ2"X`0```-/@"=B)@D2```#K&XUV`(M2%(N:0(```+@!````T^`)V(F"0(``
+M`+@!````6\.0BT0D!(M`%(N`/(```,.)]HM$)`2+4!2+1"0(B8(\@```PXGV
+MBU0D#(M,)`C'00@`````B=`E_P\``(E!#+@`````.5$,=2'V1"00('0'@4D,
+M`"```,=!%`````#'01``````N`$```##C78`4XM,)`R)RHM$)!2[#P```/9!
+M%`$/A,<```#V0!0!=1F+1"0(BT`4BT`,NP\````[1"00#X2H````9HM"$"7_
+M#P``9HE!((M"%"4`@/\/P>@/9HE!(L9!)`"+0A2H`G4LJ`1T",9!)`'K(HGV
+M]D(4$'0&@$DD".L4@$DD`HM"%"7@````P>@%B$$EB?:+0A`E``#X!\'H$XA!
+M)HM"%/;$`70.)0!^``#!Z`F(02?K!9#&02?_BT(0)0"`!P#!Z`^(02B+0A`E
+M````.,'H&XA!*8M"$,'H#(/@`8A!*KL`````B=A;PY"0D%575E.#[&R+K"2`
+M````B6PD)&;'1"06``!FQT0D%```QT0D$`````#'1"0,`````(N4)(@````/
+MMT("B<+!Z@?!Z`@QT+H,````J`$/A+X(``"+C"2(````#[=!`HG"P>H&P>@%
+M,="Z#````*@!#X2<"```@^P(_[0DD````%7H_/___XE$)#"#Q!"Z#````(7`
+M#X1X"```@[PDA`````9T*H.\)(0````&=PR#O"2$`````7<,ZQ2#O"2$````
+M"'0*N at P```#I1`@``(.\)(P`````=$R+112+F$R```")7"00BY!0@```B50D
+M#(.]I`$```-V#(N`0!$``(E$)##K(+X`````BU44C02U`````(N$`D`1``")
+M1+0P1H/^"7;HBT44BX!8@```B40D"(7`=0C'1"0(`0```(M5%(N"!(```"4`
+M```"B40D&(N"$$```"5@`/X`B40D'(N*%$```(E,)"R+DAA```")5"0H@^P(
+MBYPDD`````^W0P)05>C\____@\00N@,```"%P`^$>P<``(N4)(@````/MT("
+M)?`!```]P````'10/<````!_"3V@````=#+K3CU``0``=`D]4`$``'02ZSYF
+MQT0D%@$`9L=$)!0!`.LN9L=$)!8"`&;'1"04`0#K'F;'1"06`P!FQT0D%`(`
+MZPYFQT0D%@0`9L=$)!0"`(.]I`$```-V#XM%%,>``)@```<```#K#8M%%,>`
+M`)@``$<```"#O:0!```##X;E````BXPDB`````^W00*I@`````^$I0```(M<
+M)"1F@;L`"````#`/AI(```"H('04#[>[_`@```^W at P`)``")1"0$ZQ:+5"0D
+M#[>Z_@@```^WB@()``")3"0$@^P(:@-7Z/S___^)QX/$"&H#_W0D$.C\____
+MB40D%`^W7"0DN<P,``"+%)F`XC^)^,'@!B7`````"<*)%)F^V`P``(L,GH/A
+M\(GZP>H"@^(!BT0D%-'@@^`."<()T8D,GH/$$+X`````OZ`+```/MUPD%(T$
+M=HM-%(L4A:`+```!V(L$AXD$$4:#_AMVY8/L"/^T))````!5Z,<,``"^````
+M`(/$$+\`+@``#[=<)!:0C02VBTT4BQ2%`"X```'8BP2'B0011H/^(G;EO@``
+M``"_(#8```^W7"04B?:-!':+312+%(4 at -@```=B+!(>)!!%&@_X_=N6^````
+M`+O`,```O\0P``")]HL,\X.\)(P`````=`V- at 0"`__\]_P\``'8)BU44BP3W
+MB00*1H'^J@```';4@[VD`0```W=$BU44BXH<@```B<@E__\/``T``-`!B8(<
+M@```BT44QT!<`````(M%%,>`>)@```@```"+512+ at DB```"`S`2)@DB```"#
+MO"2,`````'14BT44BUPD$(F83(```(M%%(M4)`R)D%"```"^`````(.]I`$`
+M``-V$8M5%(M$)#")@D`1``#K'8GVC0RU`````(M5%(M$M#")A`I`$0``1H/^
+M"7;EBTT4BUPD)`^VDU at 6```/MH-9%@``P>`("<(/MH-:%@``P>`0"<(/MH-;
+M%@``P>`8"<*)D0"```"#O"2$`````71U@[PDA`````%R1(.\)(0````&=`^#
+MO"2$````"'1^Z:(```"+312+1"0D#[:0718``,'B"`^V@%P6```)T`M$)!@-
+M``"!`(F!!(```.MWBTT4BUPD)`^VDUT6``#!X@@/MH-<%@``"=`-``""`(F!
+M!(```.M0BTT4BT0D)`^VD%T6``#!X@@/MH!<%@``"=`-```@`(F!!(```.LI
+MBTT4BUPD)`^VDUT6``#!X@@/MH-<%@``"=`+1"08#0``(`")@02```"+512+
+M at A!````+1"0<B8(00```BT44BU0D+(F0%$```(M%%(M,)"B)B!A```"+112+
+M7"0(B9A8@```BTT4BT0D)`^VD%X6```/MH!?%@``P>`("<*+7"0D#[:#8!8`
+M`,'@$`G"#[:#818``,'@&`G"B9$(@```BTT4#[:38Q8``,'B"`^V at V(6```)
+MT(F!#(```(M%%,>`@````/____^#O:0!```$=19F@[VH`0```7<,BU44BT(4
+M@,P$B4(4BT44QX`8@`````<``(/L"/^T))````!5Z/S___^#Q!"Z`P```(7`
+M#X2K`@``@^P(_[0DD````%7H`PT``(/$"/]T)"A5Z$H&``"#Q!"Z`P```(7`
+M#X1^`@``9H&]H`$``!OQ=1J+A"2(````]D`"@'0-BT44QX`(V````@4``(M%
+M%,>`')@```$```"+112+@!29``")P8'A_S\``(N4)(@```#V0@(@=!6-%(T`
+M````N*.++KKWXHG0P>@$ZPRXS<S,S/?AB=#!Z`.#[`R#P&10Z/S___^+512+
+M at F"8``"#R`&)@F"8``"#Q!!J`&H!:&"8``!5Z/S___^#Q`C_M"20````5>C\
+M____@\00A<!U'(N,)(@```#V00(@=05F at TD"`KH#````Z:H!``"+7"0D@[O@
+M&````'07BT44QX`@F0```/`!`,>#Y!@```$```"[`````+X!````C3R=````
+M`(M5%(GPB-G3X(F$.@`0``!#@_L)?N.[`````(/L"%-5Z/S___^#Q!!#@_L)
+M?NV+113'@*0````!``$`BT44QX"H`````0```(M%%,>`K`````$```"+512+
+M at K`0``")@K`0``"+113'@*````!E"0@`BUPD),>#9!8``&4)"`"+512+ at JP`
+M```-```'`(F"K````(.\)(0````&=1R+512+ at J````"`S!")@J````"!BV06
+M````$```@^P,5>C\____@\00A<!T#(/L#%7H_/___X/$$(M5%(N"((```"7_
+M_W_^B8(@@```BT0D)(.X^!@``/]T$H/L"/^P^!@``%7H_/___X/$$(M4)"2#
+MNOP8``#_=!*#[`C_LOP8``!5Z/S___^#Q!"+3"0D@[D`&0``_W02@^P(_[$`
+M&0``5>C\____@\00@[W(`0```'0/BU44BX7(`0``B8)(@```BYPDA````(F=
+ML`$``+@!````ZQ:-=@"+A"20````@S@`=`*)$+@`````@\1L6UY?7<.0@^P4
+M:@+_="0<Z#(#``"#Q!S#B?93@^P(BUPD$&H`:@%J`E/H_/___X/$$+H`````
+MA<!T+(/L"&H34^@!`P``@\00N@````"%P'05@^P,:#0(``#H_/___[H!````
+M@\00B="#Q`A;PY!64X/L!(M<)!"+="04:@!J`6H"4^C\____@\00N@````"%
+MP`^$AP$``(GP)?`!```]P`````^$B0```#W`````?Q8]H````'0]/;````!T
+M-ND/`0``C78`/4`!```/A*@````]0`$``'\,/=````!T4^GN````/5`!```/
+MA(H```#IW@```(M#%,>`!)@```````"+0Q3'@`"B```#````BT,4QX!\F```
+M&0```(/L#&@L`0``Z/S___^#Q!#IH@```(GVBT,4QX`$F````````&:#NZ`!
+M```2#X6%````BT,4QX!\F```&````(/L#&@L`0``Z/S___^+0Q3'@`"B```"
+M````@\00ZUGWQA````!T#XM#%,>`!)@```,```#K#8M#%,>`!)@```````!F
+M@[N@`0``$G4KBT,4QX!\F```&````(/L#&@L`0``Z/S___^+0Q3'@`"B````
+M````@\00D(/L"&H34^AI`0``@\00N@````"%P'0U@^P,:#0(``#H_/___VH`
+M:@%J`E/H_/___X/$(+H`````A<!T$(/L"&H`4^@M`0``B<*#Q!")T(/$!%M>
+MPU575E.#[`R+="0 at BWPD)(.^Y!@````/A(````"+7A2+ at R"9``"I```!`'5P
+MQX;D&````````(NK$)P``(N#%)P``(N3&)P``(E4)`B)ZM'JB<'1Z0'*B<'!
+MZ0;!Z@>)%"1T.87)=#6+1"0(]]B9]SPD@^`_B40D!(GHF??YB<^+1"0$
+MP>`%BY, at F0``"=`)R(#,"(F#()D``(/L"%=6Z"(#``"#Q!"%P'43]D<"('4%
+M9H-/`@*X`````.M9D(/L"%=6Z/S___^#Q!"%P'4S@^P,:(@3``#H_/___X/$
+M"%=6Z/S___^#Q!"%P'45]D<"('4%9H-/`@*X`````.L7C78`@^P,5N at W&```
+MN`$```"#Q!"-=@"#Q`Q;7E]=PU=64XM\)!"+="04B?"%]G4%N/____^)PXM'
+M%(M0#(FP`$```(/L#&H/Z/S___^#Y at .#XP-64V@`0```5^C\____B<*#Q"#W
+MQ@$```!U"HM'%,=`%`````")T%M>7\.)]E575E.#[!2+;"0L#[=%`E`/MT4`
+M4.C\____@\00]D4"@'0]#[_XC1Q_P>,"C;L$.@``@^P(:@C_=P3H_/___XG&
+M@>;_````P>8%BX,$.@``P>`$"<9FBT<(@\00ZP>)]KX`````9CV0`'\$J`%T
+M(8/L"&H(F(/H&%#H_/___XG#@>/_````N`$```"#Q!#K*(/L"&H(F(/H&(G"
+MP>H?`=#1^%#H_/___XG#@>/_````N`````"#Q!#!XP+1X`G#@<L!!```BT0D
+M((M(%(GP)?\```#!X`@/MM,)T(F!G)@``(M$)""+2!2)\"4`_P``#[;7"=")
+M@="8``"+1"0 at B:C\!P``N`$```"#Q`Q;7E]=PXUV`(M$)`2+0!2+@&28``#!
+MZ!,E_P$``/;$`70%-0#^__^8PXUV`%=64XM\)!"*7"04BT\4BY%DF```@>(`
+M\/__B=C!X`DE``X```G"#[]$)!@E_P$```G"B9%DF```BU<4BX)@F```@\@"
+MB8)@F```OC@```"$VW01#[;SC03U`````"GPB<;!Y at F[`````(UV`(M'%(N`
+M8)@``*@"=!2#[`Q6Z/S___^#Q!!#@_L[?N'K!8/[.WX'N`````#K"E?H_/__
+M_YB#Q`1;7E_#D(M,)`R+5"0$BT0D"`^W0`(EX`$``#W`````=#`]P````'\)
+M/:````!T%NLL/4`!``!U)6:+ at EH(``!FB0'K(9!FBX)<"```9HD!ZQ1FBX)>
+M"```9HD!ZPBX`````,.)]K@!````PXGV4X/L!(M<)`R-1"0"4/]T)!13Z('_
+M__^#Q`RZ`````(7`="R+0Q2+D&"8``"+@&28``#!Z!,E_P$``/;$`70%-0#^
+M__]F.T0D`@^>P`^VT(G0@\0$6\.)]E93@^P$BUPD$(MT)!2#NZ0!```#=U:#
+M[`A64^C\____@\00A<!T18U$)`)05E/H#?___X/$#+H`````A<!T1+X`````
+M@^P$:@`/MH9(.P``4%/H0?[__X/$$$:#_@)VY(/^`P^6P`^VT.L8D(M3%(N"
+M8)@``(/(`HF"8)@``+H!````B="#Q`1;7L.055=64X/L/(M4)%2+1"10B40D
+M+/9"`H`/E,!F#[;`9HE$)`BX`@```&8K1"0(9HE$)`@/MT(")>`!```]P```
+M``^$Q@$``#W`````?Q`]H`````^$9P$``.G\`0``/4`!```/A?$!``!FBP(M
+MH0\``&8]Z at 1W)8M4)"QFBY+D"```9HE4)`R+="0L9HNVY@@``&:)="0*Z9<`
+M``!FBP(MC!0``&8][P!W(HM$)"QFBX#H"```9HE$)`R+5"0L9HN2Z@@``&:)
+M5"0*ZV=FBP(M?!4``&8]X`!W(HMT)"QFB[;L"```9HET)`R+1"0L9HN`[@@`
+M`&:)1"0*ZS=F at 3I<%G8BBU0D+&:+DO`(``!FB50D#(MT)"QFB[;R"```9HET
+M)`KK#F;'1"0*``!FQT0D#```BT0D+&:+J&8(``!FBY!L"```9HE4)!!F@[AL
+M"`````^4P&8/ML!FB40D#@^W3"0(NSP-``"+%(N!XO___^^+="0L#[>&7`D`
+M`,'@'`G"B12+NT at -``"+%(N!XO____L/MX9>"0``P>`:"<*)%(N[_`T``(L4
+MBX/B]P^WAEH)``#!X`,)PHD4B^FD````BT0D+&:+@/0(``!FB40D#(M4)"QF
+MBY+V"```9HE4)`J+="0L9HNN:`@``&:+AFX(``!FB40D$&:#OFX(````#Y3`
+M9@^VP&:)1"0.ZU>+5"0L9HN2^`@``&:)5"0,BW0D+&:+MOH(``!FB70D"HM$
+M)"QFBZAJ"```9HN0<`@``&:)5"009H.X<`@````/E,!F#[;`9HE$)`[K"K@`
+M````Z1,!```/MW0D"+^$#0``BQRW at .,_@^P(:@0/M^U5Z/S____!X`</MU0D
+M'L'B!@G0)<`````)PXD<M[^0#0``BQRW@^/X@\0(:@15Z/S____1Z(/@!PG#
+MB1RW at .-_@\0(:@,/MVPD&%7H_/___\'@!R6`````"<.)'+>_G`T``(L<MX/C
+M_(/$"&H#5>C\____T>B#X`,)PXD<MX/CXX/$"&H##[=$)!90Z/S____!X`*#
+MX!P)PXD<M[G,#0``BQ2Q@^+WBT0D(,'@`X/@"`G"B12QNP````"#Q!"_``T`
+M``^W="0(B?:-!%N+5"10BTH4BQ2%``T```'PBP2'B0010X/[&';ABW0D+,>&
+M[!@```````"X`0```(/$/%M>7UW#B?955U93@^P,BWPD((G^BU0D)`^W0@(E
+MX`$``#W`````=$L]P````'\,/:````!T->M#C78`/4`!``!U.;T`````BT\4
+MBY%$F0``@^+'#[>'8`D``,'@`X/@.`G"B9%$F0``ZQV0O0$```#K%9"]`@``
+M`.L-D+@`````Z=<!``")]H._I`$```-W%XM7%(N"$)D``(/(`XF"$)D``.M7
+MC78`BT\4BX$0F0``)0;\__\/MY1N<@@``,'B!`G0@\@!B8$0F0``@^P$_W0D
+M*/^VW!@``%?H_/___XM7%`^_A&Y:"```)?\!``"`S`*)@FB9``"#Q!"0BT\4
+MBY%$F```@>)_P/__#[>$;C`(``#!X`<E@#\```G"B9%$F```BT\4BY%(F```
+M@>+_#_S_#[>$;C8(``#!X`PE`/`#``G"B9%(F```BT\4BY%0F```@>(``/__
+M#[Z$-5<(``#!X`@E`/\```G"#[:$-50(```)PHF14)@``(M?%`^WE&Y("```
+MB=#!X!C!XA`)T`^WC&Y."```B<K!X@@)T`G(B8,TF```BT\4BY$HF```,/8/
+MMX1N/`@``,'@"`G"B9$HF```BT\4BY%DF```@>+_#_C_#[>$;D((``#!X`PE
+M`/`'``G"B9%DF```NP(```!F@;X`"````C!W'&:!OZ(!```B$'4UBT0D)/9`
+M`D!T*[,(ZR>-=@"+5"0D9HL"@^`?#[?`A<!T$X/H"H/X#'8+#[>$;K0(```!
+MPY"+3Q2+D229``"`X@&-!!LE]P````G"B9$DF0``N`$```"#Q`Q;7E]=PXUV
+M`(M,)`2+5"0(B="#^CQV!;@\````9HF!S`$``(M!%(F0/)D``+@!````PXGV
+M55=64X/L+(M\)$2+7"1`#[='`B7@`0``/<````!T5CW`````?PX]H````'1[
+MZ:H```")]CU``0``#X6=````9HN#=@D``&:)1"04C8-B"0``B40D$(V#>`D`
+M`(E$)!@/MX/&#```B40D"(VKR`P``.F#````9HN#@`L``&:)1"04C8.""P``
+MB40D$(V#C at L``(E$)!@/MX,8#0``B40D"(VK&@T``.M09HN#@`L``&:)1"04
+MC8.("P``B40D$(V#*@P``(E$)!@/MX,X#0``B40D"(VK. at T``.L=D+@`````
+MZ98```")T,'@!HV<&%`-``")7"0,ZV2#[`0/MP=0C40D&%#_="1,Z'<```#'
+M1"0<`````(/$"%?_="1,Z/S___^)QKH`````@\009H.[!`D```!T)@^WBP0)
+M``"-=@!F@[Q3!@D```!T#`^WA%,&"0``.?!TCT(YT7_D@^P,5P^W1"084%7_
+M="0D_W0D7.A4`P``N`$```"#Q""#Q"Q;7E]=PU575E.#[#2+7"109L=$)"X`
+M`&;'1"0L/P!H"`$``&@`````Z/S___^#Q`AH@````&@@`0``Z/S___^]B```
+M`+\!````O@````"#Q!`/M\9FB;P`"````$=&9H/_/W;M9HDU!@```&;'!0(`
+M```!`&;'!00````_`+X`````9H,]!@````!V+@^W^P^WWH/L!/]T)$@/MX0;
+M"````%!7Z+4'``!FB41=`(/$$$9F.34&````=]5FBTT`#[<%!@```&:+7$7^
+MO@````!F at ST&`````'9V#[?&9CE,10!_"F:+3$4`9HET)":)\/?0B<=F`ST&
+M````=",/M]=FBT15_F8[1%4`?@IFBT15`&:)1%7^1F8Y-08```!WNKX`````
+M9H,]!@````!V(6:+%08````/M\9F.5Q%`'X*9HM<10!FB70D)$9F.?)WY@^_
+MR8/!&;L?A>M1B<CWZXG0P?@$P?D?*<B-!("-!("--`!FQT0D(@``OP`````/
+MO\Z)3"0<B<CWZXE$)!")5"04BT0D%,'X!,'Y'RG(0(7`?CJY(`$``+@?A>M1
+M]VPD'(G3P?L$BT0D')F)V"G0C5`!#[=$)")FBUPD)F:)'$%F_T0D(D</M\<Y
+MT'SEOP`````/MP4&````B<)F.71%_@^.V0```(/&,HE4)!AF.715_GY9#[_.
+MB<L/M\>)1"0,#[]$10")RBG"B50D$(M$)`P/OU1%`BG1BT0D$`^OP87`?BI'
+MBU0D&&8Y=%7^?AX/M]</OT15`(G9*<&)R`^_5%4"B=DIT0^OP87`?]:#[`AJ
+M``^WUP^WA!(*````T>`/M\!0#[>$$@@```#1X`^WP%`/MT15`E`/MT15`%`/
+MM\90Z)T'``!`#[=4)$*Y(`$``&;1Z&:)!%&#Q""+7"0D9CG8=@1FB1Q19O]$
+M)"(/MQ4&````9CET5?X/CR?___]F at WPD(C]W)+L@`0``N1X!```/MU0D(F:+
+M!%%FB0139O]$)")F at WPD(C]VYKF`H0``OP````"^(@$``+L@`0``#[?'#[<4
+MAL'B&('*``#_``^W!(/!X`@,_R7__P``"<*+;"1`BT44B10(@\$$1V:#_Q]V
+MS(/$+%M>7UW#55=64X/L1(MT)&2+1"18B40D(&;'1"0>``!FQT0D'```9L=$
+M)!H``&;'1"08``!FQT0D%C\`9L=$)!(``+^@`0``_W0D:/]T)%SH_/___]'@
+M9HE$)!R#Q!"+5"1@]D(#`706BTPD4(J!'`@``.L49HE<)!+I6`$``(M4)!B*
+M at AT(``"#[`0/OL!0_W0D:/]T)%SH_/___XA$)!F#Q!"#?"14``^$HP```+L`
+M````B?8/M].+3"149H,\T0!T$&:+!-%FB414($-F at _L'=N*)W8/L#(U$)"I0
+MC40D+%`/M\-0C40D.%"+5"1\#[<"4.C=!@``NP````"#Q"!F.>MS%(M4)!P/
+MM\-F.51$('0&0V8YZW+PBT0D'&8[1"0>=0Z+3"1 at 9HL!9CM$)!QT#@^WPXM4
+M)%2#?,($`'01#[?#BTPD5&:+1,$"9HE$)`Z[`````&8Y\W,<B?8/M\.-%("+
+M3"189HM440AFB51$($-F.?-RYH/L#(U$)"I0C40D+%`/M\90C40D.%"+5"1\
+M#[<"4.@[!@``NP````"#Q"!F.?-S+XGV#[?#9HM$1"!F.T0D''4%9HE<)!8/
+MM\-FBT1$(&8[1"0>#X2D_O__0V8Y\W+3NP````")]HM,)&#V00)`#X36````
+M9H/[!'<P#[=$)!:-!("+5"189HM$0 at 9FB40D%`^W1"02C02`9HM$0 at 9FB40D
+M$.E;`0``C78`9H/[!74N#[=$)!:-!("+3"189HM$001FB40D%`^W1"02C02`
+M9HM$001FB40D$.DE`0``D&:#^P9U+@^W1"06C02`BU0D6&:+1$("9HE$)!0/
+MMT0D$HT$@&:+1$("9HE$)!#I\0```)!F at _L'#X7F````#[=$)!:-!("+3"18
+M9HL$06:)1"04#[=$)!*-!(!FBP1!9HE$)!#INP```(UV``^WPX/X!P^'K```
+M`/\DA5@[```/MT0D%HT$@(M4)%AFBT1"!F:)1"04#[=$)!*-!(!FBT1"!F:)
+M1"00ZWL/MT0D%HT$@(M,)%AFBT1!!&:)1"04#[=$)!*-!(!FBT1!!&:)1"00
+MZU$/MT0D%HT$@(M4)%AFBT1"`F:)1"04#[=$)!*-!(!FBT1"`F:)1"00ZR</
+MMT0D%HT$@(M,)%AFBP1!9HE$)!0/MT0D$HT$@&:+!$%FB40D$)"#[`AJ``^W
+M1"0<4`^W1"0D4`^W1"0R4`^W1"0T4(M4)'P/MP)0Z$H#``")P8/$(&8[1"0.
+M=@5FBTPD#HM$)&#V0`(0=!^+5"089H&Z``@````P=A!F.XH."```=@=FBXH.
+M"```#[?S#[=4)`P/OD0D"2G"#[?!.<)^`HG"9HD4=V:%VW4KBTPD4(N!T`$`
+M``^WA`!,.P``T>!FBQ=F*<)FB50D"F:%TG\'9L=$)`H!``^WRP^_1"0*#[<4
+M3SG0?@*)T&:)!$]#9H/[!P^&D_W__P^W!XM4)!B)@O`8``"+3"10BUD4N0``
+M``"#X0'!X1ZX/P```&8C1P;!X!B)R at G"N#\```!F(T<$P>`0"<*X/P```&8C
+M1P(/M\#!X`@)PK at _````9B,'#[?`"<*)DS29``"+1"10BU`4N#\```!F(T<.
+MP>`8"<&X/P```&8C1PS!X!`)P;@_````9B-'"@^WP,'@"`G!N#\```!F(T<(
+M#[?`"<&)BCB9```/MP=0_W0D5.C\____9HL'BU0D6&:)@LX!``"#Q$1;7E]=
+MPXUV`%575E.#[!R+?"0XBW0D,(M<)#2-1"0:4%</M\-0#[?&4.@^`0``@\00
+MA<!T"P^W1"0:Z24!``"0@^P,C40D)%"-1"0F4`^W1P10_S</M_96Z&<"``"#
+MQ!2-1"0 at 4(U$)")05P^W1"0N4`^WVU/H*@,``(/$%(U$)!Q0C40D'E!7#[=$
+M)#!04^@0`P``@\0 at C40D#%!7#[=$)!I0#[=$)")0Z+X```"-1"0:4%</MT0D
+M+%`/MT0D,E#HIP```(/$&&H`#[=$)!90#[=$)!Q0#[=$)"A0#[=$)"I04^CT
+M````B<6#Q""-1"0,4%</MT0D%E`/MT0D)%#H:````(U$)!I05P^W1"0H4`^W
+M1"0T4.A1````@\08:@`/MT0D%E`/MT0D'%`/MT0D)%`/MT0D)E!3Z)X```"#
+MQ!AJ``^WP%`/M\50#[=$)"Q0#[=$)"Y05NA_````#[?`@\0 at D(/$'%M>7UW#
+M55=64XMT)!R+;"04BWPD&(M."+L`````9H-^!`!V1Y!F.2EU-XU1"+@`````
+M9H-Y!@!V*&8Y.G47#[?`9HM401Z+1"0 at 9HD0N`$```#K')"#P@)`9CE!!G?:
+MB?:#P31#9CE>!'>ZN`````!;7E]=PU575E.#[`2+;"08BTPD'(M\)""+="0D
+MBUPD*&;'1"0"9``/M\8/M],/K\*Z`````(7`#X2C````@WPD+`!T!V;'1"0"
+M`0!F.<]T=0^WQ0^WR2G(C02`C02`P>`"#[?7*<J)T9GW^6:%P'D5#[?&@WPD
+M+`!T8XT$@(T$@,'@`NM89H/X9'X6#[?#@WPD+`!T2(T$@(T$@,'@`NL]D`^_
+MR`^WPP^OP;ID````*<H/M\X/K]$!T`^W5"0"B=&9]_GK&(GP at WPD+`!T#P^W
+MQHT$@(T$@,'@`HUV``^WT(G0@\0$6UY?7<.-=@!55U93BW0D&(M\)""+;"0D
+MBUPD'`^WPV:+3$;^#[=4)!2-!)*-!("-%(4`````#[<&C02`C02`C02%]O__
+M_SG0=A)FBP9FB0=FBP9FB44`Z80````/M\&-!("-!("-!(4*````.=!S+&:)
+M#V:)30#K9V:+!$YFB0=FBP1.9HE%`.M69HL$3F:)!V:+1$X"9HE%`.M$N0``
+M``!FA=MT.@^WVXUV``^W!$Z-!("-!(#!X`(IT(/`"8/X$G:V#[=$3@*-!("-
+M!("-!(7V____.=!WL4$YRW_.B?9;7E]=PXUV`%=64XM$)!B+?"00BW0D%(M0
+M"+D`````#[=`!(G#@_@`?@^)]F8Y,G0(@\(T03G+?_/_="0 at _W0D(`^W0 at 90
+MC4((4`^WQU#HU?[__X/$%%M>7\.)]HM$)`2-B#P6``"+%80[``")D#P6``"-
+M!-4`````*="-!(6(.P``B4$8QT$4`0```,=!#!0```#'01`C````PY!75E.+
+M5"04BT0D$(N`_`<``/9``B!T);\`````NQP```"Y0````+YR````QT(,````
+M`,="$'<```#K(Y"_`````+LR````N0````"^,@```,="#!0```#'0A`C````
+MBU($N``````Y^G($.=IV#3G*<@0Y\G8%N`$```!;7E_#D(M$)`2+2!2+D/`8
+M``#!X at F!X@!^``"`SH")D3"9``#'@.P8```!````PXGV5U93BWPD$(G[C;<\
+M%@``N`````"#?A0`='B#O^P8```!=6F+1Q2+@#"9``"I`(```'59P>@9B48$
+MQX?L&````````%97Z`K___^#Q`B%P'4[@^P(5E?H/0```(/$$(7`="J#[`A6
+M5^A(````@\00A<!^&8/L"%97Z$L!``#'A^P8```"````@\00B?:+@^P8``!;
+M7E_#B?:+3"0(N`````"+400[40QV!3M1$'(%N`$```##5E.+7"00NO____^#
+M>Q0`#X3W````BP.-%,4`````*<*-%)6(.P``B5,8BT,$.T,0<F*Z_____X,[
+M``^$S````(M#!(E#"#M#$')!@SL`=#R+`TB)`XT4Q0`````IPL'B`HM+&(N"
+MD#L``"M!"-'@BTL(*<&)2PB!PH@[``")4Q@[2Q!R!X,[`'7&B?:Z`0```.MY
+MD(M#!+H`````.T,,=VNA@#L``$BZ_O___SD#=%R+0P2)0P@[0PQW2:&`.P``
+M2#D#<S^)QI"+`T")`XT4Q0`````IPL'B`HM+&(N"D#L``"M!"-'@BTL(*<&)
+M2PB!PH@[``")4Q@[2PQW!SDS<L>-=@"Z`@```(UV`(G06U[#C78`BTPD!(M4
+M)`B#>A0`=#>+0AAFBP!FB8%@"0``BT(89HM``F:)@5X)``"+0AAFBT`$9HF!
+M7`D``(M"&&:+0`9FB8%:"0``PXGVBTPD!(M!%(N`!(```"7__P``BY&P`0``
+M at _H!=#.#^@%R'H/Z!G0)@_H(="3#C78`BU$4#0``@0")@@2```##D(M1%`T`
+M`$(`B8($@```PY"+410-```@`(F"!(```,.05U93BWPD$(/L#%?H_/___XG&
+M@\0()?___W]05^C\____BT<4BU`PB=.!X_`#``#!ZP2#Q!"#?"04`'00N"4`
+M```IV-'H`</K'XUV`(/[`78#2^L4@^P(5E?H_/___[@`````@\00ZRJ+3Q2!
+MX at _\__^)V,'@!"7P`P``"<*)43"#[`A65^C\____N`$```"#Q!!;7E_#B?93
+M@^P(BUPD$(M4)!2X`````(/Z"7\>@^P$_W0D'(T$4HT$@(V$@WP6``!04^C\
+M____@\00@\0(6\.-=@!3@^P(BUPD$(M4)!2X`````(/Z"7\>@^P$C012C02`
+MC82#?!8``%#_="0 at 4^C\____@\00@\0(6\.-=@!55U93@^P,BVPD((MT)"2)
+MZH/^`G0:@_X"=PF#_@%T*.L^B?:#_ at -T#X/^!'01ZS"_"0```.LQD+\(````
+MZRF_`0```.LBB?:_`````+@`````@[V`%@```'5\ZPN-=@"X_____^MPD(T$
+M?XT$@(V<@GP6``"X_____X-[!`!U5X/L"&H\4^C\____B7,$@\00 at WPD*`!U
+M+,=##`L```#'0Q0"````QT,8_____\=#'/\#``!FQT,@"@!FQT,B"@#K$XGV
+M@^P$_W0D+%=5Z/S___^#Q!")^(/$#%M>7UW#D%.+3"0(BUD4BY%H%@``@>+_
+M`P``BX%P%@``P>`0)0``_P,)PHF3I````(M9%(N1;!8``('B_P,``(N!=!8`
+M`,'@$"4``/\#"<*)DZ@```"+612+ at ZP````E`/S__XN1>!8``('B_P,```G0
+MB8.L````6\.05E.+="0,BTPD$+@`````@_D)=U2-!$F-!("-G(9\%@``N```
+M``"#>P0`=#S'0P0`````N/[____3P"&&:!8``"&&;!8``"&&<!8``"&&=!8`
+M`"&&>!8``%-6Z"W___^X`0```(/$")!;7L.055=64XM\)!B+;"04BY7\!P``
+MN`````"#_PD/AP@$``"-!'^-!("-M(5\%@``N`$```"#?@0`#X3L`P``@WX8
+M_W4VA=)T%0^W0@(EH````+H?````/:````!T!;H/````N`$````YT',2C78`
+MT>"#R`$YT'+WZP20BT88C1R]`````(M4)!2+2A2)PH'B_P,``(M&','@"B4`
+M_`\`"<*+1A3!X!0E``#P#PG"B9090!```(M$)!2+2!0/MT8BP>`$)?`````/
+MMU8@@^(/"=`-`"`(`(F$&8`0``"+5"04BT(4QX08P`D````(``"#NJ0!```#
+M=PZ+0A3'A!@`$0```````8-^)`!T3HT,O0````"+1"04BU at 4BU8D@>+___\`
+MBT8HP>`8"<*)E`O`"```BU0D%(M:%(N$"\`)``")PH/*`8-^*`!T"(G"@<H!
+M`0``B90+P`D``(-^,`!T(HT,O0````"+1"04BU`4BT8P)?___P`-`````8F$
+M"@`)``"#?BP`=$.-#+T`````BT0D%(M0%(M&+"7__P\`#0``$`")A`K`$```
+M]D8,0'0;BT0D%(M0%(N$"L`)``"`S`*)A`K`"0``C78`]D8,$'0AC0R]````
+M`(M$)!2+4!2+A`H`$0``#0``(`")A`H`$0``]D8,@'0?C0R]`````(M$)!2+
+M4!2+A`H`$0``@,P"B80*`!$``(M&!(/X`W1I at _@#=PJ#^`)T$^GY````@_@$
+M#X30````Z>L```"-#+T`````BT0D%(M0%(N$"L`)```,HHF$"L`)``"+5"04
+M@[JD`0``!!G;@>,````!@<,``"4`B<J+3"04BT$4B9P0`!$``.F?````C0R]
+M`````(M$)!2+4!2+A`K`"0``#6("``")A`K`"0``H0`````K!0````"+E?08
+M``")TRG#*QT`````P>,*BT0D%(M0%(G8#0````&)A`H`"0``BU0D%(.ZI`$`
+M``09VX'C`````8'#```$`(G*BTPD%(M!%(F<$,`)``#K((T,O0````"+1"04
+MBU`4BX0*P`D``(/((XF$"L`)``"0]D8X`70AC0R]`````(M$)!2+4!2+A`H`
+M$0``#0``)`")A`H`$0``]D8,`703N`$```")^=/@"85H%@``ZQ&)]KC^____
+MB?G3P"&%:!8``/9&#`%T$[@!````B?G3X`F%;!8``.L1B?:X_O___XGYT\`A
+MA6P6``#V1 at P"=!.X`0```(GYT^`)A7`6``#K$8GVN/[___^)^=/`(85P%@``
+M]D8,!'03N`$```")^=/@"85T%@``ZQ&)]KC^____B?G3P"&%=!8``/9&#`AT
+M$[@!````B?G3X`F%>!8``.L1B?:X_O___XGYT\`AA7 at 6``!6_W0D&.@#^___
+MN`$```"#Q`B-=@!;7E]=PXUV`(M$)`C!X`*+5"0$BU(4BX0"``@``,.)]HM4
+M)`C!X@*+1"0$BT at 4BT0D#(F$$0`(``"X`0```,.0BTPD"(M$)`2+4!2X`0``
+M`-/@B8)`"```N`$```##B?964XM4)!#!X@*+1"0,BW`4BX06``H``(G#@^,#
+M=1JX`0```(I,)!#3X(N60`@``(7"=`6[`0```(G86U[#C78`5U93BWPD$(MT
+M)!2+5Q2X`0```(GQT^")@H`(``"[`````(GV5E?H_/___X/$"(7`=!:#[`QJ
+M"NC\____@\000X'[#R<``'[<BT<4QX"`"````````('[#R<```^>P`^VP%M>
+M7\.-=@"X`0```,.)]E93BW0D+(M<)#2+3"00BT0D%"7_#P``BU0D),'B$@G0
+MBU0D,,'B&0G0]L,!=`4-`````?;#$'0%#0```"#VPP1T!0T``$``]L,@=`4-
+M``"``(E!"(M$)!R)PL'B&O;#`G0&@<H``(``B5$, at _[_=!:)\,'@#24`X`\`
+M"=")00R!20@```!`N`$```!;7L.)]K@`````PXGV4XM,)!"+7"08BU0D#(-\
+M)!0`=!2+0 at P)R(7;=0.`S!")0 at SK)XUV`(7;=!"+1"0<BT`(B4((B4H,ZQ&0
+MQT((`````(G(@,P0B4(,D,="%`````#'0A``````N`$```!;PXUV`%.+3"0,
+MB<JX#P```/9!%`$/A*(```"+010E_A\``-'H9HE!(`^W01)FB4$BQD$D`(M!
+M$*@!=1VH`G0$QD$D`?9"$`AT!(!))`+V0A`$=`6`220$D(M"""4``#P`P>@2
+MB$$EBT(4)0#@'P#!Z`V(02:+0A`E``\``(G#P>L(B%DGBT(0)?````#!Z`2(
+M02B+0A`E`/```,'H#(A!*<9!*@"$VW0&C4,!B$$G@'DH`'0#_D$HN`````!;
+MPXGVPY"0D(/L#(M,)!"+013'@-"8```6'```N@````"-=@"+013'@("8````
+M``$`0H/Z!W[MBT$4BX``G```P>@8B<+!Z at 2#X`_!X`0)T(/L"&H(4.C\____
+M@\0<PY!75E.![)````"+G"2@````C7PD<+ZL1```_+D%````\Z6-?"10OL!$
+M``"Q!?.EC7PD,+[41```L07SI8U\)!"^Z$0``+$%\Z6Z`````(UV`(M$E'")
+MA).T+@``BT244(F$D\@N``"+1)0PB823W"X``(M$E!")A)/P+@``0H/Z!'[.
+M@<20````6UY?PU93@^P0BW0D'&@P+P``Z/S___^)PX/$$(7`=12+1"0 at QP`"
+M````N`````#INP```(/L!&@`"```:*`\``!0Z/S___^+1"0DB4,,BT0D*(E#
+M$(M$)"R)0Q1FB;.@`0``9L>#H@$`````9L>#S`$``#P`QX/0`0```````,>#
+M5!D```````#'@U at 9````````QX-<&0```````,>#:!D```$```#'@VP9````
+M````QX-P&0``9````,>#=!D```(```#'@X09``#_____QX.(&0``_____\>#
+MC!D``/_____&@Y`9````B=B#Q!"#Q`1;7L.-=@!55U93@^PHBWPD3%?_="1,
+M_W0D3/]T)$P/MT0D3%#H_/___XG&@\0 at N`````"%]@^$:@4``(GS:@!J`6H"
+M5NC\____@\00A<!U#L=$)!0#````Z2D%``"0@^P(:@!6Z/S___^#Q!"%P'4.
+MQT0D%`,```#I"04``)"+1A2+@"!````/MM")T,'H!(F&I`$``(G0@^`/9HF&
+MJ`$``(.^I`$```5T"8.^I`$```=U"F:#NZ@!```!=PW'1"04#0```.F\!```
+MBT,4BX`8F```9HF#J@$``(/L#%/H_/___X/$$(7`=0W'1"04#@```.F/!```
+MBT,4QX``F```!P```(/L#%/H_/___V:)@ZP!``"#Q!`/M\`E\````(/X('18
+M at _@@?PR#^`=T3H/X$'1)ZPJ#^#!T0H/X4'0]9H.[K`$```!U,X.[I`$```5U
+M&(&[J`$```D`0P!U#&;'@ZP!``!&`.L3D(.[I`$```=U"6;'@ZP!``!1``^W
+MDZP!``")T"7P````@_ at O?A>)T(/@#X/X!'\-QT0D%`T```#IX`,``(/L!(U$
+M)!Y0:,$```!3Z/S___^#Q!"%P'4-QT0D%`@```#IN0,``&:!?"0:`3!W#<=$
+M)!0%````Z:,#``!FBT0D&F:)A@`(``"+0Q2+D!!```"#XAC!Z at .#^@)T#<=$
+M)!0*````Z78#``"#[`2-1"0>4&H_4^C\____@\00A<!U#<=$)!0(````Z5(#
+M``!FBT0D&F:)A@((``"#[`2-1"0>4&H<4^C\____@\00A<!U#<=$)!0(````
+MZ2(#``#'1"0,0`,``&:#?"0:`'1&#[=$)!HE\/\``,'@#(E$)`R#[`2-1"0>
+M4&H;4^C\____@\00A<!U#<=$)!0(````Z=T"```/MT0D&@E$)`R!;"0,P```
+M`,=$)!``````O0````"+1"0,.<5S,(/L!(U$)!Y0C87`````4%/H_/___X/$
+M$(7`#X2/`@``#[=$)!HQ1"0013ML)`QRT(%\)!#__P``=`W'1"04!P```.EP
+M`@``9L>&=@D```H`9L>&@`L```,`O0````"-1&T`C42%`&;'A(9^"0``"P!%
+M at _T)=NB]`````+J at 1```N:9$``!FBP1J9HF$;H at +``!FBP1I9HF$;H(+``"-
+M1&T`C42%`(T$AF;'@#`,```+`&;'@)0+```+`$6#_0)VQ8/L"(V&``@``%!3
+MZ/S___^#Q!"%P'4-QT0D%`@```#ITP$``&:#OA@(````='4/MX.L`0``)?``
+M``"#^!!U9(M#%,>``)@```=```"#[`QHT`<``.C\____B1PDZ/S___]FB8.N
+M`0``BT,4QX``F```!P```,<$)-`'``#H_/___P^W at ZX!```E\````(/$$(/X
+M('0.QT0D%`T```#I50$``)"#[`2-1"0>4&B_````4^C\____@\00A<!U#<=$
+M)!0(````Z2T!``!FBT0D&F:)A at 0(``!FB8/4`0``@^P,4^C\____@\00A<!U
+M#<=$)!0(````Z?T```"#NZ0!```'=12#[`B-1"0<4%/H_/___X/$$.LVD`^W
+M at ZP!```E\````(/X+WX3@^P(C40D'%!3Z/S___^#Q!#K$8/L"(U$)!Q04^C\
+M____@\00A<`/A*,```"#[`Q3Z/S____'1"0@`````+T`````@\00@^P$C40D
+M'E"X'P```"GH4%/H_/___X/$$(7`=%D/MT0D&@%$)!!F#[9$)!N(A&Y<%@``
+M9HM$)!J(A&Y=%@``18/]`G:[@WPD$`!T"H%\)!#]_P(`=0K'1"04"0```.LJ
+M4^@D^?__@^P(4^C\____B=B#Q!#K,\=$)!0(````ZPJ)]L=$)!0(````A?9T
+M#(/L#%;H_/___X/$$(7_=`:+1"04B0>X`````(/$'%M>7UW#D%.#[!2+7"0<
+M4^C\____@\00@[O(%@```'0.@^P,4_^3R!8``(/$$)!J`&H!:@-3Z/S___^)
+M'"3H_/___X/$&%O#C78`55=64X/L+(MT)$#'1"0(`(```,=$)`P at F```QT0D
+M$%55557'1"04JJJJJL=$)!AF9F9FQT0D')F9F9F_`````(UL)`B-!+T`````
+MBQPHBU84BQ0:B10$N0````")R,'@$(G""<J+1A2)%!B+1A2+!!@YT'0'N```
+M``#K84&!^?\```!^U[D`````BU2,$(M&%(D4&(M&%(L$&#G"=`JX`````.LX
+MC78`08/Y`W[<C02]`````(M.%(L4*(L$!(D$$4>#_P$/CGG___^#[`QJ9.C\
+M____N`$```"#Q!"#Q"Q;7E]=PXUV`(M4)`R+3"00BT0D"/;$`7039L<".!-F
+MQP'4%[@!````PXUV`*F`````="&+1"0$9H.X&`@```!T$V;'`@@)9L<!K`JX
+M`0```,.-=@"X`````,.)]E575E.#[`R+;"0 at B>^)ZXVUM`$``&;'1"0*``!F
+M@;T`"````%!V)8/L!(U$)`Y0:,D```!5_Y6$`0``@\00N@````"%P`^$3`(`
+M`)!F at WPD"@!U+(.]I`$```=U(V:#O:@!```(=1EFQT0D"@4`9L>'!@@```$`
+M9L>'"`@```$`@[NP`0``!G0[9H&[H@$``&5P=3!FBY/4`0``C4*<9H/X`7<,
+MC4(%9HF#U`$``.L49H.[U`$``$%U"F;'@]0!``!#`)#'1 at 0`````9H._%@@`
+M``!T&\=&!`$```!F@[\&"````'4*QT8$`P```(UV`&:#OQ@(````=`2#3 at 0$
+M9H._&@@```!T*&:!NZ(!```1#G0=BU8$B="#R`B)1 at 1F@[\("````'4(B="#
+MR"B)1 at 1FQT80"`D/MX6L`0``)?````"#^"]_"8.]I`$```=U"&;'1A+$">L&
+M9L=&$JP*9L=&##@39L=&#M07BD8!@^#?@\A`B$8!N`````!F@[NH`0```W8+
+M]D0D"@)U!+`!B?;!X`2*5@&#XNL)PH/*"`^W3"0*B<C1Z(/P`8/@`='@@^+]
+M"<*(5@&`#@-F@[NH`0```79=N`````#VP0%U"O9&!`ET!+`!B?:-'(4`````
+MBA:#XO,/MTPD"HG(P>@#@_`!@^`!P>`#"=H)PH at 6N`````#VP01U"?9&!`ET
+M`[`!D(C"P>($B@:#X.\)T(/(H(@&@":_N@````"#O\@(````=`F#O\P(````
+M=06Z`0```(I&`8/@_ at G0@\B`B$8!@$X"`0^W1"0*)?`!``!T"L'X!&:)1 at CK
+M!Y!FQT8("@!F]T0D"@#P=!4/MTPD"L'I#+@!````T^!FB48*ZP9FQT8*@`"Z
+M`0```(G0@\0,6UY?7<.0D)!75E.+3"00BW0D%(M<)!B)SXM!%(FP*(```(N!
+ML`$``(/X`70/@_@!<B:#^`9T(8/X"'5$BT$4QX`L@```__\``(M!%,>`,(``
+M`/__!P#K*(M1%(GP*P4`````P>`#B8(L@```BU$4B?`K!0````#!X`.)@C"`
+M``"+412-1@&#OU09````=`B)\`.'5!D``(F"-(```('C__^``8G8P>@8A<!T
+M#8M!%,>`((````````&+012)F""```!;7E_#B?964X/L!(MT)!"[`````(GV
+M@^P(:@)6Z/S___^#Q!"%P'06@^P,:@KH_/___X/$$$.!^^<#``!^V('[YP,`
+M``^>P`^VP(/$!%M>PXGVBU0D!(M"%,>`*(````````"+2A2+ at 02````-```$
+M`"7__\__B8$$@```BT(4QX`@@```__\``,-55U93BVPD%(M<)!AF at WL2`'1!
+MBU44BX($@```#0``$`")@@2```"+510/MT,0B8(D@```BU44#[=#$HF".(``
+M`(M5%(M#%,'@`XF",(```.L6B?:+512+@@2````E___O_XF"!(```(M5%(L#
+MB8(H@```BTT4BX$@@```)0``@/\/MU,("<)F at WL8`'01#[=#&(/`!,'@$"4`
+M`'\`"<*)D2"```"+312+D1B````P]@^W0QK!X`@E`/\```G"B9$8@```BWL(
+M.7L<=@.+>QR+<PPY<QQV`XMS'#GW=0:+2P3K`Y"+"XM5%(M#!(/H`\'@`R7_
+M_P<`#0``&`J)@M2```"+512-!,WH____)?__!P`-````"HF"V(```(M-%(GX
+M)?__``")\L'B$`G0B8'<@```6UY?7<-3@^P(BUPD$(M3%(M$)!2)@@!@``"+
+M0Q3'@`A@```!````:@)J`V@,8```4^C\____@\00N@````"%P'05BT,4BY`$
+M8```BT0D&&:)$+H!````B="#Q`A;PY"0D%.+1"0(BU at 4BTPD#-'AN@,```#3
+MXHN#%$````G0B8,40```N`$```!;PXGV4XM$)`B+6!2+3"0,T>&X`P```-/@
+M]]"+DQ1````AT(F#%$```+@!````6\-3BTPD#(M$)`B+6!2+DQA```"X_O__
+M_]/`(<*+1"00@^`!T^`)PHF3&$```+@!````6\.0BTPD"+C_____ at _D%=Q6+
+M1"0$BT`4BX`<0```@^`OT^B#X`'#5E.#[`2+="00BU0D%(M&%(N8%$```(T,
+M$K@#````T^`-`/`!`/?0(</!X at P)TX#/@(-\)!@`=`:!RP```0"+1A2)F!1`
+M``"#[`B+AF at 6```-`````5!6Z/S___^#Q!1;7L.0D(M$)`2+0!2+@`A```"#
+M^`$/E,`/ML##D%=64XM\)!"+="04BT<4BYC`````@_O_=1/'!@````"X````
+M`.F9````C78`B=@ENM@%`8D&]\,```@`=`<-````0(D&]L,%=`.##@'WP\`%
+M``!T7H,.0(M/%(N1Q````('B_P,```N7+"\``(F7+"\``(N!Q````"4``/\#
+MP>@0"=")ARPO``"+D<@```"!XO\#```)PHF7+"\``(N!R````"4``/\#P>@0
+M"=")ARPO``#VPR!T!H$.````0+@!````6UY?PXGVBT0D!(N`:!8``,.05U93
+MBW0D$(M<)!2)\8N^:!8``(7_>1&+1A3'0"0`````BT84BT`DD(G:@>*ZV`4!
+M]L-`=#.#N>06````=`.#RD"#N>@6````=`.`S@&#N>P6````=`.`RH"#N?`6
+M````=`:`S at 2-=@#VPP%T`X/*!_?#````0'0&@<H```@`BT84B9"@````B9EH
+M%@``A=MY"XM&%,=`)`$```"0B?A;7E_#D)"+1"0$#[>`O@$``,.+5"0$BT0D
+M"&8Y at KX!``!V&P^WP,'@!0-"%(N`'(@``+H!````J0"```!U!;H`````B=##
+M5E.+7"0,BW0D$+@`````9CFSO@$```^&V0````^WQL'@!8G"`U,4BXH4B```
+MQX(`B````````(G"`U,4QX($B````````(G"`U,4QX((B````````(G"`U,4
+MQX(,B````````(G"`U,4QX(0B````````(G"`U,4QX(4B```!P```(G"`U,4
+MQX(8B`````````-#%,>`'(@```````"#^01U38.[:!D```!T1(U&0`^WP,'@
+M!8G"`U,4QX(`B````````(G"`U,4QX($B````````(G"`U,4QX((B```````
+M``-#%,>`#(@```````"0N`$```!;7L-75E.+?"00BU0D&(MT)!2X`````&8Y
+MM[X!``!V:X72=#@/MEH%P>,(#[9"!`G##[9*`\'A&`^V0 at +!X!`)P0^V0@'!
+MX`@)P0^V`@G!T>F)V,'@'PG!T>OK"[L`````N0````"0#[?&P>`%B<(#5Q2)
+MBAB(```#1Q2)VH#.@(F0'(@``+@!````6UY?PU575E.#[!2+="0PBTPD+(M4
+M)"B!PK0!``"#?"0X`1G;]].!XZJJJJJ_`````&8Y2 at H/AD$#```/M@:#^`4/
+MAXT```#_)(7\1```QT0D!`4```#IA0```+\`````]D(!$`^$$@,``,=$)`0&
+M````ZVS'1"0$!`````^WP8/`0`^W4 at J_`````#G0#XWI`@``ZTN_`````&:#
+M?@($#X;7`@``QT0D!`````!F at WX"!78L9H-^`@X9P(/@_H/``XE$)`3K&<=$
+M)`0'````ZP^-=@"_`````.F>`@``B?8/ME8$#[9&!<'@"`G"#[9&!L'@$`G"
+M#[9&!\'@&`G",=J)5"00#[9&"<'@"`^V5@@)PC':@>+__P``B50D#`^V;@H/
+MMD8+P>`("<4/MD8,P>`0"<4/MD8-P>`8"<4QW0^V1 at _!X`@/ME8."<(QVH'B
+M__\``(E4)`@/MGX0#[9&$<'@"`G'#[9&$L'@$`G'#[9&$\'@&`G',=]F at WX"
+M#7<&@>?_````@WPD!`0/A7,!``"+7"0H@[MH&0````^$8@$``(U90`^WR8G(
+MP>`%B00DB<*+1"0H`U`4BT0D$/?0B8(`B```BQ0DBT0D*`-0%(M$)`SWT(F"
+M!(@``(L$)(M4)"@#0A2)J`B(``"+!"0#0A2+5"0(B9`,B```BP0DBU0D*`-"
+M%(FX$(@``(L$)`-"%,>`%(@```0```#_="0T45+H_/___P^V3A0/MD85P>`(
+M"<$/MD86P>`0"<$/MD87P>`8"<$/ME88#[9&&<'@"`G"#[9&&L'@$`G"#[9&
+M&\'@&`G"#[?;P>,%B=B+="0T`T84B8@`B```@\0,B=@#1A3'@`2(````````
+MB=@#1A2)D`B(``")V`-&%,>`#(@```````")V`-&%,>`$(@```````")V`-&
+M%,>`%(@```<```")V`-&%,>`&(@````````#7A3'@QR(````````BP0D`T84
+MBU0D$(F0`(@``(L$)`-&%(M,)`R)B`2(``#K=(UV``^WR8G(P>`%B<*+7"0H
+M`U,4BW0D$(FR`(@``(G"`U,4BUPD#(F:!(@``(G"BW0D*`-6%(FJ"(@``(G"
+M`U84BUPD"(F:#(@``(G"`U84B;H0B````T84BW0D!(FP%(@``/]T)#11_W0D
+M,.C\____@\0,OP$```")]HGX@\046UY?7<.0D(/L$&H&BT0D&`5<%@``4/]T
+M)"#H_/___X/$',.#[!!J!O]T)!R+1"0<!5P6``!0Z/S___^X`0```(/$',.-
+M=@!3BUPD$(M,)`BZ#````(M$)`QF.8'4`0``=!@/MX$""```P>@'@^`!@_@!
+M&=*#XOB#P at N%VW0"B1.X`````%O#BTPD!(G*N`````!F@[D6"````'0.9H.Y
+M!@@```$9P(/@`D!F@[H8"````'0#@\@$9H.Z&@@```!T'F:!N:(!```1#G03
+M@\@(9H.Z"`@```!U!H/(((UV`,.-=@!3@^P(BUPD$&:#NPH(````=$J#[`2-
+M1"0*4&H/4_^3A`$``(/$$+H`````A<!T60^W5"0&B="#X!S!^`*)@Y09``"#
+MX at +1^HF3F!D``,>#H!D```$```#K(8UV`,>#E!D```````#'@Y at 9````````
+MQX.@&0```````&:#NPH(````#Y7`#[;0B="#Q`A;PY!3@^P0BUPD&/^SE!D`
+M`%/_DY`!``"+4Q2+@@"8``"`S"")@@"8``"#Q`C_LY09``!3_Y.4`0``B8.<
+M&0``@\0,.X.8&0``#Y7`#[;`4/^SE!D``%/_DYP!``"#Q!A;PY"+1"0$BT at 4
+MBX$00```)9__\?^+5"0(@^('"P25($4``(F!$$```,.05E.#[`B+7"04BW0D
+M'&H&_W0D'(V#8A8``%#H_/___XM+%`^VDV(6```/MH-C%@``P>`("<(/MH-D
+M%@``P>`0"<(/MH-E%@``P>`8"<*)D0B```"+2Q0/MH-G%@``P>`(#[:39A8`
+M``G"@>;_/P``P>80"?*)D0R```"+4Q2+@@R````E__\``(F"#(```(/$%%M>
+MPU.+1"0(BT at 4BX%0@```B<*X`````(N)3(```+L`````"<@)VEO#B?:+1"0$
+MBT`4BX!,@```PXGVBTPD!(M1%(N"((````T````!B8(@@```BU$4B8(@@```
+MPXGV5E.+="0,BUPD$(N&_`<``(7`=&#V0`(@=%JP`+D`````.PMS'(UV`(I4
+M"P2$TGD,@^)_.,)R!8C0C78`03L+<N>+5A2+B at 2```"$P'06T.@\`G<0B<@-
+M`````HF"!(```.L1D(M6%(G()?____V)@@2```!;7L.0BU0D!(M"%(N`9)@`
+M`(G!P>D3@>'_`0``B<C!Z`B%P'0&@?$`_O__BU(4BX)0@```BY),@```,=`Q
+MR,.04XM4)`B+0A2+@"!````E_P```(G!@^$/NP````#!Z`0Y at J0!``!U#&8Y
+MBJ@!``!U`[,!D(G86\.+3"0$BT0D"(M1%(N2D(````$0BU$4BY*,@````5`$
+MBU$4BY*4@````5`,BU$4BY*(@````5`(BU$4BY*8@````5`0P[@!````PXGV
+MBT0D!(M0%(N"5)D``(/(`8F"5)D``,.0BT0D!(M`%(N`')P``"7_````PY"+
+M1"0$BT`4BX!8@```@^`'PXUV`(M$)`2+4!2+1"0(@^`'B8)8@```PXUV`%57
+M5E.+?"04BVPD&(G[BT0D'`^W0`(EX`$``#W`````="H]P````'\+/:````!T
+M%.LBB?:^`````#U``0``="#K$HGVO@$```#K%9"^`@```.L-D+@`````Z;L`
+M``")]@^WC'-X"```#[>$<WX(``#!X`8)P0^WA'.$"```P>`,"<$/MX1SB@@`
+M`,'@$@G!#[>$<Y`(``#!X!@)P0^WE'.6"```#[>$<YP(``#!X`8)P@^WA'.B
+M"```P>`,"<(/MX1SJ`@``,'@$@G"#[>$<ZX(``#!X!@)PH/]`70/@_T!<AJ#
+M_0)T">L+C78`B<KK#(G1ZPBX`````.L>D(FK6!D``(M'%(F(8)D``(M'%(F0
+M9)D``+@!````6UY?7<.)]K@!````PXGV5U93BWPD$(MT)!2)^X/^"'86@^P(
+M:/__``!7Z/S___^#Q!`Y\',2D,>#A!D``/____^X`````.LC@^P(5E?H_/__
+M_XM7%(F"<!```(/$$(FWA!D``+@!````B?9;7E_#@^P4BU0D&(M"%(N`<!``
+M`"7__P``4%+H_/___X/$',-55U93@^P4BVPD*&C_/P``5>C\____@\00.T0D
+M)',1QX6(&0``_____[@`````ZSR+=12+GA2```"!XP#`__^#[`C_="0L5>C\
+M____)?\_```)PXF>%(```(/$$(M$)"2)A8 at 9``"X`0```)"#Q`Q;7E]=PX/L
+M%(M4)!B+0A2+@!2````E_S\``%!2Z/S___^#Q!S#55=64X/L%(ML)"AH_S\`
+M`%7H_/___X/$$#M$)"1S$<>%C!D``/____^X`````.M`BW44BYX4@```@>/_
+M_P#`@^P(_W0D+%7H_/___\'@$"4``/\_"<.)GA2```"#Q!"+1"0DB86,&0``
+MN`$```")]H/$#%M>7UW#@^P4BU0D&(M"%(N`%(```"4``/\_P>@04%+H_/__
+M_X/$',.0@^P4BT0D&/^PL`$``%#H_/___X/$',.0BU0D!+@`````@WPD"`9T
+M%("Z(0@```!T"X.Z=!D```%W`K`!PXUV`%.+7"0(_W0D#%/H_/___X/$"(7`
+M#X2R````BT,4QX!PF```'P```(M#%,>`=)@```T```"+0Q3'@'B8```,````
+MBT,4QX#PF0```P```(M#%,>`])D```4```"+4Q0/MX.L`0``)?````"#^#`/
+MG,`/ML"-!(44````B8+XF0``BU,4BX(<@```)7_`__\,@(F"'(```(M#%,>`
+M!($``#T```"+4Q2+ at A!```"#R`*)@A!```"+4Q2+ at A!````-`````XF"$$``
+M`.MGD(M#%,>`<)@``!\```"+0Q3'@'28``!_````BT,4QX!XF```#@```(M#
+M%,>`\)D```P```"+0Q3'@/29``#_````BU,4#[>#K`$``"7P````@_ at P#YS`
+M#[;`C02%%````(F"^)D``%O#4XM<)`C_="0,4^C\____@\0(A<`/A+(```"+
+M4Q2+ at A!````E_____(F"$$```(M3%(N"$$```(/@_8F"$$```(M#%,>`!($`
+M``$```"+4Q2+ at AR````E?\#__PV`#P``B8(<@```BT,4QX!PF```'P```(M#
+M%,>`=)@``'\```"+0Q3'@'B8```.````BT,4QX#PF0``#````(M#%,>`])D`
+M`/\```"+4Q0/MX.L`0``)?````"#^#`/G,`/ML"-!(44````B8+XF0``6\.)
+M]E.#[`B+3"00BT0D%(M<)!B#^!`/A[,```#_)(5`10``@_L"=!:#^P)R(X/[
+M!'(H at _L%=AF#^W]T%.L<9H.YJ`$```09P(/@#>F.````N`````#IA````+ at -
+M````ZWV#N6 at 9````#Y3`#[;`ZVZX`````.MG@[FH&0````^4P`^VP.M8N```
+M``"%VW1/N`P```"#^P%U18M!%(N`"*(``/;$(`^4P`^VP.LQN`````"%VW0H
+MN`````"#^P%U'H.Y;!D````/E,`/ML#K#_]T)!Q34%'H_/___X/$$(/$"%O#
+M4X/L"(M<)!"+1"04BU0D'(/X!70S at _@%=PJ#^`)T$>M_C78`@_ at +=$>#^!!T
+M6^MPA=(/E<`/ML")@V at 9``"X`0```.MQC78`BT,4BX@(H@``A=)T!X#-(.L%
+MB?:`Y=^+0Q2)B`BB``"X`0```.M'D(/B!HF3R`$``(M#%(F02(```+@!````
+MZRV%T@^5P`^VP(F#;!D``+@!````ZQB)]H/L#/]T)"Q2_W0D+%!3Z/S___^#
+MQ""#Q`A;PY"#[!3_="0L_W0D+/]T)"S_="0L_W0D+/]T)"SH_/___X7`#Y7`
+M#[;`@\0LPU93@^P$BW0D$(-\)!0`=&"+1A3'@`1`````````@^P,:@KH_/__
+M_[L*````@\00D(M&%(N`$$```*D```$`="*#[`QHR````.C\____BT84QX`$
+M0````````(/$$$MUT.L&A=MU"HGVN`````#K&I"+5A2+@@2````E___[_XF"
+M!(```+@!````@\0$6U[#D(M,)`2+412+@@2````-```$`(F"!(```(-\)`@`
+M=`V+013'@`1```````$`PXUV`%.+7"0(BTPD$(M3%(N"!(````T```0`B8($
+M@```@WPD#`!T$8M3%`^WP0T```(`B8($0```6\.05U93BU0D$(M<)!2+3"08
+MBT0D'(G6OP$```"#^P-T)8/[`W<(@_L"=`KK-9"#^P1T'^LM@^P(45+HR_[_
+M_XG'@\00ZR114NA-____@\0(ZQ@/M\!045+H;?___X/$#.L(N`````#K"9")
+MGE`9``")^%M>7\.+1"0$BT`4BX`$0```)0```P#!Z!##B?:+1"0$BT`4BX`0
+M0```P>@0@^`!P[@`````PXGVN`````##B?:X`````,.0D%.#[`B+1"04 at _@$
+M=#N#^`1W#H/X`70I at _@"=#SK2HGV at _@@=#.#^"!W"H/X"'0 at ZS>-=@`]``$`
+M`'0DZRN-=@"[`````.LID+L`````ZR&[`````.L:B?:[`````.L1NP````#K
+M"HGVN`````#K$Y"#[`A3_W0D'.C\____B=B#Q!"#Q`A;PY"+1"0$BT`4BT`,
+MPY"+1"0$BU`4BT0D"(E"#,.0BT0D!(M`%,=`"`0```##D(/L#(M4)!"+0A3'
+M0`@@````:@!J!&H(4NC\____A<`/E<`/ML"#Q!S#C78`4X/L%(M<)!R+4Q2+
+M at DB```"#X-^)@DB```!3Z/S___^)'"3H_/___X/$&%O#C78`@^P8BTPD'(M1
+M%(N"2(```(/(((F"2(```%'H_/___X/$',.0BTPD!(M1%(M$)`B)@D"```"+
+M412+1"0,B8)$@```PY!3BU0D"(M,)`RX`````(/Y/W="@_D?=B"+4A2+FD2`
+M``"#Z2"X_O___]/`(=B)@D2```#K&XUV`(M2%(N:0(```+C^____T\`AV(F"
+M0(```+@!````6\.04XM4)`B+3"0,N`````"#^3]W0H/Y'W8 at BU(4BYI$@```
+M@^D at N`$```#3X`G8B8)$@```ZQN-=@"+4A2+FD"```"X`0```-/@"=B)@D"`
+M``"X`0```%O#D(M$)`2+0!2+D#R```"+@`R!``"H('0#@,X"J0```@)T`X#.
+M`8G0PY!3BUPD"(M,)`R+4Q0/ML&)@CR```"Z`````/;%`G0"LB#VQ0%T!H'*
+M```"`HM#%(F0#($``(72=`^+4Q2+0C2#R!")0C3K#9"+4Q2+0C2#X.^)0C1;
+MPXGVBU0D",=""`````"+1"0,)?\/``")0 at SV1"00('0&@,P at B4(,QT(4````
+M`,="$`````"X`0```,-64X/L!(M,)!"+="04B?.+1"0<N@\```#V1A0!#X3G
+M````]D`4`745BT$4BT`,N@\````[1"08#X3,````9HM#$"7_#P``9HE&((M#
+M%"4``/]_P>@09HE&(L9&)`"+0Q2H`G50J`1T",9&)`'K1HGV]D,4$'0F@$XD
+M`@^V0Q6(1B6#N:@9````=2J#[`B-1B!04>C\____@\00ZQCV0Q0(=`:`3B0(
+MZPSV0Q0@=`:`3B00B?:+0Q`E``#P#\'H%(A&)HM#%/;$`70.)0#^``#!Z`F(
+M1B?K!9#&1B?_BT,0)0"`#P#!Z`^(1BB+0Q`E````\,'H'(A&*8M#$,'H#(/@
+M`8A&*KH`````B="#Q`1;7L.0D)!55U93@^P\BWPD4(ML)%R)?"0LO@````"+
+M5"18#[="`HG"P>H'P>@(,="Z#````*@!#X0-"```BTPD6`^W00*)PL'J!L'H
+M!3'0N at P```"H`0^$[@<``&H`:@%J`E?H_/___X/$$+H`````A<`/A.('``"#
+M[`C_="1 at 5^C\____B40D.(/$$+H,````A<`/A+$'``"#?"14!G0A at WPD5`9W
+M"8-\)%0!=PGK$8-\)%0(=`JZ#````.F)!P``QT0D)`````"%[70=BT<4BX!`
+M$0``B40D)(/L"/]T)#!7Z-,,``"#Q!"+1Q2+@%B```")1"0 at A<!U",=$)"`!
+M````BU<4BX($@```)0````*)1"08BX(00```)6``_@")1"0<BYH40```B5PD
+M-(N2&$```(E4)#"#[`C_="1<5^C\____B3PDZ/S___^#Q`C_="1 at 5^C\____
+M@\00N@,```"%P`^$X`8``(M4)%@/MT(")?`!```]0`$``'14/4`!``!_)CW`
+M````='P]P````'\,/:````!T7.F-````/=````!T=.F!````/<`(``!T5CW`
+M"```?PD]4`$``'0DZVH]0`D``'0)/5`)``!T%.M:QT0D%`$```#'1"00`0``
+M`.M2QT0D%`(```#'1"00`0```.M`QT0D%`,```#'1"00`@```.LNQT0D%`0`
+M``#'1"00`@```.L<QT0D%`4```#'1"00`@```.L*N at P```#I%`8``(M'%,>`
+M`)@```<```"[`````(GVC01;BT\4BQ3%H$4``(E4)`R+5"04C01"BP2%H$4`
+M`(M4)`R)!!%&]\8_````=0V#[`QJ`>C\____@\000X/[&':^NP````"0BPS=
+M`$@``(7M=`V- at 0"`__\]_P\``'8DBU<4BP3=!$@``(D$"D;WQC\```!U#H/L
+M#&H!Z/S___^#Q!"00X'[Q@```':[5O]T)!3_="0<5XM,)#S_D<P6``"#Q`C_
+M="1 at 5^C\____@\009H._J@$``$$/AMT```"+1Q3'@"R8```"H`(`BUPD6&:!
+M.[0)=2F+1"0L#[:((`@```^W@"H(```IP;AG9F9F]^F)T-'XP?D?B<-F*<OK
+M%HM,)"P/MI$@"```N&=F9F;WZHG3T>N+5"18#[="`B70````/<````!U+XM/
+M%(M$)"P/MI`@"```]]K!X@:!XL`/``")V,'@$O?8)0``_``)PHF13)D``.L-
+MBT<4QX!,F0```````(M7%(N"**(``(#D_8F"**(``(M7%(N"**(``"7_`_[_
+M@,P(B8(HH@``BT<4QX!@@```#P```&:#OZH!``!"=@V+1Q3'@%2B````````
+MBT<4QX!XF```#@```(/L!(U$)#Q0_W0D,%?H_/___X/$$+H#````A<`/A!X$
+M``"-1"0X4`^W1"084/]T)#!7BU0D//^2V!8``(/$$+H#````A<`/A/0#``"+
+M3"18]D$"0'0-@^P(45?H_/___X/$$(/L"/]T)#!7Z/S___^#Q!"Z`P```(7`
+M#X3``P``A>UT#8M'%(M<)"2)F$`1``"+3Q2+1"0L#[:07!8```^V@%T6``#!
+MX`@)PHM<)"P/MH->%@``P>`0"<(/MH-?%@``P>`8"<*)D0"```"+3Q0/MI-A
+M%@``P>((#[:#8!8```G0"T0D&(G"@<H``(``@[MH&0```'0(B<*!R@``@`B)
+MD02```"#[`C_="1<5^C\____BT<4QX#@@```_____X/$"(M'%,>`Y(```/__
+M__^+5Q2+ at A!````+1"0DB8(00```BT<4BU0D/(F0%$```(M'%(M,)#B)B!A`
+M``"+1Q2+7"0HB9A8@```BT\4BT0D-`^VD&(6```/MH!C%@``P>`("<*+7"0T
+M#[:#9!8``,'@$`G"#[:#918``,'@&`G"B9$(@```BT\4#[:39Q8``,'B"`^V
+M at V86```)T(F!#(```(M'%,>`@````/____^+1Q3'@!B`````!P``_W0D,%?_
+MD]06``"#Q!"Z`P```(7`#X1)`@``BT<4BX`4F0``B<*!XO\_``"+1"18]D`"
+M('0/P>("N*.++KKWXL'J!.L*N,W,S,SWXL'J`XM'%,>`')@```$```"#[`R-
+M0F10Z/S___^+5Q2+ at F"8``"#R`.)@F"8``"#Q!"+5"18#[="`B6@````/:``
+M``!T/XM,)"R#N5P9```"=#*+5Q2+ at B"9``"`S/")@B"9``"+5Q2+ at B"9```-
+M```!`(F"()D``,>!7!D```$```#K#HM<)"S'@UP9````````NP````"^`0``
+M`(TLG0````"+5Q2)\(C9T^")A"H`$```0X/["7[CBUPD+,>#+"\```````"[
+M`````&:#O[P!````=!F#[`A35^C\____@\000P^WA[P!```YV'_GBT0D+,>`
+M:!8``&4)"`"#?"14!G4*QX!H%@``91D(`(M7%(M,)"R+ at 6@6``")@J````"+
+M5Q2+ at JP````-```'`(F"K````(/L#%?H_/___X/$$(7`=`R#[`Q7Z/S___^#
+MQ!!J`&H!:&"8``!7Z/S___^#Q`B+1Q3'@`B!``!2````_W0D7%?H_/___XM7
+M%(N"((```"7__W_^B8(@@```@\00BUPD+(.[A!D``/]T$H/L"/^SA!D``%?H
+M_/___X/$$(M$)"R#N(@9``#_=!*#[`C_L(@9``!7Z/S___^#Q!"+5"0L@[J,
+M&0``_W02@^P(_[*,&0``5^C\____@\00@[_(`0```'0/BU<4BX?(`0``B8)(
+M@```BTPD5(F/L`$``+H!````ZQ&0BUPD8(,[`'0"B1.Z`````(G0@\0\6UY?
+M7<.)]E.+7"0(BU0D#(M#%(N(!(```('A___\_X/Z`713 at _H!?P:%TG0LZU&#
+M^@9T!X/Z"'0^ZT6+4Q2)R`T```$`B8($@```BU,4BT(4@^#?B4(4ZR>+4Q2)
+MR`T```(`B8($@```BU,4BT(4@\@@B4(4ZPF+0Q2)B`2```!;PY"#[!1J`O]T
+M)!SHP@,``(/$',.)]E.#[`B+7"00:@!J`6H"4^C\____@\00N@````"%P'00
+M@^P(:A-3Z)$#``")PH/$$(G0@\0(6\.055=64X/L%(M<)"B+="0L:A-3Z&T#
+M``"#Q!"Z`````(7`#X1=`0``:@!J`6H"4^C\____@\00N@````"%P`^$00$`
+M`(/L"&H`4^@V`P``@\00N@````"%P`^$)@$``(7V#X09`0``#[>#K`$``"7P
+M````@_ at O?B6]"`````^W1@*H('41)=````"YZ@```#W`````=2JYZP```.LC
+MO0`````/MT8"J"!U$270````N:H````]P````'4%N:L````/MT8"J$!T%:@@
+M=0PET````#W`````=06#S03K"?9&`D!U`X/-`?9&`P%U`X/-`@^W1 at +!Z`2#
+MX`&#^`$9__?7@^<#BT,4BY!\F```#[=&`J@@=0PET````#W`````=3&+0Q2)
+MN`28``"+0Q2)J`"B```YRG1*BT,4B8A\F```@^P,:"P!``#H_/___X/$$.LO
+M.<IT&8M#%(F(?)@``(/L#&@L`0``Z/S___^#Q!"+0Q2)N`28``"+0Q2)J`"B
+M``"Z`0```(G0@\0,6UY?7<.)]E575E.#["2+;"0XB6PD(/]T)#Q5Z/S___^)
+MQX/$$+@`````A?\/A+X!``"+1"08@[A<&0```0^%Z````(M%%(N`()D``*D`
+M``$`#X74````BU0D&,>"7!D```````"[`````)"+112+L!"<``"+B!2<``"+
+M@!B<``")1"04A?9T!(7)=1J+512+ at B"9```-```!`(F"()D``$.#^PE^Q8GP
+MT>B)RM'J`=#!Z0:)PL'J!P^$Q0```(/Y`0^.O````(I$)!3WV`^^P(G3F??[
+MB40D#(/@/XE$)!")\)GW^8G!@^$?BUT4BT0D$,'@!8N3()D```G0"<B`S`B)
+M at R"9``"+5"08QX)<&0```@```,='#`$```"*7"00B%\0B$\1ZUN-=@"+5"0T
+M#[="`B6@````/:````!T1(M<)!B#NUP9```"=3>#?PP`=3&+512+ at B"9``"`
+MS/")@B"9``"+512+ at B"9```-```!`(F"()D``,>#7!D```$```"0@^P(5U7H
+M=@$``(/$$+@`````]D<"`G55BU44BX)@F```@\@"B8)@F```BT0D-`^W4`+V
+MQ@%U&0^WA:P!```E\````(/X+WX@]L)`=!N-=@"#O:0!```'=`^#[`Q5Z/H4
+M``"#Q!"-=@"X`0```(/$'%M>7UW#C78`5U93BWPD$(MT)!2)\(7V=06X____
+M_XG#BT<4BU`,B;``0```@^P,:@_H_/___X/C`X/F`U93:`!```!7Z/S___^)
+MPX/$(/?&`0```'4FBT<4QT`4`````&H`:@%J`E?H_/___X/$$(7`=`F+1Q2+
+M@,````")V%M>7\.)]HM$)`2+0!2+@&28``#!Z!,E_P$``/;$`70%-0#^__^8
+MPXUV`(M,)`R+5"0$BT0D"`^W0`(EX`$``#W`````=#`]P````'\)/:````!T
+M%NLL/4`!``!U)6:+ at EH(``!FB0'K(9!FBX)<"```9HD!ZQ1FBX)>"```9HD!
+MZPBX`````,.)]K@!````PXGV5U93@^P$BW0D%(M\)!B+1A2+@&"8``"[````
+M`*@"=2A6Z/S___^)PXU$)`905U;H9/___X/$$(7`=`UF.UPD`GX&9H-/`@*0
+M9HE?$@^_PX/$!%M>7\.)]E575E.#[`R+1"0HQT0D"`````"->/_![P-(@^`'
+MB00DBW0D)+T`````A?9^9XM$)"S!X`.)1"0$BQPD`?.#^PAV!;L(````N`$`
+M``"(V=/@2+H!````B at PDT^)*,="*3"0$T^"+5"0@(P2ZT^B*#"33Z(GIT^`)
+M1"0(B=@K!"0!Q8L$)(UT!OC'!"0`````1X7V?Z2#[`C_="0L_W0D%.C\____
+MB40D&(M$)!B#Q!Q;7E]=PU575E.#[$R+;"1 at B>Z+1"1D#[=X`L'O!X/G`0^W
+M0`(E\`$``#U``0``=&$]0`$``'\R/<`````/A*,````]P````'\0/:`````/
+MA(0```#IF````#W0````#X2!````Z8@````]P`@``'1U/<`(``!_"CU0`0``
+M=!/K<9`]0`D``'0)/5`)``!U8HGVQT0D/``````/MX6L`0``)?````"#^"]_
+M4X.]I`$```=T2HM-%(N11)D``(/BQXN&6!8```^_`,'@`X/@.`G"B9%$F0``
+MZR7'1"0\`0```.L;C78`QT0D/`(```#K#HGVN`````#I#0,``(GVBTT4BX$0
+MF0``)0;\__^+7"0\#[>47G((``#!X at 0)T(/(`8F!$)D``(/L!/]T)&C_ME at 9
+M``!5Z/S___^+510/OX1>6@@``"7_`0``@,P"B8)HF0``@\009H&^``@``/]/
+M=D*+1"1D]D`"$'0X9HN$?M0(``"*G#?<"```BI0WW@@``(A4)"!FBXQ^V`@`
+M`&:)3"009HN4?N`(``!FB10DZSJ-=@"+3"0\9HN$3C`(``"*G#%4"```BI0W
+M5P@``(A4)"!FBXQ^-@@``&:)3"009HN4?L`(``!FB10DBTT4BY%$F```@>)_
+MP/__P>`')8`_```)PHF11)@``(M-%(N!4)@``+``#[;3"=")@5"8``"+312+
+MD5"8```P]HI$)"#!X`@E`/\```G"B9%0F```BTT4BY%(F```@>+_#_S_BT0D
+M$,'@#"4`\`,`"<*)D4B8``"+712+3"0\#[>43D@(``")T,'@&,'B$`G0#[>,
+M3DX(``")RL'B"`G0"<B)@S28``"+312+D2B8```P]HM<)#P/MX1>/`@``,'@
+M"`G"B9$HF```BTT4BY%DF```@>+_#_C_#[>$7D((``#!X`PE`/`'``G"B9%D
+MF```NP(```!F@;X`"````C!W&6:!O:(!```B$'4RBT0D9/9``D!T*+,(ZR2+
+M5"1D9HL"@^`?=!B#Z`IF at _@,=@^+3"0\#[>$3K0(```!PY"+312+D229``"`
+MX@&-!!LE]P````G"B9$DF0``BUPD9(-[#`!T"@^^0Q`/OEL1ZQ`/MX1^1 at D`
+M``^WG'Y*"0``BTT4BY$@F0``@>(?^/__P>`%)>`'```)PHF1()D``(M-%(N!
+M()D``(/@X(G:@^(?"=")@2"9``"+512+ at B"9``"`S`B)@B"9``!F@;X`"```
+M`$!V08M4)&0/MT(")=`````]T````'4+9H&^``@``/]/=B*+312+D0RB``"!
+MXO__`_^+!"3!X!(E``#\``G"B9$,H@``9H&^``@```!0=@V+113'@."9````
+M````N`$```"#Q$Q;7E]=PY!75E.+="00BU0D%`^W0 at +!Z`2#X`&#^`$9P(/@
+MV(V$@)`!``#!X!B)P]'K#[<2B=B)T;H`````]_&)P[\?````B=B)^=/HJ`%U
+M`T]U\[@F````*?B)Q[@7````B<(I^K`!B-'3X`'8NA@````I^HC1T^B+7A2+
+MDQ28``"!XO__`0#!X!$)PHF3%)@``(M>%(N3%)@``('B_Q_^_XGXP>`-)0#@
+M`0`)PHF3%)@``%M>7\.-=@"#[`R+5"00BT0D%(/X/'8%N#P```!FB8+,`0``
+M@^P$C40D#%#_LOP'``!2Z/S___^#Q!S#55=64X/L%(ML)"B+7"0LB>__M0 at O
+M``#_M00O``#H_/___X/$"&H at C84,+P``4.C\____9HN5S`$``(/$$&:#^CQ^
+M!;H\````9H/Z.W\*N0````!FA=)U#HN%T`$``&:+C``X3@``@^P(C40D$E"-
+M1"044`^_PE`/O\%04U7H9@(``(/$(+H`````A<`/A$H"``"#[`S_="0T4XU$
+M)!Y0C40D(%!5_Y?<%@``@\0 at N@````"%P`^$(0(``(.]I`$```=T"&:#ARHO
+M```$O@````!FBX>`&0``9@&$=PPO``!F@[QW#"\``#]V"F;'A'<,+P``/P!&
+M at _X/=MUF@[\L"````0^'I@```&:#O:H!``!!=UP/MT,")=`````]P````'5,
+M9H$[M`EU(P^VCR`(```/MX<J"```*<&X9V9F9O?IB=#1^,'Y'V8IR.L2#[:7
+M(`@``+AG9F9F]^J)T-'H@^P(#[?`4%7H4`8``(/$$+X`````C1RU`````(M-
+M%(N'!"\```^W5+`"P>(8@<H``/\`#[<$L,'@"`S_)?__```)PHF4&8"A``!&
+M at _X??L6+310/MY<2+P``@^(_P>(8#[>'$"\``(/@/\'@$`G"#[>'#B\``(/@
+M/\'@"`G"#[>'#"\``(/@/PG"B9$TF0``BTT4#[>7&B\``(/B/\'B&`^WAQ at O
+M``"#X#_!X!`)P@^WAQ8O``"#X#_!X`@)P@^WAQ0O``"#X#\)PHF1.)D``(M-
+M%`^WER`O``"#XC_!XA@/MX<>+P``@^`_P>`0"<(/MX<J+P``@^`_P>`("<(/
+MMX<<+P``@^`_"<*)D32B``"+310/MY<H+P``@^(_P>(8#[>')B\``(/@/\'@
+M$`G"#[>')"\``(/@/\'@"`G"#[>'(B\``(/@/PG"B9$XH@``BU44@[]L&0``
+M`1G`@^#`@\!\B8(\F0``9HN'#"\``&:)A<X!``"Z`0```(GVB="#Q`Q;7E]=
+MPXGV55=64X/L5(M$)'!FB40D)HM4)'1FB50D)(MT)&B-O at PO``!FQT0D(CP`
+M9L=$)"`\`/]T)&Q6Z/S____1X&:)1"0FBXPDA````&;'`<3_BX0D@````&;'
+M`#P`@\0(_W0D;%;H_/___XA$)"6[`````(/$$&:#O at 0)````#X2'````#[9L
+M)!6)ZH/B^(E4)!"09H.\7 at 8)````=&%F#[9$)!5F.81>!@D``'01#[>$7 at 8)
+M``"#X`<,X#G%=4")V,'@!HV$,%`-``"#[`A0BTPD<`^W`5#H2P4``(/$$(%\
+M)!#@````=0YF.40D&G8/9HE$)!KK"&:)1"0:ZPV00P^WA at 0)```YV'^(BU0D
+M9`^W0@(ET````#W`````#X6F````@&0D%0>`3"05`;L`````9H.^!`D````/
+MA),````/MFPD%8GI@^'XB4PD#)!F@[Q>!@D```!T868/MD0D%68YA%X&"0``
+M=!$/MX1>!@D``(/@!PS at .<5U0(G8P>`&C80P4`T``(/L"%"+5"1P#[<"4.B/
+M!```@\00 at 7PD#.````!U#F8Y1"08=@]FB40D&.L(9HE$)!CK&9!##[>&!`D`
+M`#G8?XCK"F:+3"0:9HE,)!B+1"1D]D`#`70(BH8<"```ZP:*AAT(``"#[`0/
+MOL!0_W0D;/]T)&SH_/___XC#BU0D=`^W0@*#Q!"H0`^$I@$``"70````/<``
+M``!U)H/L#(U$)#Q0#[>&&`T``%"-AAH-``!04O]T)'SH&@4``(/$(.LG@^P,
+MC40D/%`/MX;&#```4(V&R`P``%#_="1\_W0D?.CQ!```@\0@#[=4)!8/OL,I
+MP@^W1"0:.<)^`HG"B=&+1"1D]D`"$'1$9H&^``@````P=A(/MX8."```#[_2
+M.=!^`HG0B<%F@;X`"```_S]V'(M4)&3V0@*`=!(/MX80"```#[_1.=!^`HG0
+MB<$/MU0D-@^_P3G"?@*)PF:+1"0>T>")T68IP7D%N0````!F.TPD''X$BTPD
+M'&:)3PAFB4\&9HE/!&:)3P)FB0^+1"0T9CG(=@*)R&:)1PIFBT0D,F8[!W8#
+M9HL'9HE'#(M$)#!F.P=V`V:+!V:)1PYF@;X`"```_S]V20^_T8M$)&3V0`*`
+M=`T/MX84"```.<)\#>L/#[>&$@@``#G"?02)R.L:BU0D9/9"`H!T"6:+AA0(
+M``#K!V:+AA((``!FB4<>ZP=FBP=FB4<>9HM'#HM,)'!FB0%FBP>+5"1T9HD"
+M#[\"B89\&0``BTPD9`^W00*H('40)=`````]P`````^%Y0```(/L#(U$)"Q0
+M#[>&.`T``%"-ACH-``!0_W0D?/]T)'SH80,```^W3"0V#[[#*<$/MT0D.(/$
+M(#G!?@*)P0^W5"0F#[_!.<)^`HG"9HM$)![1X(G19BG!>06Y`````&8[3"0<
+M?@2+3"0<#[=$)"8/O]$YT'X"B=!FB4<0#[=$)"0/O]$YT'X"B=!FB4<29HE'
+M%`^W1"0B#[_1.=!^`HG09HE'%F:)1Q@/MUPD(`^_P3G#?@*)PV:)7QIFB5\<
+M#[?3BTPD<`^_`3G"?0-FB1D/MU<2BTPD=`^_`3G"?@EFBT<29HD!B?:+5"1T
+M#[\"B89D&0``N`$```"#Q$Q;7E]=PXGV55=64X/L0(ML)%1FBX4H"```9HE$
+M)`YJ((V%#"\``%"-1"0<4.C\____9L=$)!X(`(/$$`^W1"0.9HM4)`IF*51$
+M$+X`````9L=$)`P```^W?"0.B7PD!&:#?'P0`'D(9L=$?!```)!F at _X(=0J^
+M#P```.M0C78`BTPD!`^_5$P0#[?>#[>$70PO```YPG4T9H.\70PO````=0=F
+M_T1,$.L69H-\)`PR=@=F_T1\$.L'9O],?!")]KX`````9O]$)`SK`49F at _X/
+M=HT/MT0D#F:#?$00/WX'9L=$1!`_``^W1"0.#[><10PO```K7"14>0:[````
+M`)`/MT0D#@^_3$00BY4$+P``9HL$6F:)!$IF_T0D#F:#?"0.#@^&$____V;'
+M1"0."``/MU0D#F:+1%009HF$50PO``!F_T0D#F:#?"0.#G;A@\0\6UY?7<.0
+M5U93@^P at BUPD-(M\)#"Z`````)!F at SS3`'0/9HL$TV:)1%000H/Z!W[JB=:#
+M[`R-1"0:4(U$)!Q0#[?"4(U$)"A0#[?'4.C\____N@````"#Q"`Y\GT=BT0D
+M$&8[1"0,=!*+1"0,B?9".?)]!V8Y1%00=?2+1"0,9CM$)`YU!68Y^'0,N#P`
+M``"#?-,$`'0%9HM$TP(/M\"#Q"!;7E_#D%575E.+;"04BTPD&(M\)!R+7"0@
+MBW0D)`^WPP^WU@^OPKH`````A<!T88G89CG/=%</M\4/M\DIR(T$@(T$@,'@
+M`@^WURG*B=&9]_F)PHG89H72>#.)\&:#^F1_*P^_T@^WS@^ORKAD````*=`/
+MM],/K\(!P;@?A>M1]^F)T,'X!<'Y'V8IR)`/M]")T%M>7UW#B?955U93@^P\
+MBVPD6(M\)%RZ``````^WQXG!@_@`?A2)]HT$DF:+1$4(9HE$5"!".=%_[H/L
+M#(U$)"I0C40D+%`/M]]3C40D.%"+5"1P#[<"4.C\____O@````!FQT0D.@``
+MN@````"#Q""#^P!^*XG8BWPD'&:+3"0>C78`9CE\5"!U!6:)5"0:9CE,5"!U
+M!8G6ZP:00CG0?^,/M_:--+;1Y@^W3"X&#[=<)!J-')O1XP^W1"L&B40D#`^W
+M?"0>#[=4)!R)5"04BT0D5`^W$%'_="005_]T)"!2Z([^__^#Q!2+5"1 at 9HE"
+M!@^W1"X$B40D#`^W5"L$BT0D5`^W"/]T)`Q25_]T)"!1Z%[^__^#Q!2+5"1@
+M9HE"!`^W1"X"B40D#`^W5"L"BT0D5`^W"/]T)`Q25_]T)"!1Z"[^__^#Q!2+
+M5"1 at 9HE"`@^W!"X/MQ0KBUPD5`^W"U!25_]T)"!1Z`?^__^+5"1T9HD"@\10
+M6UY?7<-75E.+3"04BWPD'(MT)"`/MU0D$(T$DHT$@(T4A0`````/MUPD&(T<
+M60^W`8T$@(T$@(T$A?;___\YT'8+9HL!9HD&9HD'ZW0/MT/^C02`C02`C02%
+M"@```#G0<R=FBT/^9HD&9HD'ZU-FBP%FB09FB0?K2&:+`6:)!V:+00)FB0;K
+M.9`YV7,T#[<!C02`C02`P>`"*="#^/=\!8/X"7[)#[=!`HT$@(T$@(T$A?;_
+M__\YT'>_@\$".=ERS%M>7\.+3"0$C9$\%@``#[>!K`$``"7P````@_ at O?C&A
+MY$\``(F!/!8``(T$P(T$A>A/``")0AS'0A@!````QT(,%````,="$%4```##
+MC78`H61.``")`HT$P(T$A6A.``")0AS'0A@!````QT(,%````,="$",```##
+MB?955U93@^P,BU0D((M\)"0/MX*L`0``)?````"#^"]^2&H`:B1J`8/L#&H'
+M4O^2T!8``(/$%%#H,>W__[T`````OFL```"Y`````+MK````@\00 at _@!=7-F
+MOE,`LU/'1Q`W````ZV2)]FH`:B5J!H/L#&H'4O^2T!8``(/$%%#HZ>S__[T`
+M````@\00OC(```"#^#]T`XUP!(GI at _@_=`6Y0````(U9,HGJ at _@_=0:-512-
+M=@")5PR#^#]U"(U#\>L&C78`C4,%B4<0BU<$N``````YZG($.?)V#3G*<@0Y
+MVG8%N`$```"#Q`Q;7E]=PY"+1"0$#[^0@!D```.0?!D``(M(%,'B"8'B`'X`
+M`(#.@(F1,)D``,>`8!D```$```##C78`5U93BWPD$(G[C;<\%@``N`````"#
+M?A@`#X3@````@[]@&0```0^%S0```(M'%(N`,)D``*D`@```#X6Y````B<+!
+MZAF)5 at 0E``"``<'H%X/X`G4<9H._J@$``$%V#@^WAR@(```!T(E&!.L$@T8$
+M!0^WAZP!```E\````(/X+WXC@^P,5^B2`0``@\00BT8$.T84<@@K1A2)1 at 3K
+M!\=&!`````#'@V`9````````@^P(5E?H)/[__X/$$(7`=3F#[`A65^@[````
+M@\00A<!T*(/L"%97Z$8```"#Q!"%P'X7QX-@&0```@```,>#7!D```````"-
+M=@"+ at V`9``!;7E_#B?:+3"0(N`````"+400[40QV!3M1$'(%N`$```##5E.+
+M7"00BT0D#`^W@*P!```E\````+[@3P``@_ at O?P6^8$X``(L#C03`C42&"(E#
+M'(M#!#M#$')7NO____^#.P`/A*T```"+0P2)0P@[0Q!R-H,[`'0QD(L32HD3
+MC132C126BTL<BT(8*T$0T>"+2P at IP8E+"(/""(E3'#M+$'('@SL`==*)]KH!
+M````ZV60BT,$N@`````[0PQW5XL&2+K^____.0-T2XM#!(E#"#M##'<XBP9(
+M.0-S,9"+$T*)$XT4THT4EHM+'(M"&"M!$-'@BTL(*<&)2PB#P at B)4QP[2PQW
+M!XL&2#D#<M"Z`@```(UV`(G06U[#C78`5U93BUPD$(VS/!8``,=&%`````!J
+M`&HD:@&#[`QJ!U/_D]`6``"#Q!10Z/WI__^#Q!"#^`%U68M&'`^_.&H`:B!J
+M!(/L#&H'4_^3T!8``(/$%%#HU.G__X/$$(/_`70:@_\!<@R#_P)T%8/_`W09
+MZQ_'1A0`````ZQ:)1A3K$8U$`/N)1A3K"-'@B484C78`6UY?PU575E.#[!2+
+M="0PBUPD-%;_="0PZ/S___^)Q8U[_\'O`TN#XP>#Q!"%]GYRBT0D,,'@`XE$
+M)`B0C0PS at _D(?@6Y"````+H!````T^)*N`$```"(V=/@2#'"BDPD"-/BB='W
+MT8M$)"`C#+B)3"0$B>B(V=/@BDPD"-/@(=`+1"0$BU0D((D$NHUT'OBY"```
+M`"G9T^V[`````$>%]G^:@\0,6UY?7<.)]E575E.#[!2+5"0L#[="`L'H!(/@
+M`8/X`1G`)?X```"#P`)0_W0D+.C\____B<>]`````(/$$(,X`'X\D(U$;0"-
+M1(<@#[98",'C`HM4)""+<A2#[`QJ``^V0`M0:@Y74NC\____#[?`B80>`(<`
+M`(/$($4Y+W_%BT0D)/9``A`/A:L```"#[`AJ!/]T)"SH_/___XG'O0````"#
+MQ!"#.``/CHH```")]HU$;0"-=(<@#[9&"(T$A0"'``")1"0(BU0D((M:%(/L
+M#&H`#[9&"U!J#E=2Z/S___\/M\"+5"0HB003@\0@@'X)`'0X#[9&"8T$@HE$
+M)`B+1"0 at BU@4@^P,:@$/MD8+4&H.5_]T)#SH_/___P^WP(M4)"B)!!.#Q""-
+M=@!%.2\/CWO___^-=@"#Q`Q;7E]=PU575E.#[!2+?"0HBX=H%@``)?___W]0
+M5^C\____B<6+1Q2+4#")TX'C\`,``,'K!(G>@\00 at WPD)`!T$+ at E````*=C1
+MZ(TT`^L(B?:#^P*#UO\YWG08BT\4@>(/_/__B?#!X`0E\`,```G"B5$P@^P(
+M55?H_/___SG>#Y7`#[;`@\0<6UY?7<-64X/L!(M,)!"+5"04#[>!O`$``+L`
+M````.=!^(X/L!/]T)!R-!%*-!("-A('X%@``4%'H_/___XG#@\00C78`B=B#
+MQ`1;7L-64X/L!(M,)!"+5"04#[>!O`$``+L`````.=!^(X/L!(T$4HT$@(V$
+M@?@6``!0_W0D(%'H_/___XG#@\00C78`B=B#Q`1;7L-55U93@^P,BVPD((M\
+M)"2)ZXV5M`$``(/_`G08 at _\"=P>#_P%T)NM8 at _\#=`^#_P1T$^M,#[=R"$[K
+M39`/MW((@^X"ZT.^`0```.L\O@`````/MT((B<&#^`!^%8T$=HT$@(.\@_P6
+M````=`5&.?%_ZP^W0 at BZ_____SGP='GK"+K_____ZW"0C01VC02`C9R#^!8`
+M`+K_____ at WL$`'57@^P(:CQ3Z/S___^)>P2#Q!"#?"0H`'4LQT,,"P```,=#
+M%`(```#'0QC_____QT,<_P,``&;'0R`*`&;'0R(*`.L3B?:#[`3_="0L5E7H
+M_/___X/$$(GRB="#Q`Q;7E]=PXUV`%.+3"0(BUD4BY'D%@``@>+_`P``BX'L
+M%@``P>`0)0``_P,)PHF3I````(M9%(N1Z!8``('B_P,``(N!\!8``,'@$"4`
+M`/\#"<*)DZ@```"+612+ at ZP````E`/S__XN1]!8``('B_P,```G0B8.L````
+M6\.05U93BWPD$(M,)!0/MX>\`0``O@`````YR'95C01)C02`C9R'^!8``+X`
+M````@WL$`'0]QT,$`````+C^____T\`AA^06```AA^@6```AA^P6```AA_`6
+M```AA_06``!35^@F____O@$```"#Q`B)]HGP6UY?PXGV55=64XMT)!B+?"04
+MBX_\!P``#[>'O`$``+H`````.?`/AL8#``"-!':-!("-G(?X%@``N@$```"#
+M>P0`#X2J`P``@WL8_W4TA<ET%0^W00(EH````+H?````/:````!T!;H/````
+MN`$````YT',0D-'@@\@!.=!R]^L$D(M#&(TLM0````"+5"04BTH4B<*!XO\#
+M``"+0QS!X`HE`/P/``G"BT,4P>`4)0``\`\)PHF4*4`0``"+1"04BT at 4#[=#
+M(L'@!"7P````#[=3((/B#PG0#0`@"`")A"F`$```BU0D%(M"%,>$*,`)````
+M"```@WLD`'1#BTH4BU,D@>+___\`BT,HP>`8"<*)E"G`"```BT0D%(M(%(N$
+M*<`)``")PH/*`8-[*`!T"(G"@<H!`0``B90IP`D``(-[,`!T(HT,M0````"+
+M;"04BU44BT,P)?___P`-`````8F$"@`)``"-#+4`````BT0D%(M0%(M#+"7_
+M_P\`@WLL`'0%#0``$`")A`K`$```@WLL`'0E]D,,0'0?C0RU`````(ML)!2+
+M512+A`K`"0``@,P"B80*P`D``/9##!!T(8T,M0````"+1"04BU`4BX0*`!$`
+M``T``"``B80*`!$``/9##(!T'XT,M0````"+;"04BU44BX0*`!$``(#,`HF$
+M"@`1``"+0P2#^`-T6H/X`W<*@_@"=!/IT0```(/X!`^$J0```.G#````C12U
+M`````(M$)!2+2!2+A!'`"0``#**)A!'`"0``BVPD%(M-%(N$$0`1```-```E
+M`(F$$0`1``#IA@```(T,M0````"+1"04BU`4BX0*P`D``(/(8HF$"L`)``"+
+M%0`````K%0````"+AW`9```IT"L%`````,'@"HML)!2+510-`````8F$"@`)
+M``"+512+A`H`$0``#0``!`")A`H`$0``ZQ^-#+4`````BT0D%(M0%(N$"L`)
+M``"#R"")A`K`"0``]D,X`70AC0RU`````(ML)!2+512+A`H`$0``#0``)`")
+MA`H`$0``]D,,`703N`$```")\=/@"8?D%@``ZQ&)]KC^____B?'3P"&'Y!8`
+M`/9##`%T$[@!````B?'3X`F'Z!8``.L1B?:X_O___XGQT\`AA^@6``#V0PP"
+M=!.X`0```(GQT^`)A^P6``#K$8GVN/[___^)\=/`(8?L%@``]D,,!'03N`$`
+M``")\=/@"8?P%@``ZQ&)]KC^____B?'3P"&'\!8``/9##`AT$[@!````B?'3
+MX`F']!8``.L1B?:X_O___XGQT\`AA_06``!3_W0D&. at S^___N@$```"#Q`B-
+M=@")T%M>7UW#D(M$)`C!X`*+5"0$BU(4BX0"``@``,.)]HM4)`C!X@*+1"0$
+MBT at 4BT0D#(F$$0`(``"X`0```,.0BTPD"(M$)`2+4!2X`0```-/@B8)`"```
+MN`$```##B?964XM4)!#!X@*+1"0,BW`4BX06``H``(G#@^,#=1JX`0```(I,
+M)!#3X(N60`@``(7"=`6[`0```(G86U[#C78`5U93BWPD$(MT)!2+5Q2X`0``
+M`(GQT^")@H`(``"[Z`,``(GV5E?H_/___X/$"(7`=!"#[`QJ9.C\____@\00
+M2W7BBT<4QX"`"````````(7;#Y7`#[;`6UY?PY!55U93@^P,BUPD)(ML)"B+
+M?"0LBW0D,,=$)`@`````QT0D!`````#&1"0#`<9$)`(`@WPD-``/A.0```"#
+M[`B+5"0HBX)H%@``)?___W]04NC\____B<&#Q!"%]G07BD8<@^`!B$0D`XM7
+M$('B_W\``(E4)`B+4Q"!XO]_``"+0P at E``!`@(!\)`,`=6>%P'1CL`"$P'0(
+MBT0D.(E$)`2+1"0(`=`K1"0$.T0D-'=%B=`K1"0$`40D"(7_="*+1Q`E`(#_
+M_XM4)`B!XO]_```)T(E'$/9&'`%U!<9$)`(!@'PD`@!T#H%C"/__OW^!8Q``
+M@/__ at 4L(``"`((!\)`(`=`N%[70'@64(__]_WX/L"%'_="0LZ/S___^#Q!"-
+M=@`/MD0D`H/$#%M>7UW#C78`5U93BW0D,(M<)#B+?"04BU0D&('B_P\``(M$
+M)"3!X!`)PO;#('0&@<H``(``BT0D-,'@&24````>"=#VPP%T!0T````!]L,0
+M=`4-````((E'"(M$)"")PL'B%/;#`G0&@<H````!B5<,BT0D+,'@$"4```\`
+MB4<0BT0D*(E'%(/^_W06B?#!X`TE`.`/``G0B4<, at 4\(````0/;##'1+N`#_
+M`'^*3"0\T_BZ`````*@!=#R)V,'H`X/@`8/X`1G`]]`E````@/;#!'0%#0``
+M0``)1PB+1"1`)?]_```)1Q"+1"0\P>`4"4<4N@$```")T%M>7\.-=@!3BT0D
+M%(M,)!R+7"0DBU0D#(7`=!7!X!0E``#P``E"$(M$)!#!X`4)0A2%R707B<C!
+MX!@E````#PE"$(M$)!C!X`H)0A2%VW02B=C!X!P)0A"+1"0 at P>`/"4(4N`$`
+M``!;PXGV4XM$)!"+3"08BUPD'(M4)`R#?"04`'00"T(,A<EU`X#,$(E"#.LY
+MD(7)=!C'0@@`````B4(,BT,0B4(0BT,4B4(4ZQS'0@@`````@,P0B4(,QT(0
+M`````,="%`````"0QT(<`````,="&`````"X`0```%O#C78`BTPD"(G*N`\`
+M``#V01P!#X1$`0``BT$<)?X?``#1Z&:)02`/MT$:9HE!(L9!)`"+01BH`74>
+MJ`)T!,9!)`'V0A@(=`2`220"]D(8!'0&@$DD!(GVBT(<)0``8`#!Z!6#^`%T
+M((/X`7(/@_@"="F#^`-T-^M'C78`BD(4@^`?B$$EZSF0BT(4)>`#``#!Z`6#
+MR("(027K)8M"%"4`?```P>@*@\B`B$$EZQ*+0A0E`(`/`,'H#X/(@(A!)9"+
+M0APE`.`?`,'H#8A!)HM"&"7P````P>@$B$$GBT(8)0`/``#!Z`B(02B+0APE
+M``!@`,'H%8/X`G0B at _@"=PF#^`%T)NLRB?:#^`-U*XM"$"4````/P>@8`$$H
+MD(M"$"4``/``P>@4`$$HBT(0)0``#P#!Z!``02B+0A at E`/```,'H#(A!*0^V
+M0A^#X`&#^`$9P(/``HA!*K@`````PXGVBT0D!(M,)`B+$2.0+"\``(D1]](A
+MD"PO``##D%.#[!"+7"08C8.H%@``4%/H_/___XM#%,>`)($```````"+0Q3'
+M@"B!````````BT,4QT!``````(M#%,>`,($``````@"+0Q3'@#B!```````"
+M@\086\-3@^P0BUPD&(M#%,=`0`8```"- at Z@6``!04^C\____BT,4QX`D at 0``
+M`````(M#%,>`*($```````"#Q!A;PXGV5E.+="00BUPD#+H`````D(T$DHT$
+M at F:+A(.T&0``9CL&=06)T.LTD(T$DHT$@HV,@[`9``!F at WD$`'449HL&9HE!
+M!&:+1@)FB4$&B=#K#)!"@_H_=KJX`````%M>PXGVBT0D!(N`L!D``,.0BT0D
+M!`5L%@``PXGV5E.#[`2+="00B?.X`````(.^I`$```5U#&:#OJ@!```)=0*P
+M`8F#J!D``(/L"&@`%0``C8.T&0``4.C\____N0````"#Q!"0C02)C02!C12#
+MQX+$&0``]`$``,>"R!D``,@```#'@LP9``#(````QX+0&0``9````,>"V!D`
+M`"@```#'@M09```'````C8*P&0``QD`+`,9`#`#&0`D'QD`*`(.[J!D```!T
+M%,>"]!D```S^OP#'@O at 9```X_[\`08/Y/W:"@[NH&0```'0JBU84BX/T&0``
+MB8(L at 0``BU84BX/X&0``B8(T at 0``@^P,5NC\____@\00QX.L&0``9````,>#
+MI!D```$```"#Q`1;7L.04X/L"(M<)!"#NZ at 9````=">#[`Q3Z/S___^+0Q3'
+M@"R!````````@\00BT,4QX`T at 0```````)"#Q`A;PXUV`%575E.![(P```"+
+ME"2D````BYPDJ````(NL)*````"+A;`9``")1"04N`````"#^@4/AQ($``#_
+M))5P40``B=ZX`````(/[!`^'^P,``(N4)*````"+2A2+D5"8``"!XO__#_"+
+MA)VT+@``P>`4)0``\`\)PHF14)@``(N\)*````"+3Q2+D5R8``"!XG^`__^+
+MA)W<+@``P>`')8!_```)PHF17)@``(M/%(N17)@``('B_W_`_XN$G<@N``#!
+MX`\E`(`_``G"B9%<F```BT\4BY%8F```@>+__P/\BX2=\"X``,'@$B4``/P#
+M"<*)D5B8``"+5"04#[9"!#G8<PC_A6P6``#K$HM,)!0/MD$$.=AV!O^%<!8`
+M`(GPBU0D%(A"!.D<`P``QT0D2'\```"-="1(QT8$,@```,=$)$!_````QT0D
+M1"@```#'1"0X?P```,=$)#Q-````QT0D,'\```#'1"0T0````,=$)"@?````
+MQT0D+!````#'1"0@/P```,=$)"0P````A=L/E<`/ML")1"00B[PDH````(M/
+M%(N1;)@``('B_S_ at _XG#P>,"BP0SP>`.)0#`'P`)PHF1;)@``(M/%(N1;)@`
+M`('B__\?\(M$'$#!X!4E``#@#PG"B9%LF```BT\4BY%HF```@>+__P'_BT0<
+M.,'@$24``/X`"<*)D6B8``"+3Q2+D6B8``"!XO___X"+1!PPP>`8)0```'\)
+MPHF1:)@``(M/%(N!:)@``(/@X(M4'"B#XA\)T(F!:)@``(M/%(N1;)@``(#F
+MP(M$'"#!X`@E`#\```G"B9%LF```@WPD$`!T%(M7%(N";)@``(/(`8F";)@`
+M`.L9BX0DH````(M0%(N";)@``(/@_HF";)@``(-\)!``#Y3`#[;`BTPD%`^V
+M40<YT`^$C`$``(-\)!``=`C_A7P6``#K!O^%@!8``(-\)!``BWPD%`^41P?I
+M90$``,=$)!@(````C50D&,="!`8```"%VP^5P`^VV(N$)*````"+2!2+ at 0BB
+M``"#X,"+%)J#XC\)T(F!"*(``(M4)!0/MD((.=@/A!D!``"%VW0(_X6$%@``
+MZP;_A8 at 6``"+3"04B%D(Z?L```#'1"1P`````,=$)'0$````QT0D>`@```")
+MWK@`````@_L"#X?8````B[PDH````(M/%(N16)@``('B_P_\_XM$G'#!X`PE
+M`/`#``G"B9%8F```BU0D%`^V0 at 8YV',(_X6,%@``ZQ*+3"04#[9!!CG8=@;_
+MA9`6``")\(M4)!2(0@;K>(U,)%")3"0,OE!1``#\N0@```"+?"0,\Z6X````
+M`(/[!W=:BX0DH````(M(%(N1))D``(#B`8M$G%#1X"7^````"<*)D229``"+
+M5"04#[9"!3G8<PC_A706``#K$HM,)!0/MD$%.=AV!O^%>!8``(M\)!2(7P6)
+M]K@!````@<2,````6UY?7<-64X/L!(M,)!")SHN9L!D``,=##`````"#N:@9
+M````#X2#````@7L0``#``'8*QT-``````.L,D+@``,``*T,0B4-`@7L8``#`
+M`'X,QT-$`````.L.C78`N```P``K0QB)0T2+412+0T")@BR!``"+412+0T2)
+M at C2!``"+013'@#"!``````(`BT$4QX`X at 0```````H/L"(V&J!8``%!1Z/S_
+M__^#Q!#'0S@`````QT,\`````(/$!%M>PU=64XM<)!"+B_P'``"#NZ09````
+M#X0B`0``@[NP`0```0^%%0$``(NSL!D``(!^!`-W&0^V1 at 1`4&H!4^C\____
+M@\0,Z?,```"-=@"`?@4&=Q8/MD8%0%!J!5/H_/___X/$#.G4````B[N\%@``
+MB?B#X'^#^#]V"(U'?\'H!^L)BX.\%@``P>@'.48D?3^`?@<`=1QJ`&H"4^C\
+M____:@!J!5/H_/___X/$&.F,````@'X&`0^'@@````^V1 at 9`4&H$4^C\____
+M@\0,ZV\Y1B!]+(!^!P!T#6H!:@)3Z/S___^#Q`R`?@8!=U$/MD8&0%!J!%/H
+M_/___X/$#.L^@^P(45/H_/___X/H`H/$$(/X`7<I@'X'`'4-:@!J`E/H_/__
+M_X/$#(!^!@!T$&H`:@13Z/S___^#Q`R-=@!;7E_#5U93BUPD$(NS_`<``(.[
+MI!D````/A)8```"#N[`!```!#X6)````B[NP&0``@'\$`W<5#[9'!$!0:@%3
+MZ/S___^#Q`SK:HGVBXN\%@``B<B#X'^#^#]V"(U!?\'H!^L)BX.\%@``P>@'
+M.4<@?1F`?P8!=SP/MD<&0%!J!%/H_/___X/$#.LI@^P(5E/H_/___X/H`H/$
+M$(/X`7<4@'\&`'0.:@!J!%/H_/___X/$#)!;7E_#5U93BW0D$(GW_[;\!P``
+M5N@;]___C12`C120C9R6M!D``(F>L!D``(/$"(.^I!D```!T;(.^L`$```%T
+M8_^&G!8``&H`:@%6Z/S___]J`&H%5NC\____:@!J!%;H_/___X/$)&H`:@)6
+MZ/S___]J`&H#5NC\____@^P$5NC\____@\0(@,P!4%;H_/___X/$%%;HN?S_
+M_X/$$.GB````D(![!`!T$@^V0P10:@%6Z/S___^#Q`R)]H![!0!T$@^V0P50
+M:@56Z/S___^#Q`R)]H![!P!T$@^4P`^VP%!J`E;H_/___X/$#(!["`!T$@^V
+M0PA0:@-6Z/S___^#Q`R)]H![!@!T$@^V0P90:@16Z/S___^#Q`R)]H._J!D`
+M``!T/X/L#%;H_/___X/$"(#D_E!6Z/S___^)-"3H$?S__XM&%,>`,($`````
+M`@"#Q!"+1A3'@#B!```````"ZR.)]H/L#%;HY_O__XDT).C\____@\0(@,P!
+M4%;H_/___X/$$%M>7\.-=@!75E.+="00BUPD%(GWBT84QX`D at 0```````(M&
+M%,>`*($```````"#[`B-AJ at 6``!05NC\____BP.)AKP6``"+0P2)AL`6``"+
+M0PB)AL06``"+1A2+D"R!``"+B#2!``")T"4``,``@\00/0``P`!T#HG()0``
+MP``]``#``'5ABY^P&0``*U-`B=`K0S@!AY06``")4SB)RBM31(G0*T,\`8>8
+M%@``B5,\BT,X.T,0=@^#[`Q6Z,K[__^#Q!"-=@"+0SP[0QAV#(/L#%;H\_S_
+M_X/$$(/L#%;HZ_K__X/$$%M>7\-3@^P(BUPD$(M$)!2+D[`9``"`>`41=2C_
+M0CC_ at Y06``"+0C@[0A!V0X/L#%/H;OO__XD<).BJ^O__@\00ZRV0@'@%&74F
+M_T(\_X.8%@``BT(\.T(8=A6#[`Q3Z(#\__^)'"3H?/K__X/$$)"#Q`A;PXUV
+M`%93BW0D#(N6L!D``(N.O!8``(G(@^!_ at _@_=@B-07_!Z`?K"8N&O!8``,'H
+M!SE")'Q2.4(@?3&`>@<`=`]J`6H"5NC\____@\0,ZVR`>@8`=#(/MD(&2%!J
+M!%;H_/___X/$#.M3C78`@'H&`'06#[9"!DA0:@16Z/S___^#Q`SK-XUV`(!Z
+M!0!T%@^V0 at 5(4&H%5NC\____@\0,ZQN-=@"`>@0`=!(/MD($2%!J`5;H_/__
+M_X/$#)!;7L.055=64XM4)!2+0A2+N.R```"+J/"```"+L/B```"+FK`9``"#
+M>S0`=`4Y<S1V#KD`````_X*@%@``ZRF0B?$K2S2)Z"M#,(GZ*U,L*<$IT;@I
+M.5-?]^G!^@Z)R,'X'XG1*<&)]HES-(E[+(EK,(G(6UY?7<-55U93@^P,BWPD
+M((M4)"2)^XNWL!D``(L"B8>\%@``BT($B8?`%@``BT((B8?$%@``5^A5____
+M@\0$A<!Y&O^'I!8``(/L#%?H\_C__X/$$.FO`0``C78``48,@[^H&0````^$
+MS````(/L"(V'J!8``%!7Z/S___^+1Q2+D"R!``"+J#2!``"#Q!`Y5D!W"CEN
+M1'9Y.59`=C.#[`S_=D!2:(A1``!H`````%?H_/___XM'%(M60(F0+($``(/$
+M((M'%,>`,($``````@`Y;D0/AB\!``"#[`S_=D15:(A1``!H-````%?H_/__
+M_XM'%(M61(F0-($``(/$((M'%,>`.($```````+I]P```"M60(G0*T8X`8>4
+M%@``B58XB>HK5D2)T"M&/`&'F!8``(E6/(UV`(.[I!D````/A,,```"#O[`!
+M```!#X6V````BX.L&0``C02`.48,=D.+3 at R)R`^O1A2[TTUB$/?CB=#!Z`8Y
+M1CAW&XG(#Z]&'/?CB=#!Z`8Y1CQW"5?H0OW__X/$!(/L#%?HIO?__X/$$.ME
+MBT8,.X.L&0``=EJ)P@^O5A"XTTUB$/?BB=#!Z`8Y1CAV%H/L#%?H,OC__XD\
+M).AN]___@\00ZRV+1 at P/KT88NM--8A#WXHG0P>@&.48\=A6#[`Q7Z$3Y__^)
+M/"3H0/?__X/$$)"#Q`Q;7E]=PU575E.#[`R+?"0 at BVPD*(M<)"R^`````(T$
+M=HM/%(L4Q:!1``")5"0(BU0D)(T$0HL$A:!1``"+5"0(B0010_;#/W40@^P,
+M:@'H_/___X/$$(UV`$:#_ at UVOKX`````D(M/%(L4]0!3``"+!/4$4P``B001
+M0_;#/W4.@^P,:@'H_/___X/$$)!&@_Y%=M*^`````)"-!':+3Q2+%(7 at 5@``
+M`>B+!(7 at 5@``B0010_;#/W4-@^P,:@'H_/___X/$$$:#_C]VSH/$#%M>7UW#
+MB?955U93@^P4BVPD+`^W10)0#[=%`%#H_/___X/$$/9%`H!T;0^_\(T<=L'C
+M`HVS9%T``(/L"&H(_W8$Z/S___^)QX'G_P```,'G!8N#9%T``,'@!`G'9HM.
+M"(M$)#"+4!2+@@2B``"#Q!!F at 7T`M`EU"X/($(F"!*(``.L;BUPD((M3%(/@
+M[XF"!*(``.L)B?:)P;\`````9H'YD`!_!?;!`70E@^P(:@@/O\&#Z!A0Z/S_
+M__^)PX'C_P```+@!````@\00ZRZ)]H/L"&H(#[_!@^@8B<+!ZA\!T-'X4.C\
+M____B<.!X_\```"X`````(/$$(GVP>,"T>`)PX'+`00``(M$)""+2!2)^"7_
+M````P>`(#[;3"=")@9R8``"+1"0 at BT@4B?@E`/\```^VUPG0B8'0F```BUPD
+M((FK_`<``+@!````@\0,6UY?7<.-=@"+5"0(BT0D!(N`>!D``(/Z!W<A_R25
+MJ%X``(GV@\!$PX/`2,.#P$S#@\!0PP64````PXGVN`````##B?955U93@>R,
+M````B[PDH````(N$)*@```!FB40D+HG]O@````"+E"2D````#[="`B7P`0``
+M/<`````/A*0!```]P````'\0/:`````/A"H!``#I]0$``#U``0``=`L]4`$`
+M``^%XP$``(N4)*0```!FBP(MH0\``&8]Z at 1W'6:+A>0(``!FB40D)&:+E>8(
+M``!FB50D(NF4````BY0DI````&:+`BV,%```9CWO`'<:9HN%Z`@``&:)1"0D
+M9HN5Z@@``&:)5"0BZV6+E"2D````9HL"+7P5``!F/>``=QIFBX7L"```9HE$
+M)"1FBY7N"```9HE4)"+K-HN$)*0```!F at 3A<%G8:9HN5\`@``&:)5"0D9HN%
+M\@@``&:)1"0BZPYFQT0D(@``9L=$)"0``,=$)!@`````QT0D'`````!FBY5F
+M"```9HE4)"QFBX5L"```9HE$)"IF@[UL"`````^4P&8/ML!FB40D*&:+E;H(
+M``!FB50D)NG:````9HN']`@``&:)1"0D9HN7]@@``&:)5"0B#[>'_`@``(E$
+M)!P/MY<`"0``B50D&&:+AV@(``!FB40D+&:+EVX(``!FB50D*F:#OVX(````
+M#Y3`9@^VP&:)1"0H9HN'O`@``&:)1"0FZW)FBY?X"```9HE4)"1FBX?Z"```
+M9HE$)"(/MY?^"```B50D'`^WAP()``")1"089HN7:@@``&:)5"0L9HN'<`@`
+M`&:)1"0J9H._<`@````/E,!F#[;`9HE$)"AFBY>^"```9HE4)";K"K@`````
+MZ00#``"[``````^W5"0NN4!5``"-!%N-!$*+!(&)1)PP0X/[$';MBX0DI```
+M`/9``H!T+8/L#&H`:G=J`_]T)#2-7"1,4^C\____@\04:@!J>FH#_W0D,%/H
+M_/___X/$(+L`````B?:-!%N+3Q2+%,5`50``BT2<,(D$$4;WQC\```!U#X/L
+M#&H!Z/S___^#Q!")]D.#^Q!VSKL`````BT\4BQ3=X%D``(L$W>19``")!!%&
+M]\8_````=0V#[`QJ`>C\____@\000W33NP`````/MU0D+HE4)!2-!%N+3Q2+
+M%,7H60``B50D#(M4)!2-!$*+!(7H60``BU0D#(D$$4;WQC\```!U#8/L#&H!
+MZ/S___^#Q!!#=,&[``````^W1"0NB40D$(T$6XM/%(L4Q0!:``")5"0,BU0D
+M$(T$0HL$A0!:``"+5"0,B0011O?&/P```'4-@^P,:@'H_/___X/$$$-TP;L`
+M````#[=4)"ZY(%H``(UV`(T$6XT$0HL$@8E$G#!#@_L0=NV+E"2D````#[="
+M`B5``0``/4`!``!U-8/L#&H#:C-J`0^WA5P)``!0C5PD3%/H_/___X/$%&H#
+M:BUJ`0^WA5X)``!04^C\____@\0@@^P,:@!J7VH!#[=$)$!0C5PD3%/H_/__
+M_X/$%&H`:F!J!`^W1"1$4%/H_/___X/$%&H`:FAJ`P^W1"0\4%/H_/___X/$
+M%&H`:FMJ`P^W1"0Z4%/H_/___[L`````@\0 at D(T$6XM/%(L4Q2!:``"+1)PP
+MB0011O?&/P```'4/@^P,:@'H_/___X/$$(GV0X/[$';.NP`````/MU0D+KG`
+M6P``C78`C01;C01"BP2!B42<,$.#^P=V[8/L#&H`:AUJ!@^W1"0^4(U<)$Q3
+MZ/S___^#Q!1J`&H$:@$/MT0D0E!3Z/S___^[`````(/$((UV`(T$6XM/%(L4
+MQ<!;``"+1)PPB0011O?&/P```'4/@^P,:@'H_/___X/$$(GV0X/[!W;.QX5@
+M&0```````+@!````@<2,````6UY?7<-55U93BVPD%(M,)!B+?"0<BUPD((MT
+M)"0/M\,/M]8/K\*Z`````(7`=&&)V&8YSW17#[?%#[?)*<B-!("-!(#!X`(/
+MM]<IRHG1F??YB<*)V&:%TG at SB?!F at _ID?RL/O](/M\X/K\JX9````"G0#[?3
+M#Z_"`<&X'X7K4??IB=#!^`7!^1]F*<B0#[?0B=!;7E]=PXGV55=64X'L3`$`
+M`(N$)&`!``")1"0<9L=$)!@``&;'1"06/P"+E"1L`0``#[="`B7P`0``/=``
+M```/A(,````]T````'\3/:````!T3CW`````=&[IC0```#U0`0``=!<]4`$`
+M`'\)/4`!``!T">MV/4`)``!U;XM,)!QFBX%V"0``9HE$)"2)R`5B"0``B40D
+M((U`%HE$)"CK58M<)!QFBX.`"P``9HE$)"2)V`6("P``B40D((V`H@```(E$
+M)"CK+HM4)!QFBX*`"P``9HE$)"2)T`6""P``B40D((U`#(E$)"CK"K@`````
+MZ=@"``"-="0@@^P(:`@!``"-1"0\4.C\____C:PDR````+\!````NP````"#
+MQ!"-=@!FB7Q<.$=#@_\_?O1FB5PD-F;'1"0R`0!FQT0D-#\`NP````!F at WPD
+M-@!T+(/L!%8/MT1<0%"+C"1X`0``#[<!4.AR`@``9HE$70"#Q!!##[=$)#8Y
+MV'_49HM5``^W1"0V9HM,1?Z[`````(/X`'YJ9CE470!_"F:+5%T`9HE<)!B)
+MV/?09 at -$)#8/M_B%_W0 at 9HM$??YF.T1]`'X*9HM$?0!FB41]_D,/MT0D-CG8
+M?[^[`````&:#?"0V`'0<#[=$)#:09CE,70!^"F:+3%T`9HE<)!9#.=A_Z@^_
+MRH/!&;L?A>M1B<CWZXG0P?@$P?D?*<B-!("-!(#1X&:)1"0:9L=$)!0``+\`
+M````#[_(B<Z)R/?KB40D"(E4)`R+1"0,P?@$P?D?*<A`@_@`?CJX'X7K4??N
+MB='!^02)\)F)R"G0C4@!C78`#[=4)!2+7"0<BX,$+P``BUPD&&:)'%!F_T0D
+M%$<Y^7_?OP`````/MT0D-HG"9HM,)!IF.4Q%_@^.YP```&:#?"04/P^'"`$`
+M`&:#1"0:,HG69HM<)!IF.5Q5_GY'#[_#B<,/OU1]`(G!*=&)R@^_3'T"*<@/
+MK]"%TGXID$=FBT0D&F8Y1'7^?AL/OT1]`(G:*<*)T`^_5'T"B=DIT0^OP87`
+M?]@/MU1\.M'B#[?2#[=$?#C1X`^WP`^W3'T"#[=<?0`/MW0D&E)045-6Z#?\
+M__^#Q!1`#[=,)!2+7"0<BY,$+P``9M'H9HD$2HN#!"\``&:+5"069CD42'8$
+M9HD42&;_1"04#[=4)#9FBTPD&F8Y3%7^?@YF at WPD%#\/AB?____K+6:#?"04
+M/W<E#[=,)!2+7"0<BY,$+P``9HM$2OYFB01*9O]$)!1F at WPD%#]VVXM$)!QF
+MQX"`&0````"X`0```('$3`$``%M>7UW#B?955U93@^P<BVPD.(M<)#"+="0T
+MC40D&E!5#[?&4`^WPU#H0@$``(/$$(7`=`L/MT0D&NDI`0``D(/L#(U$)"10
+MC40D)E`/MT4$4/]U``^WVXE<)"!3Z/S___^#Q!2-1"0 at 4(U$)")050^W1"0N
+M4`^W]E;H=0$``(/$%(U$)!Q0C40D'E!5#[=$)#!05NA;`0``@\0 at C40D#%!5
+M#[=$)!I0#[=$)")0Z+T```"-1"0:4%4/MT0D+%`/MT0D,E#HI@```(/$(`^W
+M1"0*#[=4)`P/MTPD%`^W7"024%)14U;HM?K__X/$%(G'C40D#%!5#[=$)!90
+M#[=$)"10Z&D```"-1"0:4%4/MT0D*%`/MT0D-%#H4@```(/$(`^W1"0*#[=4
+M)`P/MTPD$`^W7"0.4%)14U;H8?K__X/$%`^WP`^WWP^W5"08#[=,)!904U)1
+M_W0D%.A!^O__@\04#[?`C78`@\0<6UY?7<-55U93@^P$BVPD((M$)!AFB40D
+M`HM\)!R+30B^`````&:#?00`=$V09HM$)`)F.0%U-HU1"+L`````9H-Y!@!T
+M)XUV`&8Y.G439HM461Z+1"0D9HD0N`$```#K'8/"`D,/MT$&.=A_W(/!-$8/
+MMT4$.?!_M+@`````@\0$6UY?7<.-=@!75E.+1"08BWPD$(MT)!2+4`BY````
+M``^W0`2)PX/X`'X/B?9F.3)T"(/"-$$YRW_S@^P,_W0D+/]T)"P/MT(&4(U"
+M"%`/M\=0Z/S___^#Q"!;7E_#C78`4X/L"(M<)!"#NP0O````=!N#[`S_LP0O
+M``#H_/___\>#!"\```````"#Q!"#NW at 9````=!N#[`S_LW at 9``#H_/___\>#
+M>!D```````"#Q!"#Q`A;PXUV`%93@^P0BW0D((M<)!QHM````.C\____B8-X
+M&0``@\00A<!U",<&`@```.MPQX,(+P``@````(/L#&B`````Z/S___^)@P0O
+M``"#Q!"%P'4(QP8"````ZT3'@\@6``"H1@$`QX/,%@``/#@!`,>#T!8``%PZ
+M`0#'@]06```,.0$`QX/8%@``F#H!`,>#W!8``)!``0"X`0```(UV`(/$!%M>
+MPY"055=64X/L#(M\)""+;"0HBUPD++X`````C01VBT\4BQ3%X%X``(E4)`B+
+M5"0DC01"BP2%X%X``(M4)`B)!!%#]L,_=1"#[`QJ`>C\____@\00C78`1H/^
+M#W:^O@````"0BT\4BQ3U8&```(L$]61@``")!!%#]L,_=0Z#[`QJ`>C\____
+M@\00D$:#_D)VTKX`````D(T$=HM/%(L4A8!B```!Z(L$A8!B``")!!%#]L,_
+M=0V#[`QJ`>C\____@\001H/^/W;.@\0,6UY?7<.)]E575E.#[`R+;"0 at BW0D
+M),=$)`@`````OP````!F at 3Z_$@^'S0````^W!HE$)`0MD`@``+H%````B=.9
+M]_N%TG4CBT0D!(V<`.#N__^X9V9F9O?KP?H"B=C!^!^)TRG#ZT6-=@`/MPZ-
+M at 5#W__^Z!0```(G3F??[N`````"%T@^%N`$``(V<":#N__^X9V9F9O?KP?H"
+MB=C!^!^)TRG#QT0D"`$```#!XP*!X_\```"#[`AJ"%/H_/___XG#BU44BX($
+MH@``@\009H$^M`EU$8/($(F"!*(``.D;`0``C78`BU44@^#OB8($H@``Z0<!
+M``"-=@!FBP:Y%````+H`````9O?Q9H72=4=F at 3[_$W9`@^P(:@@/MPZ!Z<`2
+M``"X9V9F9O?IB=#!^`/!^1\IR,'@`E#H_/___XG#@\0(:@)J`^C\____B<>#
+MQ!#IJ````&:+!KD*````N@````!F]_%FA=)U/X/L"&H(#[<.@>G`$@``N&=F
+M9F;WZ8G0P?@"P?D?*<C1X%#H_/___XG#@\0(:@)J`NC\____B<>#Q!#K5XUV
+M`&:+!KD%````N@````!F]_&X`````&:%TG5^@^P(:@@/MPZ!Z<`2``"X9V9F
+M9O?IB=#1^,'Y'RG(4.C\____B<.#Q`AJ`FH!Z/S___^)QX/$$(UV`(G9P>$$
+MC02]``````G!BT0D"-'@"<&!R0$0``"+510/ML&)@IR8``#!Z0B+512)R(/@
+M?XF"V)@``(FU_`<``+@!````@\0,6UY?7<.+5"0(BT0D!(N`>!D``(/Z!W<=
+M_R25N&H``(GV@\`$PX/`",.#P`S#!:P```##B?:X`````,.)]E575E.#[!R+
+M;"0PBT0D.&:)1"0:B6PD%&;'1"0.``!FQT0D#```9L=$)`H``&;'1"0(``"+
+MM7 at 9``")ZH'"/!8``(E4)`2_`````(M4)#0/MT(")?`!```]T`````^$>`$`
+M`#W0````?QL]H`````^$)`$``#W`````#X1;`0``Z8T!```]4`$``'0>/5`!
+M``!_##U``0``=!#I<P$``#T`"```#X5H`0``BU0D-&:+`BVA#P``9CWJ!'<E
+MBT0D%&:+ at .0(``!FB40D#HM4)!1FBY+F"```9HE4)`SIDP```(M4)#1FBP(M
+MC!0``&8][P!W(HM$)!1FBX#H"```9HE$)`Z+5"049HN2Z@@``&:)5"0,ZU^+
+M5"0T9HL"+7P5``!F/>``=R*+1"049HN`[`@``&:)1"0.BU0D%&:+DNX(``!F
+MB50D#.LKBT0D-&:!.%P6=B"+5"049HN2\`@``&:)5"0.BT0D%&:+@/((``!F
+MB40D#(M4)!1FBY)L"```9HE4)!*+1"049HN`N@@``&:)1"00Z8,```"+5"04
+M9HN2_`@``&:)5"0*BT0D%&:+@``)``!FB40D"(M4)!1FBY)N"```9HE4)!*+
+M1"049HN`O`@``&:)1"00ZT&+5"049HN2_@@``&:)5"0(9HE4)`J+1"049HN`
+M<`@``&:)1"02BU0D%&:+DKX(``!FB50D$.L*N`````#I;00``+H`````N81E
+M``"+!-&)!)9"=/>Z``````^W3"0:NXAE``"-!%*-!$&+!(.)1)8$0G3PN@``
+M```/MTPD&KN at 90``C012C01!BP2#B426"$)T\+H`````#[=,)!J[P&4``(T$
+M4HT$08L$@XE$E at Q"@_HG=NV#[`QJ`&@N`0``:@$/MT0D*E"-7 at Q3Z/S___^#
+MQ!1J`&@.`0``:@*+5"14#[<"4%/H_/___X/$%&H`:`$!``!J`HM4)%0/MT("
+M4%/H_/___X/$((M$)#3V0`)`#X2W````@^P,:@-HJ````&H!BU0D'(M"'`^_
+M0`)04^C\____@\04:@-HJ0```&H!BU0D'(M"'`^_0`104^C\____@\04:@-H
+MJ@```&H!BU0D'(M"'`^_0`904^C\____@\04:@-HK@```&H!BU0D'(M"'`^_
+M0`A04^C\____@\04:@-HKP```&H!BU0D'(M"'`^_0`I04^C\____@\04:@-H
+ML````&H!BU0D'(M"'`^_0`Q04^C\____@\0 at BT0D-/9``H!T.(/L#&H`:!\!
+M``!J`P^W1"0B4(U>#%/H_/___X/$%&H`:"(!``!J`P^W1"0 at 4%/H_/___X/$
+M(.LV@^P,:@!H%P$``&H##[=$)"90C5X,4^C\____@\04:@!H&@$``&H##[=$
+M)"104^C\____@\0@#[>%K`$``"7P````@_ at O?F%F@[VL`0``-70*9H.]K`$`
+M`$5U38/L#&H":EIJ`FH"C5X,4^C\____@\04:@)J7&H":@)3Z/S___^#Q!1J
+M`FI>:@)J`E/H_/___X/$%&H":/X```!J`6H"4^C\____@\0 at 9H.]J@$``$%V
+M9(/L#&H!:!D!``!J`6H!C5X,4^C\____@\04:@-J`6H":@%3Z/S___^#Q!1J
+M`VH#:@)J`5/H_/___X/$%&H#:(L```!J`6H!4^C\____@\04:@-HC````&H!
+M:@%3Z/S___^#Q""Z``````^W3"0:NX!I``")]HT$4HT$08L$@XF$EJP```!"
+M at _H,=NJ+5"0T]D("0'0C@^P,:@!J)6H"BU0D'(M"'`^_`%"-AJP```!0Z/S_
+M__^#Q""#[`QJ`&H.:@8/MT0D*%"-AJP```!0Z/S___^[`````(/$((M-%(L4
+MW8!E``"+!)Z)!!%']\<_````=0V#[`QJ`>C\____@\000W37NP````"-!%N+
+M312+%,6(90``BT2>!(D$$4?WQS\```!U#8/L#&H!Z/S___^#Q!!#=-.[````
+M`(T$6XM-%(L4Q:!E``"+1)X(B0011_?'/P```'4-@^P,:@'H_/___X/$$$-T
+MT[L`````C01;BTT4BQ3%P&4``(M$G at R)!!%']\<_````=0^#[`QJ`>C\____
+M@\00B?9#@_LG=LZ[`````)"-!%N+312+%,6`:0``BX2>K````(D$$4?WQS\`
+M``!U$(/L#&H!Z/S___^#Q!"-=@!#@_L,=LJ+1"04QX!@&0```````+@!````
+M@\0<6UY?7<.-=@!55U93@>S\`P``BX0D$`0``(E$)!@/MX"L`0``)?````"#
+M^"]^(HM4)!AF@[JL`0``-70*9H.ZK`$``$5U"L=$)!0"````ZPC'1"04`0``
+M`(N,)!P$```/MT$")?`!```]T````'1I/=````!_$#V@````=$$]P````'14
+MZVP]4`$``'07/5`!``!_"3U``0``=`GK53T`"```=4Z+1"08!5`1``")1"0,
+MBTPD&`^WD68(``#K/HM$)!@%7!$``(E$)`R+3"08#[>1:`@``.LDBT0D&`5H
+M$0``B40D#(M,)!@/MY%J"```ZPJY`````.GV!0``BTPD#`^W00:Y`````(7"
+M#X3A!0``BY0D&`0```^_`M'@9HE$)`2+C"04!```#[\!T>!FB40D!F;'1"0H
+MK=YFQT0D*JW>QT0D"`````"^`````(M$)`P/MU`&C5PD*(GVB=")\=/XJ`%T
+M&(-\)`@!#X?1!```BT0D"&:)-$-`B40D"$:#_ at -VV(/L#(U$)#!0C40D,%"+
+M5"0@#[="!%#_,HN,)#@$```/MP%0Z)P%``#'1"0H`````(ML)$"#Q"`[;"0D
+M#X?U`0``C78`C42M`(U$A0"+3"0,BU$(C02"B40D$&:!?"0JK=X/A9<````/
+MMW0D*(T<MHT<F(/L!`^W>P:--#]6C4,(4(V$)-P"``!0Z/S___^#Q`Q6@\,0
+M4XV4)+P"``!2Z/S___^#Q`2-3"0\48M4)"`/OT("4(V,),0"``!1C80DZ`(`
+M`%!7Z(H%``"#Q""%P`^$\P,``(/L!&B`````C50D.%*+1"04P>`'C80$O`$`
+M`%#H_/___X/$$.DI`0``#[=T)"B-'+:+3"00C1R9@^P$#[=[!HTT/U:-0PA0
+MC80DW`(``%#H_/___X/$#%:#PQ!3C90DO`(``%+H_/___X/$!(U,)#Q1BU0D
+M(`^_0@)0C8PDQ`(``%&-A"3H`@``4%?H[P0``(/$((7`#X1B`P``@^P$:(``
+M``"-5"0X4HM$)!3!X`>-A`2\`0``4.C\____#[=T)#J-'+:+3"0 at C1R9@\0,
+M#[=[!HTT/U:-0PA0C80DW`(``%#H_/___X/$#%:#PQ!3C90DO`(``%+H_/__
+M_X/$!(U,)#Q1BU0D(`^_0@)0C8PDQ`(``%&-A"3H`@``4%?H7`0``(/$((7`
+M#X39`@``@^P$:(````"-5"0X4HM$)!3!X`>-A`2\````4.C\____@\00_T0D
+M"$4[;"0D#X8._O__BTPD((M$)`R+$&:+'$J+1"0D9HL\0BG(B40D"&:!?"0J
+MK=X/A;@```"^`````(/L#(M$)!3!X`8!\`^_A$2\`0``4`^_A'3``0``4`^W
+MQU`/M\-0BY0D.`0```^W`E#HX@(``&:)A'20`P``@\0 at 1H/^/W:Y@^P(BTPD
+M(/^Q!"\``(V$)'P#``!0Z&<$``")PF;!Z`^-!`)FT?B+E"0D!```9HD"9HN$
+M)/X#``")PF;!Z@\!T&;1^&:)1"0^BXPD*`0``&:)`8M$)#B+E"0P!```9HD"
+M9HE"`H/$$.DX`@``O@`````/M^\/M_N)]H/L#(M<)!3!XP8!\P^_A%R\`0``
+M4`^_A'3``0``4%57BXPD.`0```^W`5#H*`(``&:)A'20`P``@\04#[^$7+P`
+M``!0#[^$=,````!055>+E"0X!```#[<"4.CY`0``9HF$=!`#``"#Q"!&@_X_
+M=I"#?"04`@^%BP```(U$)!Y0BTPD'/^Q!"\``(V$)/@"``!0C80D?`,``%#H
+M-00``(G"9L'H#XT$`F;1^(N4)"0$``!FB0)FBT0D+HG"9L'J#P'09M'X9HE$
+M)#YFBX0D_@,``(G"9L'J#P'09M'XBXPD*`0``&:)`8M$)#B+E"0P!```9HD"
+M9HM$)#IFB4("@\00Z24!``!FBTPD!F8YC"1N`P``#XRI````BT0D!&8YA"1N
+M`P``#XR7````@^P(BU0D(/^R!"\``(V$)/P"``!0Z,,"``")PF:+1"0ZBXPD
+M,`0``&:)`6:)00*)T&;!Z`^-!`)FT?B+E"0D!```9HD"9HN$)'X#``")PF;!
+MZ@\!T&;1^&:)1"0^BXPD*`0``&:)`8/$$.F1````N0````#II@```+D`````
+MZ9P```"Y`````.F2````N0````#IB````(/L"(M$)"#_L`0O``"-A"1\`P``
+M4. at L`@``B<*+1"0XBXPD,`0``&:)`6:)00*)T&;!Z`^-!`)FT?B+E"0D!```
+M9HD"9HN$)/X#``")PF;!Z@\!T&;1^&:)1"0^BXPD*`0``&:)`8/$$+ at _````
+MBY0D&`0``&8K`HM,)!AFB8&`&0``N0$```")R('$_`,``%M>7UW#D%=64XM<
+M)!"+="04BTPD&(M\)!R+5"0 at B?AF.?%T)`^WVP^W]HG8*?`/O](/K\(/M\F)
+MRBG:#[_?#Z_3`=`I\9GW^9A;7E_#D%575E.+="08BVPD((M\)"2+5"0<#[=<
+M)!0/M\J-#$X/MP8YV'82QP<`````QT4``````.M3C78`#[=!_CG8=R@/M\)(
+MB0>)10#K/8G0*?#1^(D'B44`ZS")T"GPT?B)10!`B0?K(HGVB?(YSG,:B?8/
+MMP(YV'34#[="`CG8=]F#P@(YRG+JB?9;7E]=PXUV`%575E.#[`R+;"0PBU0D
+M((M$)"QFB40D"F;'1"0(``!FQT0D!@$`N`````!F at _H!#X:;````OP`````/
+MM\)(B00DC78`#[=$)`:+5"0D9CD\0G,1.P0D?0QF_T0D"&;_1"0&B?8/MU0D
+M!HM<)"@/OS13#[=$)`@/OPQ#BUPD)`^W%%,/MP1##[??5E%24%/HE?[__X/$
+M%&:)1%T`9HM4)`IF.=!\&V:#_S]W%9`/M\=FBUPD"F:)7$4`1V:#_S]V[$=F
+M at _\_#X9Y____N`$```"#Q`Q;7E]=PU575E.#[`2+?"08BVPD'`^_1WX/OQ<I
+MT(/X?GX.9HM'?H/H?F:)1"0"ZPAFBP=FB40D`F:+=WZY/P````^_5WZ)T$@Y
+MPGX6B<*-=@!)#[_!#[\$1SG0?@5FA<EY[XG*B?.^/P```(GVC4+_B<%F at _@^
+M=QT/O\)F.1Q'?!2)RHU*_V:#^3YW"0^_PF8Y'$=][&:%TG4;9H7V>"6)]@^_
+MUF:+1%4"9HE$50!F3GGOZQ"0#[_&9HE410"#ZP)F3GFI#[]$)`*#Q`1;7E]=
+MPU575E.#[!"+="0D9L=$)`)```^_1GZ+3"0H#[\1*="#^'Y^#F:+;GZ#[7YF
+MB6PD#NL,BT0D*&:+`&:)1"0.9HM6?F:)5"0,N3\````/OU9^#[]$)`Q(.<)^
+M$XG"20^_P0^_!$8YT'X%9H7)>>^+;"0H9HM%?HM4)#!FB0*_/P```(M<)`R-
+M=@"+;"0P9CE=`'T.9H7)=1EF at WPD`D!U$9!FQT0D`@``BW0D*+D_````9H7)
+M?AH/O\%F.1Q&?!&)]DEFA<E^"0^_P68Y'$9]\6:%R74D9H-\)`(`=1QFA?]X
+M-`^_UXM,)"QFBT11`F:)!%%F3WGLZQZ0#[_O9HM$)`()R(M4)"QFB01J@^L"
+M9D\/B7/___\/OT0D#H/$$%M>7UW#B?93@^P(BUPD$(.[!"\```!T&X/L#/^S
+M!"\``.C\____QX,$+P```````(/$$(.[>!D```!T&X/L#/^S>!D``.C\____
+MQX-X&0```````(/$$(/$"%O#C78`5E.#[!"+="0 at BUPD'&C@````Z/S___^)
+M at W@9``"#Q!"%P'4(QP8"````ZWC'@P at O``"`````@^P,:(````#H_/___XF#
+M!"\``(/$$(7`=0C'!@(```#K3,>#""\``$````#'@\@6```<7`$`QX/,%@``
+MI$<!`,>#T!8``+A*`0#'@]06``!T2`$`QX/8%@``\$H!`,>#W!8``(11`0"X
+M`0```)"#Q`1;7L.0D%575E.#[`R+?"0 at BVPD*(MT)"R[`````(T$6XM/%(L4
+MQ>!J``")5"0(BU0D)(T$0HL$A>!J``"+5"0(B0011O?&/P```'4-@^P,:@'H
+M_/___X/$$$.#^P]VOKL`````D(M/%(L4W6!L``"+!-UD;```B0011O?&/P``
+M`'4/@^P,:@'H_/___X/$$(GV0X'[B````';+NP````")]HT$6XM/%(L4A<!P
+M```!Z(L$A<!P``")!!%&]\8_````=0Z#[`QJ`>C\____@\00D$.#^S]VRH/$
+M#%M>7UW#B?955U93@^P,BVPD((MT)"3'1"0(`````+\`````9H$^OQ(/A\T`
+M```/MP:)1"0$+9`(``"Z!0```(G3F??[A=)U(XM$)`2-G`#@[O__N&=F9F;W
+MZ\'Z`HG8P?@?B=,IP^M%C78`#[<.C8%0]___N at 4```")TYGW^[@`````A=(/
+MA;@!``"-G`F@[O__N&=F9F;WZ\'Z`HG8P?@?B=,IP\=$)`@!````P>,"@>/_
+M````@^P(:@A3Z/S___^)PXM5%(N"!*(``(/$$&:!/K0)=1&#R!")@@2B``#I
+M&P$``(UV`(M5%(/@[XF"!*(``.D'`0``C78`9HL&N10```"Z`````&;W\6:%
+MTG5'9H$^_Q-V0(/L"&H(#[<.@>G`$@``N&=F9F;WZ8G0P?@#P?D?*<C!X`)0
+MZ/S___^)PX/$"&H":@/H_/___XG'@\00Z:@```!FBP:Y"@```+H`````9O?Q
+M9H72=3^#[`AJ"`^W#H'IP!(``+AG9F9F]^F)T,'X`L'Y'RG(T>!0Z/S___^)
+MPX/$"&H":@+H_/___XG'@\00ZU>-=@!FBP:Y!0```+H`````9O?QN`````!F
+MA=)U?H/L"&H(#[<.@>G`$@``N&=F9F;WZ8G0T?C!^1\IR%#H_/___XG#@\0(
+M:@)J`>C\____B<>#Q!"-=@")V<'A!(T$O0`````)P8M$)`C1X`G!@<D!$```
+MBU44#[;!B8*<F```P>D(BU44B<B#X'^)@MB8``")M?P'``"X`0```(/$#%M>
+M7UW#55=64X/L#(ML)""+1"0H9HE$)`J);"0$OP````"+M7 at 9``"+1"0D#[=`
+M`B7P`0``/<````!T.CW`````?PD]H````'0+ZTL]T````'0CZT*+1"0$9HN`
+M]`@``&:)1"0"BT0D!&:+@/8(``!FB00DZRN+1"0$9HN`^`@``&:)1"0"BT0D
+M!&:+@/H(``!FB00DZPJX`````.GA`0``N@````"YQ',``(L$T8D$ED)T][H`
+M````#[=,)`J[R',``(T$4HT$08L$@XE$E at 1"=/"Z``````^W3"0*N^!S``"-
+M!%*-!$&+!(.)1)8(0G3PN@`````/MTPD"KL`=```C012C01!BP2#B426#$*#
+M^AIV[8/L#&H`:*@```!J`P^W1"0:4(U>#%/H_/___X/$%&H`:*4```!J`P^W
+M1"084%/H_/___[H`````@\0@#[=,)`J[H'8``(T$4HT$08L$@XE$EGA"@_H"
+M=NV[`````(M-%(L4W<!S``"+!)Z)!!%']\<_````=0V#[`QJ`>C\____@\00
+M0W37NP````"-!%N+312+%,7(<P``BT2>!(D$$4?WQS\```!U#8/L#&H!Z/S_
+M__^#Q!!#=-.[`````(T$6XM-%(L4Q>!S``"+1)X(B0011_?'/P```'4-@^P,
+M:@'H_/___X/$$$-TT[L`````B?:-!%N+312+%,4`=```BT2>#(D$$4?WQS\`
+M``!U#X/L#&H!Z/S___^#Q!")]D.#^QIVSKL`````C01;BTT4BQ3%H'8``(M$
+MGGB)!!%']\<_````=1"#[`QJ`>C\____@\00C78`0X/[`G;-BT0D!,>`8!D`
+M``````"X`0```(/$#%M>7UW#C78`BU0D"(M$)`2+@'@9``"#^@=W&?\DE>AV
+M``")]H/`!,.#P`C#@\`,PX/`>,.X`````,.)]E575E.+?"08BVPD)(MT)!R+
+M7"04#[?.C0Q/#[_3#[<'.<)]%,=%``````"+1"0 at QP``````ZU&09CE9_G\N
+M#[?&2(E%`(M4)"")`NL[*?C1^(E%`(M4)"")`NLL*?C1^(M4)"")`D")10#K
+M'(GX.<]S%HGV9CD8=-1F.5@"?]V#P`(YR'+NB?9;7E]=PXUV`%575E.#[!B+
+M1"0P9HE$)`Z+3"0T9HE,)`R+7"1`9HE<)`J)Q='E9L=$)`@``+@`````9H/[
+M`0^&!@$``(M$)`QF*T0D#F8[1"0(#X+M````#[=$)`J)1"0$C78`C40D%%"-
+M1"044`^W1"024/]T)$0/O\50Z/?^__^#Q!2#?"04`'4(QT0D%`$```"+5"0$
+MC4+_.T0D$'4(C4+^B40D$)"+3"00BUPD.&:+%$N+1"049CL40W4*BT0D/&:+
+M#$CK2P^_S8M<)!"+1"0X#[\T6(G/*?>+5"04BT0D/`^_!%`/K_B+1"0X#[\4
+M4(G0*<B)!"2+1"0\#[\,6(L$)`^OP8T$!RGRB=&9]_F)P0^W1"0(BU0D+,'B
+M!@'"BUPD1&:)#%-F_T0D"(/%`HM$)`QF*T0D#F8[1"0(#X,?____N`$```"#
+MQ!A;7E]=PXGV5U93BUPD$(MT)!2+3"08BWPD'(M4)"")^&8Y\70D#[?;#[?V
+MB=@I\`^_T@^OP@^WR8G**=H/O]\/K],!T"GQF??YF%M>7\.055=64X'L7`8`
+M`(N$)'0&``!FB40D-HN4)'P&``!FB50D-,=$)"@`````C40D3%"-1"1,4(N,
+M)(`&```/MT$(4%$/OT0D1E#HD/W__\=$)$0`````@\04D+@#````*T0D,(E$
+M)"R+5"1(C01`C1S%`````(T$DHT$@(T$0HT$0XNT)'@&``"-%#!FBWH49H7_
+M#X3_`0``9HM"$HM,)"B+M"2(!@``9HD$3HG-T>6-="1`9HM*(&:)3#4`BU0D
+M3(T$DHT$@(T$0HT$0P.$)'@&``!F.T@@?@EFBT`@9HE$-0"+;"0HT>5FBT0L
+M0(G"9L'J#P'09M'X9HE$+$"-1"0XB40D((M4)$@/M_>+7"0LC0Q;P>$"C022
+MC02`C01"C00!`?"+E"1X!@``9HM<0AZ+1"0 at 9HE<!0"+5"1,C022C02`C01"
+M`<&-!#&+E"1X!@``9CM<0AY^#F:+1$(>BTPD(&:)1`T`BUPD*-'C9HM$'#B)
+MPF;!Z@\!T&;1^&:)1!PXC80D4`0``%`/M_]7BU0D4(T$DHT$@(T$0HM4)#2-
+M-%+!Y at .-!$8#A"2`!@``C5`64H/`(%`/OT0<2%`/OT0<5%#_="1`Z*+\__^-
+MA"1L`@``4%>+5"1PC022C02`C01"C01&`X0DG`8``(U0%E*#P"!0#[]$'&10
+M#[]$''!0_W0D7.AE_/__OP````"#Q#AFBT0<.&8[1!Q`='8/MTPD-HE,)!R+
+M;"0HT>6)]HM<)"C!XP8!^P^_C%Q0`@``#[^T7%`$``"+5"1,BX0D>`8```^W
+M%%")5"0(BT0D2(N4)'@&```/MP1"45;_="004/]T)"SH0?W__X/$%&:)1%Q0
+M1V:+1"PX9BM$+$`/M\`Y^'>;_T0D*/]$)#"#?"0P`P^&M/W__XM4)$"+A"2`
+M!@``9HD0OP````#'1"0P`````#M\)"@/@\T!``"-=@"+1"0H2#M$)#!U&8M,
+M)#!FBT1,.(/`!(N<)(0&``!FB01+ZRJ+5"0PT>(/OT04.`^_5!1"`=")PL'J
+M'P'0T?B+="0PBY0DA`8``&:)!'*Y`````(-\)#``=!Z+7"0PB[0DA`8```^W
+M3%[^#[]$7$`IP0^W1"0T*<&+5"0PP>('9HM$%%*)PV8K7!10B=AFA=MU!;@!
+M````B<.%R7DSBT0D,,'@!P^WTV:+;`10B=`/K\&)^T>^`````&8!Z'@"B<:+
+MA"2,!@``9HDT6$%XWHGVBT0D,-'@#[]4!#B)5"0,#[]4!$`I5"0,BUPD,(NT
+M)(0&```/MRQ>#[=$)#0!Q2G5BT0D#(E$)"0YZ'8$B6PD)`^_1"0DB<,YR'XB
+MBU0D,,'B!HGVC00*06:+1$10B[0DC`8``&:)!'Y'.<M_YXM$)##!X`8#1"0,
+M9HM41$Z)TV8K7$1,B=AFA=MU!;@!````B<,[;"0D=E`/O\4YR'Y)BT0D,,'@
+M!@-$)`QFBT1$3F:)1"0:B<@K1"0D#[?3#Z_"9 at -$)!J)_D>)PF:#^']^!;I_
+M````BX0DC`8``&:)%'!!#[_%.<A_S/]$)#"+5"0H.50D,`^"-O[__X-\)#`#
+M=R&-=@"+3"0PBYPDA`8``&:+1$O^9HD$2T&)3"0P at _D#=N*#_W]W%Y"+M"2,
+M!@``9HM$?OYFB01^1X/_?W;J@<1<!@``6UY?7<.-=@!55U93@^PLBWPD0(M,
+M)$R)_8NW!"\```^W00(ET````#W`````=`<]T````'4(C9V8%```ZQ\/MT$"
+M):````"Z`````#V@````#X4'`0``C9_T$@``BT<4BX!LH@``@^`/9HD$)%;_
+M="14C40D(%"-1"0B4`^W1"004%,/MP%05^B3^O__BT\4BY%8H@``@.8_#[=#
+M$$C!X`XE`,````G"B9%8H@``@\0 at 9H-\)!8`=!!FBT0D%O?89HF%@!D``.L)
+M9L>%@!D`````NX"B``"Y``````^V%,X/MD3.`L'@"`G"#[9$S at 3!X!`)P@^V
+M1,X&P>`8"<*+1Q2)%!B#PP1!@_D?=L^+7Q2+%"2#X@\/MT0D&,'@!"7P`P``
+M"<*-3"08#[=!`L'@"B4`_```"<(/MT$$P>`0)0``/P`)P@^W00;!X!8E``#`
+M#PG"B9-LH@``N@$```")T(/$+%M>7UW#4X/L"(M<)!"#NP0O````=!N#[`S_
+MLP0O``#H_/___\>#!"\```````"#Q!"#NW at 9````=!N#[`S_LW at 9``#H_/__
+M_\>#>!D```````"#Q!"#Q`A;PXUV`%93@^P0BW0D((M<)!QHA````.C\____
+MB8-X&0``@\00A<!U",<&`@```.MPQX,(+P````$``(/L#&@``0``Z/S___^)
+M at P0O``"#Q!"%P'4(QP8"````ZT3'@\@6``!H:P$`QX/,%@``(%T!`,>#T!8`
+M`,AB`0#'@]06``#\70$`QX/8%@``0&`!`,>#W!8```AJ`0"X`0```(UV`(/$
+M!%M>PP`````````````X!P``2P<``$L'``!5!P``4`@``%\'``!I!P``>0<`
+M`%`(``")!P``G0<``.X'``"U!P``R@<``-P'``#]!P`````%``H`%``>`#(`
+M1@!5`%H`7P!D````"@`4`!X`*``R`#P`1@!0`%H`9`#"````Q````,4```#0
+M````V@```.0```#"````PP```-0```#R````#0$``"@!````````3D].10``
+M`````/\!1D-#```````0`$@#34M+``````!``(@!151320`````W`#H#````
+M`````````````````/\!``"?````H@````$````!`````0``````$`"H````
+MJP````$````!`````0````@``P"Z````O0````$``````````0````P``P#%
+M````R`````$``````````0```"``1P#0````TP```````````````````#,`
+M,`#=````X`````$``````````0```"0`(0#H````ZP````$````!`````0``
+M`"@`.0#U````^`````$``````````0```!\`,````0```P$```$````!````
+M`0```#```P`.`0``$0$```$``````````0```'```P`9`0``'`$```$`````
+M`````0```#@`,``D`0``)P$```$``````````0```%0`50`O`0``,@$```$`
+M```!`````0```$0`50`Y`0``/`$```$````!`````0```$P`"`!#`0``1@$`
+M`````````````````&``4@!-`0``4`$```$````!`````0```&0`-`!B`0``
+M90$```$``````````0```'P`(`!N`0``<0$```$````!`````0```)@`6`!X
+M`0``>P$````````!`````````)P`4@"!`0``A`$```$````!`````0```*H`
+M$`"*`0``C0$```$``````````0```+P``P"6`0``F0$```$``````````0``
+M`+\`-@"D`0``IP$```$``````````0```,0`-P"O`0``L@$```$````!````
+M`0```,L`-@"Y`0``O`$``````````````````-``-P#+`0``S@$```$`````
+M`````0```-8`$`#6`0``V0$```$````!`````0```-H``P#L`0``[P$`````
+M`````````````#(#`P#W`0``^@$```$``````````0```-X``P```@```P(`
+M``$``````````0```.D`-P`/`@``$@(```$``````````0```/8`-P`:`@``
+M'0(```$``````````0```/H`-@`E`@``*`(```$``````````0```/\`-@`O
+M`@``,@(```$``````````0````P!,``]`@``0`(```$````!`````0```!0!
+M-P!(`@``2P(```$``````````0```"P!`P!3`@``5@(```$``````````0``
+M`$`!$`!=`@``8`(```$````!`````0```%0!`P!J`@``;0(```$`````````
+M`0```%@!(0!V`@``>0(```$````!`````0```%P!-0"#`@``A@(```$`````
+M`````0```&`!-P".`@``D0(```$``````````0```&0!`P"9`@``G`(```$`
+M`````````0```&@!`P"B`@``I0(```$``````````0```&P!4@"O`@``L@(`
+M``$````!`````0```'0!-P"W`@``N@(```$``````````0```'@!`P#"`@``
+MQ0(```$``````````0```'P!-P#,`@``SP(```$``````````0```(@!0`#5
+M`@``V`(```$``````````````(D!00#>`@``X0(```$``````````````(H!
+M2`#H`@``ZP(```$``````````````(L!0P#R`@``]0(```$`````````````
+M`(P!2@#\`@``_P(```$``````````````(T!2P`&`P``"0,```$`````````
+M`````)`!`P`0`P``$P,```$``````````0```(X!`P`:`P``'0,```$`````
+M`````0```)@!10`H`P``*P,```$````!`````0```)H!10`W`P``.@,```$`
+M`````````````)L!20!)`P``3`,```$``````````````)X!`P!<`P``7P,`
+M``$``````````0```*P!`P!F`P``:0,```$``````````0```*8!`P!P`P``
+M<P,```$``````````0```+8!-0![`P``?@,```$``````````0```+@!-P",
+M`P``CP,```$``````````0```+H!-P"9`P``G`,```$``````````0```+X!
+M(0"G`P``J@,```$````!`````0```"<#`P"P`P``LP,```$``````````0``
+M`,H!`P"]`P``P`,``````````````````.0!$`#)`P``S`,```$````!````
+M`0```.P!,`#3`P``U@,```$````!`````0```/@!`P#=`P``X`,```$`````
+M`````0```!`"-P#H`P``ZP,```$``````````0```"H"(@#W`P``^@,```$`
+M`````````0```$("-P`&!```"00```$``````````0`````"`P`0!```$P0`
+M``$``````````0```$H"`P`8!```&P0```$``````````0```$\"$``D!```
+M)P0```$````!`````0```%P"`P`N!```,00```$``````````0```&`"$0`V
+M!```.00```$````!`````0```&@"-P!%!```2`0```$``````````0```&P"
+M-P!/!```4 at 0```$``````````0```'8"$`!;!```7 at 0```$````!`````0``
+M`'H"`P!J!```;00```$``````````0```(("`P!S!```=@0```$`````````
+M`0```(,"`P!^!```@00```$``````````0```*H"`P"(!```BP0```$`````
+M`````0```+X"0@"8!```FP0```$````!`````0```+\"-@"E!```J`0```$`
+M`````````0```,$"-P"X!```NP0```$``````````0```,8"-P#$!```QP0`
+M``$````!`````0```-0"-P#4!```UP0```$``````````0```/`"-P#=!```
+MX`0```$``````````0```/0"-0#G!```Z at 0```$``````````0```/@"`P#V
+M!```^00```$``````````0```)X`1P#_!````@4```$````!`````0```/P"
+M10`)!0``#`4```$````!`````0````P#,``5!0``&`4```$``````````0``
+M`!0#-@`J!0``+04```$``````````0```!@#-@`U!0``.`4```$`````````
+M`0```"0#`P`_!0``0 at 4```$``````````0```!`#`P!*!0``304```$`````
+M`````0```#H#-P!B!0``904```$``````````0```$@#$`!T!0``=P4```$`
+M```!`````0```%H#10"%!0``B`4```$``````````0```%P#.@"0!0``DP4`
+M``$````!`````0```%X#5@">!0``H04```$``````````0```,`"`P"K!0``
+MK at 4```$``````````0```'<#`P"W!0``N at 4```$``````````0```,P"`P#`
+M!0``PP4```$``````````0````````````````#_`?\!`P"8`9D!!P"8`3`+
+M"`"8`3`,(``@`1`*(0`@`9D!(@`@`3`,.@!@`1`*-P`P`9D!-0`P`ID!-@`P
+M`YD!,``P!)D!.0`P!9D!-``P!ID!,@`P`YD!,0`P`YD!$0`0`9D!$``0`1`*
+M4@!0`9D!10!0`ID!1P!0`YD!0@!0!)D!6`!0!9D!50!0`3`,5@!0`C`,20!0
+M`E`-0`!``4`*00!``4`*0P!``D`*2`!``1`*2@!``4`*2P!``4`*8`!@`&``
+M80!A`&$`8@!B`&(`8P!C`&,`9`!D`&0`90!E`&4`9@!F`&8`9P!G`&<`:`!H
+M`&@`:0!I`&D`:@!J`&H`````````````````````````````````````````
+M_P$"`!```!1$%@4&<1;!%@4&````````````````4`$!`!``<1;!%AX`````
+M````````````````````4`(!`!``<1:M%A<`````````````````````````
+M4`,"`!``H!3(%!$&<1:M%AX&````````````````4`0"`!``/!1X%!0`<1;!
+M%A0`````````````````4`4"`!``<1;!%A$`````````````````````````
+M,`$"`#``/!3(%!0`?!5$%AL`````````````````,`(!`#``/!1X%!(`````
+M````````````````````,`,!`#``/!3(%!0`````````````````````````
+M,`0!`#``/!3(%!(`````````````````````````,`4!`#``/!1X%`\`````
+M````````````````````,`8"`#``/!2@%!<`?!5$%AX`````````````````
+M$`$#`!``C!3(%!<&/!1X%!$&<1;!%AX&````````(`$"`!``/!3(%!<&<1;!
+M%AX&````````````````8`$$`!``/!1X%!$&C!3(%!0&?!5$%A0&<1;!%AX&
+M0`$!`$``,A1N%!<`````````````````````````0`(#`$``,A1N%!<`L!/8
+M$Q<`.!-T$Q<```````````#_`0(`$P`*%"86!08>%!(6!08`````````````
+M```0`0,`$P""%*H4%P9:%%H4$0:`%J at 6'@8```````!@`0,`$P""%*H4%P9:
+M%%H4$0:`%J at 6'@8```````!@`00`$P!X%*`4%P90%%`4$0:%%JT6'@:D%1P6
+M'@80"@$`$0``````````````````````````````````````````````_P$#
+M`/\`"`E$"04&A0F%"04&T`FL"@4&````````$`H!`!0`A0F%"10&````````
+M````````````````,`H!`#0`A0F%"10&````````````````````````,`L!
+M`#0`A0F%"10&````````````````````````,`P!`#0`A0F%"10&````````
+M````````````````0`H!`$0`A0F%"10&````````````````````````F0$!
+M`#0`A0F%"10&``````````````````````````````````````````#_`00`
+M_P`("40)!09L":@)!0:T";0)!0;0":P*!090#0(`_P!L":@)%``("40)%```
+M```````````````P"@$`_P"9":@)%``````````````````````````P"P$`
+M,0"`"8H)%``````````````````````````P#`$`,0!L":@)'@``````````
+M```````````````0"@$`$0!L"9X)&P8```````````````````````!`"@(`
+M00!L":@)%`"T";0)%`````````````````"9`0$`,0!L":@)%```````````
+M````````````````````_P``````````````````````````````````````
+M``````````````````!@`````0`````````*````.`$``$`!``!(`0``:`$`
+M`'`!``!X`0``@`$``(@!``"H`0``L`$``&8````!``````````D````X`0``
+M0`$``%`!``!H`0``<`$``'@!``"``0``D`$``+`!````````9P````$`````
+M````"0```#@!``!``0``2`$``&@!``!P`0``>`$``(`!``"(`0``L`$`````
+M``!H`````0`````````)````.`$``$`!``!(`0``:`$``'`!``!X`0``@`$`
+M`(@!``"P`0```````&$```````````````@````X`0``0`$``$@!``!H`0``
+M@`$``(@!``"H`0``L`$`````````````8@````(````L`0``"@```#@!``!`
+M`0``2`$``&@!``!P`0``>`$``(`!``"(`0``J`$``+`!``!C`````0``````
+M```(````.`$``$`!``!(`0``:`$``'`!``!X`0``B`$``+`!````````````
+M`&0```````````````<````X`0``6`$``&@!``!P`0``>`$``)@!``"P`0``
+M````````````````90``````````````!0```#@!``!(`0``:`$``(@!``"P
+M`0````````````````````````````!I```````````````(````.`$``%@!
+M``!H`0``<`$``'@!``"``0``F`$``+`!`````````````&H`````````````
+M``8````X`0``2`$``&@!``"``0``B`$``+`!````````````````````````
+M````````````````````````````````8`````$`````````"0```#@!``!`
+M`0``4`$``&@!``!P`0``>`$``(`!``"0`0``L`$```````!F`````0``````
+M```)````.`$``$`!``!0`0``:`$``'`!``!X`0``@`$``)`!``"P`0``````
+M`&<````!``````````D````X`0``0`$``$@!``!H`0``<`$``'@!``"``0``
+MD`$``+`!````````:`````$`````````"0```#@!``!``0``2`$``&@!``!P
+M`0``>`$``(`!``"0`0``L`$```````!A```````````````'````.`$``$`!
+M``!0`0``:`$``(`!``"0`0``L`$``````````````````&(````"````+`$`
+M``D````X`0``0`$``%`!``!H`0``<`$``'@!``"``0``D`$``+`!````````
+M8P````$`````````"````#@!``!``0``4`$``&@!``!P`0``>`$``)`!``"P
+M`0````````````!D```````````````'````.`$``&`!``!H`0``<`$``'@!
+M``"@`0``L`$``````````````````&4```````````````4````X`0``8`$`
+M`&@!``"@`0``L`$`````````````````````````````:0``````````````
+M"````#@!``!@`0``:`$``'`!``!X`0``@`$``*`!``"P`0````````````!J
+M```````````````&````.`$``&`!``!H`0``@`$``*`!``"P`0``````````
+M`````````````````````````````````````````````$`!B`%``0``N`$`
+M`!`!2`-0`0``P@$``#`!$`)``0``S@$```(`4`$!`$`!!`"@``@`P``@`-``
+MN#P``)@\``"J/```N#P``)X\``"X/```N#P``+@\``"D/```N#P``+@\``"X
+M/```N#P``+@\``"X/```N#P``+@\``"X/```N#P``+@\``"X/```N#P``+@\
+M``"X/```N#P``+@\``"X/```N#P``+@\``"X/```N#P``+@\``"P/```BCT`
+M`)$]``"\/0``F#T``+P]``"\/0``O#T``+P]``"?/0``O#T``*8]``"M/0``
+MC!2@%+04R!0``'P5D!6D%;@5S!7@%?05"!8<%C`61!8`````0`$"`,P6``#6
+M%@``````````````````````````````````````````````````8`$Z`$`!
+M``#P%@``,`$``$`!````````,`(``$`!````````,`,``$`!````````,`0`
+M`$`!````````,`4``$`!````````,`8``$`!````````,`H``$`!````````
+M,`L``$`!````````,`P``$`!````````:`!H`$`!````````0`)#`$`!````
+M````0`I#`*``````````0`I#`,``````````0`%!`$`!````````0`I!`*``
+M````````0`I!`,``````````0`!#`$$`2`!*`$L````````````D`9 at 9`"D1
+M!```````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````X%4`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````"8``!'````")@````````,F```IHZ$"1"8````
+MX#(]%)@``&L'```<F````````""8`````@("))@```X.```HF````0(""BR8
+M``#\;P,`,)@````````TF```#@X``#B8```'````/)@````!`@!`F`````!C
+MB428``"<%G(32)@``#.V&`!,F```/&&$$E"8``#@N. at -5)@``%E(!P!8F```
+MNKZ`?ER8``!>9CHQ8)@```@=``!DF````,X!`&B8``"009I`<)@```\```!T
+MF```@````'B8```$`````)D````````$F0````````B9````````#)D`````
+M@``0F0```P````";````````!)L``"`````(FP``$`````R;```P````$)L`
+M``@````4FP``*````!B;```H````')L```0````@FP``)````"2;```4````
+M*)L``#0````LFP``#````#";```L````-)L```(````XFP``(@```#R;```2
+M````0)L``#(```!$FP``"@```$B;```J````3)L```$```!0FP``(0```%2;
+M```1````6)L``#$```!<FP``"0```&";```I````9)L```4```!HFP``)0``
+M`&R;```5````<)L``#4```!TFP``#0```'B;```M````?)L```,```"`FP``
+M(P```(2;```3````B)L``#,```",FP``"P```)";```K````E)L```<```"8
+MFP``)P```)R;```7````H)L``#<```"DFP``#P```*B;```O````K)L``"\`
+M``"PFP``+P```+2;```O````N)L``"\```"\FP``+P```,";```O````Q)L`
+M`"\```#(FP``+P```,R;```O````T)L``"\```#4FP``+P```-B;```O````
+MW)L``"\```#@FP``+P```.2;```O````Z)L``"\```#LFP``+P```/";```O
+M````])L``"\```#XFP``+P```/R;```O`````)H``!T````$F@``70````B:
+M``"=````#)H``-T````0F@``'0$``!2:```A````&)H``&$````<F@``H0``
+M`"":``#A````))H``#$````HF@``<0```"R:``"Q````,)H``!P````TF@``
+M7````#B:```I````/)H``&D```!`F@``J0```$2:```@````2)H``!D```!,
+MF@``60```%":``"9````5)H``#````!8F@``!0```%R:```E````8)H``&4`
+M``!DF@``I0```&B:```H````;)H``&@```!PF@``'P```'2:```>````>)H`
+M`!@```!\F@``6````(":``"8````A)H```,```"(F@``!````(R:``!$````
+MD)H``(0```"4F@``$P```)B:```2````G)H``%(```"@F@``D@```*2:``#2
+M````J)H``"L```"LF@``*@```+":``!J````M)H``*H```"XF@``&P```+R:
+M```:````P)H``%H```#$F@``F@```,B:``#:````S)H```8```#0F@``!@``
+M`-2:```&````V)H```8```#<F@``!@```.":```&````Y)H```8```#HF@``
+M!@```.R:```&````\)H```8```#TF@``!@```/B:```&````_)H```8```#4
+MF```(````,R8```$````R)@```8!!@"<F```;0```,"8````````T)@``!0`
+M```)"0```````@(&!@8&!@8"`@````,`!@`)`#P`````````````````````
+M``````````````````````````#P````S`````````````````````KB````
+M(```"@(```$8```!````0!@$````````````````````````````````````
+M````!017&0`I$00`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````-R(````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````!L"8\)M`D`````````````````
+M```````````````````````@````(````$````!````````&````!@````8`
+M,````!4````5````'0```!4```!`$```#_PO``_\+P`?_"\`#_PO`$00```/
+M_"\`#_PO`!_\+P`/_"\`2!````_\+P`/_"\`'_PO``_\+P!,$```#_PO``_\
+M+P`?_"\`#_PO`%`0```/_"\`#_PO`!_\+P`/_"\`5!````_\+P`/_"\`'_PO
+M``_\+P!8$```#_PO``_\+P`?_"\`#_PO`%P0```/_"\`#_PO`!_\+P`/_"\`
+M8!````_\+P`/_"\`'_PO``_\+P!D$```#_PO``_\+P`?_"\`#_PO`'`0``!H
+M`0``X`$``+@!``!H`0``,!```#`"``#@`0``L````#`"``"P$```F`T``(`1
+M``!('P``F`T``/`0``#@H```:$`!`(!8``#@H```%(`````$``0`"``(`#``
+M(``$``0<@```IX^-#L^/C0Z5CV`!IX^-#@28`````````P``````````````
+M()@````"`@(``@("``(!`@`"`@(DF```#@X```X.```'!P``#@X``"B8```!
+M``(*`0`""@```04!``(*-)@```X.```.#@``#@X```X.```XF```!P````<`
+M```+````"P```$28``"<%G(3I19R$Z at 6<A.<%G(32)@``&>Z&`!GNA@`:;H8
+M`&FZ&`!0F```X+0H#."T*`S at M"@,X+0H#%B8```N#8!^+ at V`?BX-P'XN#8!^
+M7)@``%Y=-S%>73<Q7ETZ,5Y=-S%@F```$+T``!"]```XO0``$+T``&28````
+MS@$``,X!``#.`0``S@$`%)D``!`G```0)P``?!4``!`G```8F0``D`$``)`!
+M``"$````D`$``$29```@$.!O(!#@;R`)X&\@$.!O@*$``/\4_P7_%/\%_Q3_
+M!?\9_P74F```$````!0````0````$``````````,`````````"@```"<G(2$
+M+````'Q\?'PT````!0```$``````````1`````@```!(````"````$P````0
+M````4`````````!4````'P`````(````````!`@````````("`````````P(
+M````````$`@````````4"````````!@(````````'`@````````@"```````
+M`"0(````````,!(````````$@`````````B`````````#(`````````8@```
+M`````"2`````````*(```#`````L@```__\'`#"```#___\!-(```#$````X
+M@````````#R`````````0(````````!$@````@```$B`````````5(``````
+M``!8@`````````B8````````#)@``).0A"T0F````.`R?128``!K#P``')@`
+M```````LF```_F\"`#"8````````/)@````!`@!`F```>@%J($R8```\8802
+M5)@``%D(``!HF```D$&:0&R8``"!L`P%<)@```\```!TF```@````'B8```,
+M`````)D````````$F0````````B9````````#)D`````@``0F0```0```!R9
+M```J"0``()D````````DF0``!8H%`"B9```!````+)D````````PF0``````
+M`#29````````.)D````````\F0``/P```$"9```$````2)D```````!,F0``
+M`````%"9````````5)D``$SQ4%U8F0``&````%R9``".:DL`A*$``/\%_P:(
+MH0``_P?_!XRA``#_"/\(D*$``/\)_PF4H0``_PK_"IBA``#_"_\+G*$``/\,
+M_PR at H0``_PW_#:2A``#_#O\/J*$``/\2_Q*LH0``_Q/_%+"A``#_%?\6M*$`
+M`/\7_QFXH0``_QK_&[RA``#_'?\>P*$``/\@_R/$H0``_R7_)\BA``#_*?\L
+MS*$``/\O_S'0H0``_S3_-]2A``#_.O\ZV*$``/\Z_SK<H0``_SK_.N"A``#_
+M.O\ZY*$``/\Z_SKHH0``_SK_.NRA``#_.O\Z\*$``/\Z_SKTH0``_SK_.OBA
+M``#_.O\Z_*$``/\Z_SH`FP````````2;```@````")L``!`````,FP``,```
+M`!";```(````%)L``"@````8FP``!````!R;```D````()L``!0````DFP``
+M-````"B;```,````+)L``"P````PFP```@```#2;```B````.)L``!(````\
+MFP``,@```$";```*````1)L``"H```!(FP``!@```$R;```F````4)L``!8`
+M``!4FP``-@```%B;```.````7)L``"X```!@FP```0```&2;```A````:)L`
+M`!$```!LFP``,0```'";```)````=)L``"D```!XFP``!0```'R;```E````
+M@)L``!4```"$FP``-0```(B;```-````C)L``"T```"0FP```P```)2;```C
+M````F)L``!,```"<FP``,P```*";```+````I)L``"L```"HFP``*P```*R;
+M```K````L)L``"L```"TFP``*P```+B;```K````O)L``"L```#`FP``*P``
+M`,2;```K````R)L``"L```#,FP``*P```-";```K````U)L``"L```#8FP``
+M*P```-R;```K````X)L``"L```#DFP``*P```.B;```K````[)L``"L```#P
+MFP``*P```/2;```K````^)L```(```#\FP``%@```-28```@````V)@``&@0
+M8`````````````":``"I`0````````2:``#I`0``0`````B:```I````@```
+M``R:``!I````4`$``!":``"9`0``D`$``!2:``#9`0``T`$``!B:```9````
+M$````!R:``!9````1````"":``"9````A````"2:``"E`0``2`$``"B:``#E
+M`0``B`$``"R:```E````R`$``#":``#(`0``%````#2:```(````0@```#B:
+M``!(````@@```#R:``"(````>`$``$":``"8`0``N`$``$2:``#8`0``^`$`
+M`$B:```8````$@```$R:``!8````4@```%":``"8````D@```%2:``"D`0``
+M?`$``%B:``#D`0``O`$``%R:```D````_`$``&":``!D````"@```&2:``"D
+M````2@```&B:``#D````B@```&R:```*`0``6@$``'":``!*`0``F@$``'2:
+M``"*`0``V@$``'B:``#*`0``#@```'R:```*````3@```(":``!*````C@``
+M`(2:``"*````7@$``(B:``"Z`0``G@$``(R:``#Z`0``W@$``)":```Z````
+M"0```)2:``!Z````20```)B:``"&`0``B0```)R:``#&`0``>0$``*":```&
+M````N0$``*2:``!&````^0$``*B:``"&````.0```*R:``#&````>0```+":
+M``#&````N0```+2:``#&````O0$``+B:``#&````_0$``+R:``#&````/0``
+M`,":``#&````?0```,2:``#&````O0```,B:``#&````_0```,R:``#&````
+M_0```-":``#&````_0```-2:``#&````_0```-B:``#&````_0```-R:``#&
+M````_0```.":``#&````_0```.2:``#&````_0```.B:``#&````_0```.R:
+M``#&````_0```/":``#&````_0```/2:``#&````_0```/B:``#&````_0``
+M`/R:``#&````_0````$```!&````8`````$```!&````80````$```!&````
+M8@````$```!&````8P````$```!&````9`````$```!&````90````$```!&
+M````9@````$```!&````9P````$```!&````:`````$```!&````:0````$`
+M``!&````:@````$```!&````:P````$```!&````;`````$```!&````=```
+M``$```!&````=`````$```!&````=`````$```!&````=`````$```!&````
+M=`````$```!&````=`````$```!&````=`````$```!&````=`````$```!&
+M````=0````$```!&````=@````$```!&````=P````$```!&````>`````$`
+M``!&````>0````$```!&````>@````$```!&````>P````$```!&````?```
+M``$```!&````?0````$```!&````?@````$```!&````?P````$```!&````
+M@`````$```!$````?`````$```!&````B`````$```!&````C`````$```!&
+M````D`````$```!&````E`````$```!&````F`````$```!&````G`````$`
+M``!&````H`````$```!&````I`````$```!&````J`````$```!&````K```
+M``$```!&````L`````$```!&````M``````"!P````,`!@`)`#P```!CNP``
+M8[L``(V[``"-NP``M[L``+>[``#ANP``X;L`````````````"0````0````$
+M``$``0`!``8```!&1S@`````````````````!`````$``0`$````1D<W````
+M``````````````,``0`!``$``P```$9'-@`````````````````$```````!
+M``$```!&1S4`````````````````!``!``$`````````1D<T````````````
+M``````0````!````_O___T9',P`````````````````#``$``0```/W___]&
+M1S(`````````````````!`````````#\____1D<Q``````````````````(`
+M`0`!````^O___T9',```````````````````````````````````````````
+M````````````%!!4&0`I$00`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!L"8\)M`D("6P)M`G)
+M____R?___\G____)____PO____+____R____\O____+____T____P/___\#_
+M___`____P/___[K___^R____LO___[+___^R____L/___RWB``#FX0``\^$`
+M`&SB```,X@``7^(````````````````````````@````(````$````!`````
+M```&````!@````8`?.\``-#N```.[P``'>\``"3O```S[P``?.\``'SO``!\
+M[P``?.\``'SO``!\[P``?.\``'SO``!\[P``?.\``%KO````````````````
+M````````````````````````0!````_\+P`/_"\`'_PO``_\+P`/_"\`1!``
+M``_\+P`/_"\`'_PO``_\+P`/_"\`2!````_\+P`/_"\`'_PO``_\+P`/_"\`
+M3!````_\+P`/_"\`'_PO``_\+P`/_"\`4!````_\+P`/_"\`'_PO``_\+P`/
+M_"\`5!````_\+P`/_"\`'_PO``_\+P`/_"\`6!````_\+P`/_"\`'_PO``_\
+M+P`/_"\`7!````_\+P`/_"\`'_PO``_\+P`/_"\`8!````_\+P`/_"\`'_PO
+M``_\+P`/_"\`9!````_\+P`/_"\`'_PO``_\+P`/_"\`,!```#`"``#@`0``
+ML````&`!``#@`0``<!```&@!``#@`0``N`$``(P!``#@`0``L!```&`.``"`
+M$0``'!\``#@^``"`$0``\!```."@``!H0`$`@%@``."P``!H0`$`%(```.@#
+MZ`/@!N`&(`0@!$`(0`C@!N`&!)@````````#```````````````#````()@`
+M```"`@(``@("``(!`@`"`@(``@("))@```X.```.#@``!P<```X.```.#@``
+M1)@``!P6<A,E''(3*!=R$Z(6<A,E''(38)@``!"=```0G0``&)T``!B=```0
+MG0``9)@```#.`0``S@$``,X!``#.`0``S@$`:)@``)!!FD"009I`D$&:0)!!
+MFD"009I`&)D``+@!``"X`0``A`````@!``"X`0``))D```6*!1`%B at 40!8H%
+M$`6*!1`%B at 40,*(```````````````````@!```````````````````,````
+M`````#0````%````0`````````!$````"````$@````(````3````!````!0
+M`````````%0````?``````@````````$"`````````@(````````#`@`````
+M```0"````````!0(````````&`@````````<"````````"`(````````)`@`
+M``````!P$@```````#@0````````>!````````"X$````````/@0````````
+M.!$```````!X$0```````+ at 1````````^!$````````X$@```````'@2````
+M````N!(```````#X$@```````#@3````````>!,```````"X$P```````/@3
+M````````.!0```````!X%````````+ at 4````````^!0````````X%0``````
+M`'@5````````N!4```````#X%0```````#@6````````>!8```````"X%@``
+M`````/@6````````.!<```````!X%P```````+ at 7````````^!<````````\
+M$````````'P0````````O!````````#\$````````#P1````````?!$`````
+M``"\$0```````/P1````````/!(```````!\$@```````+P2````````_!(`
+M```````\$P```````'P3````````O!,```````#\$P```````#P4````````
+M?!0````````$@`````````B`````````#(`````````8@````````""`````
+M````)(`````````H@```,````"R```#__P<`,(```/___P$T@```,0```#B`
+M````````/(````````!(@````````%2`````````6(````````!<@```_\?_
+M_\"````:,((JQ(```.`!W`7(@```$"=`'\R``````/0!T(```!P>``#4@```
+MJJH"`-B```!550`"W(````````#@@```_____^2```#__P``Z(````````#L
+M@````````/"`````````](````````#X@````````/R```"(`````(<`````
+M```$AP``C`````B'``#D````#(<``-4"```0AP```````!2'````````&(<`
+M`*`````<AP``R0$``""'```L````)(<``"P````HAP``,````"R'```\````
+M,(<``"P````TAP``+````#B'```P````/(<``#P```!`AP```````$2'````
+M````2(<```````!,AP```````%"'````````5(<```````!8AP```````%R'
+M````````8(<``-4```!DAP``WP```&B'```"`0``;(<``#H!``!PAP``=0``
+M`'2'``!_````>(<``*(```!\AP````````"!```"``$`!($```$````(@0``
+MP`````R!````````$($``&@!```4 at 0```````,"'`````0(#Q(<```0%!@?(
+MAP``"`D*"\R'```,#0X/T(<``!`1$A/4AP``%!46%]B'```8&1H;W(<``!P=
+M'A_ at AP````$"`^2'```$!08'Z(<```@)"@OLAP``#`T.#_"'```0$1(3](<`
+M`!05%A?XAP``&!D:&_R'```<'1X?")@````````,F```&8Z$K1"8````X"A]
+M%)@``&N?"IP<F````````$"8``!Z`6H at 5)@``%D(````F0````````29````
+M````")D````````,F0````"``!"9```!````')D``(`,```@F0`````0!2B9
+M```!````+)D```0````TF0``(B`?'CB9```-#`L*/)D``#\```!(F0``$K*`
+MDE29``"(X5!=6)D``/\```!<F0``CFI+`&B9``#.`P``<)D``!6U+QEXF0``
+M`0```'R9````````$*(``#-C@``4H@``$&P0`!BB``!@0)P`(*(``,8PB`$D
+MH@````0``"RB````````-*(``"`@("`XH@``("`@($"B```@"DDX1*(``+9[
+M``!(H@``_#__#P";````````*)L```P````XFP``$@```&2;```A````C)L`
+M`"T```"<FP``,P```````P`&``D`/```````````````````````````````
+M```````````)````!`````0``0`!``$````````````&````1D<X````````
+M``````````0````!``$````````````$````1D<W``````````````````,`
+M`0`!``$````````````#````1D<V``````````````````0```````$`````
+M```````!````1D<U``````````````````0``0`!````````````````````
+M1D<T``````````````````0````!``````````````#^____1D<S````````
+M``````````,``0`!``````````````#]____1D<R``````````````````0`
+M``````````````````#\____1D<Q``````````````````(``0`!````````
+M``````#Z____1D<P````````````````````````````````````````````
+M```````````````````````````````````````````(`````0````,`````
+M```````````````&````1D<W``````````````````(`````````````````
+M````````1D<V``````````````````$```````````````````#]____1D<U
+M``````````````````````````````````````#Z____1D<T````````````
+M`````````0`!``````````````#X____1D<S`````````````````````0`!
+M`````0`!``````#V____1D<R`````````````````````0````$``0`!````
+M``#S____1D<Q`````````````````````0````$``0````$```#P____1D<P
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````(````$
+M````!@````@````*````#`````X````0````8"\!`%HK`0!$+`$`^RT!`&4N
+M`0#H+@$`87(U,C$R06YI4&]L;```````````````,````!6````5@```%8``
+M`!6````5@```'(```*>/C1+/#X@)E0_@!*L/X!+/#X@)*)@```$``@H!``(*
+M``$!!0$``@H!``(*-)@```X.```.#@``#@X```X.```.#@``.)@```<````'
+M````"P````L````+````2)@``%K:&`!:VA@`:<H8`&G*&`!IRA@`4)@``."T
+MZ`W at M.@-X+3H#>"TZ`W at M.@-6)@``"X-@'XN#8!^+DWH?BY-Z'XN#8!^7)@`
+M`%YF-S%>9C<Q7F8W,5YF-S%>83<Q;)@``(&P#`6!L`P%@;`,!8"P#`6`L`P%
+M%)D``!`G```0)P``?!4``/@J```0)P``1)D``"`0N/<@$+CW(`VX]R`0N/<@
+M$+CW#*(``&I!+&1J02QD:D%`9&I!0&1J04!D'*(```J`@Q@*@(,8"H!S&`J`
+M at Q@*@(,8`````````````````````#`2````````+)@``/XO`@`\F`````$"
+M`$R8```\8802,)D``(-(``!`F0``!````'29````````^)D``!@````$H@``
+M``````BB``"(9S[0**(``+4!```\H@``KXG($P2;```@````")L``!`````,
+MFP``,````!";```(````%)L``"@````8FP``!````!R;```D````()L``!0`
+M```DFP``-````"R;```L````,)L```(````TFP``(@```#R;```R````0)L`
+M``H```!$FP``*@```$B;```&````3)L``"8```!0FP``%@```%2;```V````
+M6)L```X```!<FP``+@```&";```!````:)L``!$```!LFP``,0```'";```)
+M````=)L``"D```!XFP``!0```'R;```E````@)L``!4```"$FP``-0```(B;
+M```-````D)L```,```"4FP``(P```)B;```3````H)L```L```"DFP``*P``
+M`*B;```K````K)L``"L```"PFP``*P```+2;```K````N)L``"L```"\FP``
+M*P```,";```K````Q)L``"L```#(FP``*P```,R;```K````T)L``"L```#4
+MFP``*P```-B;```K````W)L``"L```#@FP``*P```.2;```K````Z)L``"L`
+M``#LFP``*P```/";```K````])L``"L```#XFP```@```/R;```6````````
+M`````````````````)R8`````````````````````````````)R8````````
+M`````````````````````)R8`````````````````````````````)R8````
+M`````````````````````````)R8`````````````````````````````)R8
+M`````````````````````````````)R8````````````````````````````
+M`)R8`````````````````````````````)R8````````````````````````
+M`````)R8`````````````````````````````)R8````````````````````
+M`````````)R8`````#@````X````.````#@````X`)R8````````````````
+M`````````````)R8`````````````````````````````)R8````````````
+M`,````"`````@````)R8``#Y``0`^0`$`/\`!`#]``0`_0`$`-28````````
+M``````0````$````!````````````````)H``*D!````````!)H``.D!``!`
+M````")H``"D```"`````#)H``&D```!0`0``$)H``)D!``"0`0``%)H``-D!
+M``#0`0``&)H``!D````0````')H``%D```!$````()H``)D```"$````))H`
+M`*4!``!(`0``*)H``.4!``"(`0``+)H``"4```#(`0``,)H``,@!```4````
+M-)H```@```!"````.)H``$@```""````/)H``(@```!X`0``0)H``)@!``"X
+M`0``1)H``-@!``#X`0``2)H``!@````2````3)H``%@```!2````4)H``)@`
+M``"2````5)H``*0!``!\`0``6)H``.0!``"\`0``7)H``"0```#\`0``8)H`
+M`&0````*````9)H``*0```!*````:)H``.0```"*````;)H```H!``!:`0``
+M<)H``$H!``":`0``=)H``(H!``#:`0``>)H``,H!```.````?)H```H```!.
+M````@)H``$H```".````A)H``(H```!>`0``B)H``+H!``">`0``C)H``/H!
+M``#>`0``D)H``#H````)````E)H``'H```!)````F)H``(8!``")````G)H`
+M`,8!``!Y`0``H)H```8```"Y`0``I)H``$8```#Y`0``J)H``(8````Y````
+MK)H``,8```!Y````L)H``,8```"Y````M)H``,8```"]`0``N)H``,8```#]
+M`0``O)H``,8````]````P)H``,8```!]````Q)H``,8```"]````R)H``,8`
+M``#]````S)H``,8```#]````T)H``,8```#]````U)H``,8```#]````V)H`
+M`,8```#]````W)H``,8```#]````X)H``,8```#]````Y)H``,8```#]````
+MZ)H``,8```#]````[)H``,8```#]````\)H``,8```#]````])H``,8```#]
+M````^)H``,8```#]````_)H``,8```#]````U)@``"````#4F```$````!0`
+M```0````$````!0```#8F```:!!@`&@08`!H$&``:!!@`&@08```````````
+M`)R8`````````````````````````````)R8````````````````````````
+M`````)R8`````````````````````````````)R8````````````````````
+M`````````)R8`````````````````````````````)R8```````0````$```
+M`!`````0````$)R8```````$````!`````0````$````!)R8````````````
+M`````````````````)R8`````````````````````````````)R8````````
+M`````````````````````)R8``````````````````H``````````)R8``#`
+M`#@`@``X`,``.`+``#@`P``X`)R8```&``(`!@`"``8````&``(`!@`"`)R8
+M``")````B0```(D```")````B0```)R8``"@````H````*````"@````H```
+M`)R8```'``0`!P`$``<`!``'``0`!P`$`-28```:````&@```!H````:````
+M&@``````````````G)@``$````!(````0````$````!`````G)@``!`````0
+M````$````!`````0````G)@```@````(````"`````@````(````G)@``$\`
+M``!/````3P```$\```!/````G)@``/$```#Q````80```/$```#Q````G)@`
+M`$^0``!/D```3)```$^0``!/D```G)@``%H2``!:$@``FA(``%H2``!:$@``
+MS)@```X````.````#P````X````.`````0```$8```!@`````0```$8```!A
+M`````0```$8```!B`````0```$8```!C`````0```$8```!D`````0```$8`
+M``!E`````0```$8```!F`````0```$8```!G`````0```$8```!H`````0``
+M`$8```!I`````0```$8```!J`````0```$8```!K`````0```$8```!L````
+M`0```$8```!T`````0```$8```!T`````0```$8```!T`````0```$8```!T
+M`````0```$8```!T`````0```$8```!T`````0```$8```!T`````0```$8`
+M``!T`````0```$8```!U`````0```$8```!V`````0```$8```!W`````0``
+M`$8```!X`````0```$8```!Y`````0```$8```!Z`````0```$8```![````
+M`0```$8```!\`````0```$8```!]`````0```$8```!^`````0```$8```!_
+M`````0```$8```"``````0```$0```!\`````0```$8```"(`````0```$8`
+M``",`````0```$8```"0`````0```$8```"4`````0```$8```"8`````0``
+M`$8```"<`````0```$8```"@`````0```$8```"D`````0```$8```"H````
+M`0```$8```"L`````0```$8```"P`````0```$8```"T````E3H!`'@Z`0!\
+M.@$`@#H!`)`Z`0"0.@$`A#H!`(@Z`0``````````````````````````````
+M```P````%8```!6````5@```%8```!6````<@```IY.-$L\3B`F5$^`$JQ/@
+M$L\3B`DHF````0`""@$``@H``0(%`0`""@$``@HTF```#@X```X.```.#@``
+M#@X```X.```XF```!P````<````+````"P````L```!(F```;=H8`&W:&`!U
+MRA@`=<H8`'7*&`!0F```X+3H#>"TZ`W at M.@-X+3H#>"TZ`U8F```+ at V`?BX-
+M@'XN#>A^+ at WH?BX-@'Y<F```7F8W,5YF-S%>9C<Q7F8W,5YF-S%LF```@;`,
+M!8&P#`6!L`P%@;`,!8&P#`44F0``T`<``-`'``!,!```F`@``-`'``!$F0``
+M(!"X]R`0N/<0#;CW$!"X]Q`0N/<$H@`````````````(````"`````@````(
+MH@``B&>^UHAGOM:(9S[0B&<^T(AG/M`,H@``0`$L9$`!+&1 at P4)D8,%"9&#!
+M0F0<H@``"H"#&`J`@Q@*@',8"H"#&`J`@Q at P$@```````"R8``#^+P(`/)@`
+M```!`@!,F```/&&$$C"9``""2```0)D```0```!TF0```````"BB``"U`0``
+M/*(``*^)R!,$FP```0````B;```"````#)L```,````0FP``!````!2;```%
+M````&)L```@````<FP``"0```"";```*````))L```L````LFP``#0```#";
+M```0````-)L``!$````\FP``$P```$";```4````1)L``!4```!(FP``&```
+M`$R;```9````4)L``!H```!4FP``&P```%B;```<````7)L``!T```!@FP``
+M(````&B;```B````;)L``",```!PFP``)````'2;```E````>)L``"@```!\
+MFP``*0```(";```J````A)L``"L```"(FP``+````)";```P````E)L``#$`
+M``"8FP``,@```*";```T````I)L``#4```"HFP``-0```*R;```U````L)L`
+M`#4```"TFP``-0```+B;```U````O)L``#4```#`FP``-0```,2;```U````
+MR)L``#4```#,FP``-0```-";```U````U)L``#4```#8FP``-0```-R;```U
+M````X)L``#4```#DFP``-0```.B;```U````[)L``#4```#PFP``-0```/2;
+M```U````^)L``!````#\FP``&@```````````````)H```<````'````!)H`
+M`$<```!'````")H``(<```"'````#)H``*`!``"@`0``$)H``.`!``#@`0``
+M%)H``"`````@````&)H``&````!@````')H``*$!``"A`0``()H``.$!``#A
+M`0``))H``"$````A````*)H``&$```!A````+)H``&(!``!B`0``,)H``*(!
+M``"B`0``-)H``.(!``#B`0``.)H``"(````B````/)H``&(```!B````0)H`
+M`&,!``!C`0``1)H``*,!``"C`0``2)H``.,!``#C`0``3)H``",````C````
+M4)H``&,```!C````5)H``(0!``"$`0``6)H``,0!``#$`0``7)H```0````$
+M````8)H``.H!```+````9)H``"H```!+````:)H``&H```"+````;)H``*H`
+M``"L`0``<)H``*L!``#L`0``=)H``.L!```L````>)H``"L````2````?)H`
+M`&L```!2````@)H``*L```"2````A)H``*P!``"3`0``B)H``.P!``#3`0``
+MC)H``"P````3````D)H``#H```!3````E)H``'H```"3````F)H``+H```"4
+M`0``G)H``+L!``#4`0``H)H``/L!```4````I)H``#L````Z````J)H``'L`
+M``!Z````K)H``+L```"Z````L)H``+P!``"[`0``M)H``/P!``#[`0``N)H`
+M`#P````[````O)H``'P```![````P)H``+P```"[````Q)H``/P```"\`0``
+MR)H``/P```#\`0``S)H``/P````\````T)H``/P```!\````U)H``/P```"\
+M````V)H``/P```#\````W)H``/P```#\````X)H``/P```#\````Y)H``/P`
+M``#\````Z)H``/P```#\````[)H``/P```#\````\)H``/P```#\````])H`
+M`/P```#\````^)H``/P```#\````_)H``/P```#\````U)@``"````#0F```
+M"`0&`P@$!P,(!`8#"`0&`P@$!P/<F```P,"@`,#`H`#`P.``P,#@`,#`X```
+M`````````)R8```````/````#P````\````/````#YR8````````````````
+M`````````````)R8`````(````"`````@````(````"``)R8`````"H````J
+M````*@```"H````J`)R8``````$````!`````0````$````!`)R8````````
+M`````````````````````)R8`````!@````8````&````!@````8`)R8````
+M`&````!@````;@```&X```!N`)R8`````,<```#'````QP```,<```#'`)R8
+M`````$L```!+````2P```$L```!+`)R8`````$@$``!(!```2`0``$@$``!(
+M!)R8`````$P```!,````3````$P```!,`)R8`````.0```#D````Y````.0`
+M``#D`)R8`````````````````````````````)R8`````/P```#\````_```
+M`/P```#\`)R8`````/\```#_````_P```/\```#_`)R8`````#\$```_!```
+M/P0``#\$```_!)R8``````P````,````#`````P````,`)R8`````!D"```9
+M`@``&0(``!D"```9`IR8`````"0````D````)````"0````D`)R8`````+0`
+M``"T````M````+0```"T`)R8`````)D```"9````F0```)D```"9`)R8````
+M`%````!0````4````%````!0`)R8`````"H````J````*@```"H````J`)R8
+M`````!(````2````$@```!(````2`)R8`````#+````RP```,L```#+````R
+MP)R8`````'0!``!T`0``=`$``'0!``!T`9R8`````!$````1````$0```!$`
+M```1`)R8`````"B&```HA@``*(8``"B&```HAIR8`````(0Q``"$,0``A#$`
+M`(0Q``"$,9R8``"``/(`@`#R`(``\@"``/(`@`#R`)R8```9`"<`&0`G`!D`
+M)P`9`"<`&0`G`)R8```#`````P````,````#`````P```)R8````````````
+M`````````````````)R8``"R````L@```+(```"R````L@```)R8``"$(+``
+MA""P`(0 at L`"$(+``A""P`)R8``"D)4$`I"5!`*0E00"D)4$`I"5!`)R8```@
+MDA$`()(1`""2$0`@DA$`()(1`)R8````2!H``$@:``!(&@``2!H``$@:`-B8
+M```P`@L`,`(+`#`""P`P`@L`,`(+`)R8``"4````E````)0```"4````E```
+M`)R8``"1````D0```)$```"1````D0```)R8```2````$@```!(````2````
+M$@```)R8``"`````@````(````"`````@````)R8``#9````V0```-D```#9
+M````V0```)R8``!@````8````&````!@````8````)R8``#P````\````/``
+M``#P````\````)R8``"B````H@```*(```"B````H@```)R8``!2````4@``
+M`%(```!2````4@```)R8``#4````U````-0```#4````U````)R8``#,%```
+MS!0``,P4``#,%```S!0``)R8``",!```C`0``(P$``",!```C`0``,28```#
+M`````P````,````#`````P```.A*`0#M2@$`U$H!`-A*`0#H2@$`Z$H!`-Q*
+M`0#@2@$````````````P````%0```!4````5````%0```!4````<@```IY.-
+M$L\3B`F5$^`$JQ/@$L\3B`DHF````0`""@$``@H```(%`0`""@$``@HTF```
+M``X````.````#@````X````.```XF````@````(````*````"@````H```!(
+MF```;=H8`&W:&`!D:AH`9&H:`&1J&@!0F```X+3H#>"TZ`W:L. at -VK"8#-JP
+MZ`U8F```+ at V`?BX-@'XN#>A^+ at W(?BX-@'Y<F```7F8W,5YF-S%>9C<Q7F`Y
+M,5YF-S%LF```@;`,!8&P#`6!L`P%@;`,!8&P#`44F0``T`<``-`'``!,!```
+MF`@``-`'``!$F0```!"X]P`0N/<`#;CW`!"X]P`0N/<$H@``````````````
+M```````````````(H@``B&>^UHAGOM:(9S[0B&<^T(AG/M`,H@``0`$L`$`!
+M+`!`P4(`0,%"`$#!0@`<H@``"H"#&`J`@Q@*@&,8"H"#&`J`@Q at P$@``X`,`
+M`&"````/````&($````````<@0```````""!````````)($````````H at 0``
+M`````"R!````````,($````````T at 0```````#B!````````/($```````!`
+M at 0``J```@$2!````````+)@```"@```\F`````0@`$R8```\(X02<)@``!\`
+M``!TF```@````'B8```.````@)D```````"$F0````"``J"9````````X)D`
+M``````#DF0``JJJJJNB9``!X9$8\[)D``*H```#PF0``#````/29``#_````
+M^)D``!0````HH@``M0D``#RB``"OB<B33*(```$```!0H@```*```%2B````
+M````6*(``(!3QPQ<H@```0\/#V"B```!#VE?9*(``!&*00!HH@```````&RB
+M``!JP3`,<*(``"`(@@!TH@``JGP;`'BB``#..><<?*(``,X!%P4`HP`````!
+M&`2C```")@,P"*,```8^!T@,HP``"DP+5A"C```/8!ID%*,``!MN3W at 8HP``
+M6GR/AARC``!;AL^.(*,```^73YTDHP``CZ'/I2BC```?KU^U+*,``)^YW[TP
+MHP``/\=_S32C``"_T?_5.*,````````\HP```````$"C````````1*,`````
+M``!(HP``____/TRC``#___\_4*,``/___S]4HP``__\#`%BC```?JJAY7*,`
+M``]";`9 at HP``!R(H#V2C``"%%F`7:*,```01@!]LHP```PR at -W"C``"#",0_
+M=*,```,(P%=XHP``@@;87WRC``""!.!_@*,``+I[/'^$HP``\'\P\P2;```!
+M````")L```(````,FP```P```!";```$````%)L```4````8FP``"````!R;
+M```)````()L```H````DFP``"P```"R;```-````,)L``!`````TFP``$0``
+M`#R;```3````0)L``!0```!$FP``%0```$B;```8````3)L``!D```!0FP``
+M&@```%2;```;````6)L``!P```!<FP``'0```&";```@````:)L``"(```!L
+MFP``(P```'";```D````=)L``"4```!XFP``*````'R;```I````@)L``"H`
+M``"$FP``*P```(B;```L````D)L``#````"4FP``,0```)B;```R````H)L`
+M`#0```"DFP``-0```*B;```U````K)L``#4```"PFP``-0```+2;```U````
+MN)L``#4```"\FP``-0```,";```U````Q)L``#4```#(FP``-0```,R;```U
+M````T)L``#4```#4FP``-0```-B;```U````W)L``#4```#@FP``-0```.2;
+M```U````Z)L``#4```#LFP``-0```/";```U````])L``#4```#XFP``$```
+M`/R;```:`````````````````````````````````````)H`````````````
+M!)H```````!`````")H```````"`````#)H```````"!`0``$)H```````#!
+M`0``%)H````````!````&)H```````!!````')H```````"!````()H`````
+M``!H`0``))H```````"H`0``*)H```````#H`0``+)H````````H````,)H`
+M``````!H````-)H```````")`0``.)H```````#)`0``/)H````````)````
+M0)H```````!)````1)H```````")````2)H```````"0`0``3)H```````#0
+M`0``4)H````````0````5)H```````!0````6)H```````"0````7)H`````
+M``"1`0``8)H```````#1`0``9)H````````1````:)H```````!1````;)H`
+M``````"1````<)H```````!X`0``=)H```````"X`0``>)H```````#X`0``
+M?)H````````X````@)H```````!X````A)H```````"9`0``B)H```````#9
+M`0``C)H````````9````D)H```````!9````E)H```````"9````F)H`````
+M``#9````G)H```````#Y````H)H```````#Y````I)H```````#Y````J)H`
+M``````#Y````K)H```````#Y````L)H```````#Y````M)H```````#Y````
+MN)H```````#Y````O)H```````#Y````P)H```````#Y````Q)H```````#Y
+M````R)H```````#Y````S)H```````#Y````T)H```````#Y````U)H`````
+M``#Y````V)H```````#Y````W)H```````#Y````X)H```````#Y````Y)H`
+M``````#Y````Z)H```````#Y````[)H```````#Y````\)H```````#Y````
+M])H```````#Y````^)H```````#Y````_)H```````#Y````U)@``"````#0
+MF```"!0``@@4`0((%``""!0``@@4`0+<F```P""@`,`@H`#`(.``P"#@`,`@
+MX````````````)R8``````#P````\````/````#P````\)R8````````````
+M`````````````````)R8```````#`````P````,````#`````YR8````````
+M`````````````````````)R8`````````````````````````````)R8````
+M`````````````````````````)R8`````````````````````````````)R8
+M`````````````````````````````)R8`````$!```!`0```0$```$!```!`
+M0)R8``````5E```%90``!64```5E```%99R8````````````````````````
+M`````)R8`````````````````````````````)R8`````$(```!"````0@``
+M`$(```!"`)R8`````+4```"U````M0```+4```"U`)R8``````,````#````
+M`P````,````#`)R8`````/<```#W````]P```/<```#W`)R8`````)T```"=
+M````G0```)T```"=`)R8`````"(````B````(@```"(````B`)R8`````"($
+M```B!```(@0``"($```B!)R8```8`",`&``C`!@`(P`8`",`&``C`)R8````
+M`"@````H`&``*`!@`"@`8``H`)R8``#``%``P`!0`,,`4`##`%``PP!0`)R8
+M``!_``0`?P`$`'\`!`!_``0`?P`$`)R8``!8!```6`0``%@$``!8!```6`0`
+M`)R8`````````````````````````````)R8````P````,````#`````P```
+M`,```-B8```P`D``,`)``#`"0``P`D``,`)`````````````````````````
+M`````````)R8````9````&0```!D````9````&0``)R8````"`````@````(
+M````"`````@``,R8```.````#@````X````.````#@```/1B`0#Y8@$`Y&(!
+M`.AB`0#T8@$`]&(!`.QB`0#P8@$`05(U,C$P`$%2-3(Q,0!!4C4R,3(`4D8U
+M,3$Q`%)&-3$Q,@!21C(T,3,`071H97)O<R`R,S$S(%=I4V]#`$%T:&5R;W,@
+M-3(Q,B`H1E!'02D`071H97)O<R`U,C$Q("A&4$=!*0!!=&AE<F]S(#4R,3``
+M071H97)O<R`U,C$Q`$%T:&5R;W, at -3,Q,B!7:5-O0P!!=&AE<F]S(#4R,3(`
+M1$(`1$5"54<`3D$`3D]?0T]53E1265]3150`04P`04Q"04Y)00!$6@!!3$=%
+M4DE!`$%2`$%21T5.5$E.00!!30!!4DU%3DE!`$%5`$%54U1204Q)00!!5`!!
+M55-44DE!`$%:`$%:15)"04E*04X`0D@`0D%(4D%)3@!"60!"14Q!4E53`$)%
+M`$)%3$=)54T`0EH`0D5,25I%`$)/`$)/3%9)00!"4@!"4D%:24P`0DX`0E)5
+M3D5)($1!4E534T%,04T`0D<`0E5,1T%224$`0T$`0T%.041!`$-,`$-(24Q%
+M`$-.`$-(24Y!`$-/`$-/3$]-0DE!`$-2`$-/4U1!(%))0T$`2%(`0U)/051)
+M00!#60!#65!255,`0UH`0UI%0T@@4D5054),24,`1$L`1$5.34%22P!$3P!$
+M3TU)3DE#04X at 4D5054),24,`14,`14-5041/4@!%1P!%1UE05`!35@!%3"!3
+M04Q6041/4@!%10!%4U1/3DE!`$9)`$9)3DQ!3D0`1E(`1E)!3D-%`$8R`$92
+M04Y#15]215,`1T4`1T5/4D=)00!$10!'15)-04Y9`$=2`$=2145#10!'5`!'
+M54%414U!3$$`2$X`2$].1%5205,`2$L`2$].1R!+3TY'`$A5`$A53D=!4ED`
+M25,`24-%3$%.1`!)3@!)3D1)00!)1`!)3D1/3D5324$`25(`25)!3@!)10!)
+M4D5,04Y$`$E,`$E34D%%3`!)5`!)5$%,60!*4`!*05!!3@!*,0!*05!!3C$`
+M2C(`2D%004XR`$HS`$I!4$%.,P!*-`!*05!!3C0`2C4`2D%004XU`$I/`$I/
+M4D1!3@!+6@!+05I!2TA35$%.`$M0`$Y/4E1(($M/4D5!`$M2`$M/4D5!(%)%
+M4%5"3$E#`$LR`$M/4D5!(%)%4%5"3$E#,@!+5P!+55=!250`3%8`3$%45DE!
+M`$Q"`$Q%0D%.3TX`3$D`3$E%0TA414Y35$5)3@!,5`!,251(54%.24$`3%4`
+M3%5814U"3U521P!-3P!-04-!50!-2P!-04-%1$].24$`35D`34%,05E324$`
+M35@`345824-/`$U#`$U/3D%#3P!-00!-3U)/0T-/`$Y,`$Y%5$A%4DQ!3D13
+M`$Y:`$Y%5R!:14%,04Y$`$Y/`$Y/4E=!60!/30!/34%.`%!+`%!!2TE35$%.
+M`%!!`%!!3D%-00!010!015)5`%!(`%!(24Q)4%!)3D53`%!,`%!/3$%.1`!0
+M5`!03U)454=!3`!04@!054525$\@4DE#3P!100!1051!4@!23P!23TU!3DE!
+M`%)5`%)54U-)00!300!3055$22!!4D%"24$`4T<`4TE.1T%03U)%`%-+`%-,
+M3U9!2R!215!50DQ)0P!320!33$]614Y)00!:00!33U542"!!1E))0T$`15,`
+M4U!!24X`4T4`4U=%1$5.`$-(`%-7251:15),04Y$`%-9`%-94DE!`%17`%1!
+M25=!3@!42`!42$%)3$%.1`!45`!44DE.241!1"`F(%1/0D%'3P!43@!454Y)
+M4TE!`%12`%154DM%60!500!52U)!24Y%`$%%`%5.251%1"!!4D%"($5-25)!
+M5$53`$="`%5.251%1"!+24Y'1$]-`%53`%5.251%1"!35$%415,`55D`55)5
+M1U5!60!56@!56D)%2TE35$%.`%9%`%9%3D5:545,00!63@!62454($Y!30!9
+M10!914U%3@!:5P!:24U"04)710`E<SH@<&AY0VYT,2`P>"5X+"!R97-E='1I
+M;F<@8V]U;G1E<B!V86QU92!T;R`P>"5X"@``)7,Z('!H>4-N=#(@,'@E>"P@
+M<F5S971T:6YG(&-O=6YT97(@=F%L=64@=&\@,'@E>`H````````P+CDN,30N
+M.0``````````!P````X````5````'````",`````````````````````````
+M````````````````)!.($Q$`B!/L$Q$`'A2"%`\`@A3F%!(`7A5=%A0`71;!
+M%A0`P1;:%A<`C!2@%+04R!0\%%`49!1X%```,A1&%%H4;A0``&P)A0F>"8H)
+MJ`D``&P)A0F>"8H)``!L"84)G at F*"0``;`F%"9X)B at D``'$6A1:9%JT6P18`
+M`%H4 at A2J%```@!:H%@``?!60%:05N!7,%>`5]!4(%AP6,!9$%@``<0EV"7L)
+M@`F/"90)F0FC"0``<0EV"7L)@`F/"90)F0D``'$)=@E["8`)CPF4"9D)``!Q
+M"78)>PF`"8\)E`F9"0``M`D``(4)```\%%`49!1X%``````!````:@````$`
+M``!\````!````(8````$````D@````0```"<````!````*8````!````L```
+M``(```"\`````@```,0````!````R@````0```#B````!````/0````$````
+M!`$```0````4`0``!````"0!```@````*`$``#(41A1:%&X4``!:%((4JA2`
+M%J at 6``!\%9`5I!6X%<P5X!7T%0 at 6'!8P%D06````````````````````````
+M`````````````&````"H"0```0```*,)```!````M`D```$```!G````J`D`
+M``$```"C"0```0```+0)```!````80```*@)```!````HPD```$```"T"0``
+M`0```&4```"H"0```0```*,)```!````M`D```$```!*````J`D```````"C
+M"0```````+0)```!````2P```*@)```!````HPD```$```"T"0```0```&H`
+M``"H"0```0```*,)```!````M`D```$`````````````````````````````
+M````````````"```````````````````````````````````````````````
+M`0)P%PL`C````````0(H(P\`$@```````0+ at +@H`F`(``````0)01 at X`)`(`
+M`````0+`70D`L`0``````0*@C`T`2`0``````0*`NP@`8`0``````0+PT at P`
+M;`0`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````@```````````````````````````````````````````````$#
+M<!<+`(P```````$#*",/`!(```````$#X"X*`)@"``````$#4$8.`"0"````
+M``$#P%T)`+`$``````$#H(P-`$@$``````$#@+L(`&`$``````$#\-(,`&P$
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````(```````````````````````````````````````````````!`G`7
+M"P",```````!`B at C#P`2```````!`N`N"@"8`@`````!`E!&#@`D`@`````!
+M`L!="0"P!``````!`J",#0!(!``````!`H"["`!@!``````!`O#2#`!L!```
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````"````````````````````````````````````````````````0-P%PL`
+MC````````0,H(P\`$@```````0/@+ at H`F`(``````0-01 at X`)`(``````0/`
+M70D`L`0``````0. at C`T`2`0``````0.`NP@`8`0``````0/PT at P`;`0`````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``0```````````````````````````````````````````````$`Z`,+`((`
+M``````$`T`<*!(0!``````$`?!4)!(L!``````$`^"H(!)8!````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````$
+MH@`````````````(H@``1D8^4$9&/E`,H@``;$&`9&Q!@&00H@```Z"9`0.@
+MF0$4H@``$-9,!!#63`08H@``0`"`$T``@!,<H@``8`#@&V``X!L at H@``"H!3
+M#`J`4PPDH@``.]\4`#O?%``HH@``M0$``+4!```LH@``(````"````"<F```
+M``````````"<F`````````````"<F`````````````"<F`````````````"<
+MF`````````````"<F`````````````"<F`````````````"<F```````````
+M``"<F`````````````"<F`````````````"<F`````````````"<F``````X
+M````.`"<F`````````````"<F`````````````"<F`````````````"<F```
+M^0`$`/D`!`#4F`````````0`````````````````````````G)@`````````
+M````G)@`````````````G)@`````````````G)@`````````````G)@`````
+M````````G)@``````!`````0G)@```````0````$G)@`````````````G)@`
+M````````````G)@`````````````G)@````````````*G)@``(``.`"``#@"
+MG)@```8``@`&````G)@``)(```"2````G)@``*````"@````G)@```<`!``'
+M``0`U)@``!H````:````G)@``$@```!(````G)@``!`````0````G)@```@`
+M```(````G)@```\````/````G)@``/(```!B````G)@``$^0``!,D```G)@`
+M`%H2``":$@``S)@```X````/```````````````````````````````(````
+M```````````````````````````````````````````!`G`7"P",```````!
+M`B at C#P`2```````!`N`N"@"8`@`````!`E!&#@`D`@`````!`L!="0"P!```
+M```!`J",#0!(!``````!`H"["`!@!``````!`O#2#`!L!```````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````"```````
+M`````````````````````````````````````````0-P%PL`C````````0,H
+M(P\`$@```````0/@+ at H`F`(``````0-01 at X`)`(``````0/`70D`L`0`````
+M`0. at C`T`2`0``````0.`NP@`8`0``````0/PT at P`;`0`````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````0`````````
+M``````````````````````````````````````$`Z`,;`((```````$`T`<:
+M!(0!``````$`?!49!(L!``````$`^"H8!)8!````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````,````````````
+M```````````````````````````````````!`.@#&P`"```````!`-`'&@0$
+M`0`````!`'P5&00+`@`````!`/@J&`06`P```````G`7"P`,!````````B at C
+M#P`2!``````!`N`N"@`8!@`````!`E!&#@`D!@`````!`L!="0`P"``````!
+M`J",#0!("``````!`H"["`!@"``````!`O#2#`!L"```````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````#```````````````
+M`````````````````````````````````03T`0<`@0```````03H`P(`BP$`
+M`````030!P8`E@(``````02X"P$`E@,``````0)P%PL`C`0``````0(H(P\`
+M$@0``````0+ at +@H`F`8``````0)01 at X`)`8``````0+`70D`L`@``````0*@
+MC`T`2`@``````0*`NP@`8`@``````0+PT at P`;`@`````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!'0T,Z("A'3E4I(#,N
+M-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E
+M94)31%T@,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R965"4T1=(#(P
+M,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R.```
+M1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W,C@``$=#0SH@*$=.
+M52D@,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR
+M(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)3
+M1%T@,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R965"4T1=(#(P,#0P
+M-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#
+M.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W,C@``$=#0SH@*$=.52D@
+M,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&
+M<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@
+M,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X
+M``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H
+M1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT
+M+C(@6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E
+M0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P
+M-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X``!'
+M0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5
+M*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@
+M6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$
+M72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W
+M,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z
+M("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S
+M+C0N,B!;1G)E94)31%T@,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R
+M965"4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R
+M,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W,C@`
+M`$=#0SH@*$=.52D@,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z("A'
+M3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N
+M,B!;1G)E94)31%T@,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R965"
+M4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T
+M,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W,C@``$=#
+M0SH@*$=.52D@,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I
+M(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;
+M1G)E94)31%T@,C`P-#`W,C@``$=#0SH@*$=.52D@,RXT+C(@6T9R965"4T1=
+M(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N-"XR(%M&<F5E0E-$72`R,#`T,#<R
+M.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E94)31%T@,C`P-#`W,C@``$=#0SH@
+M*$=.52D@,RXT+C(@6T9R965"4T1=(#(P,#0P-S(X``!'0T,Z("A'3E4I(#,N
+M-"XR(%M&<F5E0E-$72`R,#`T,#<R.```1T-#.B`H1TY5*2`S+C0N,B!;1G)E
+M94)31%T@,C`P-#`W,C@``"YS>6UT86(`+G-T<G1A8@`N<VAS=')T86(`+G)E
+M;"YT97AT`"YR96PN<F]D871A`"YR;V1A=&$N<W1R,2XQ`"YR;V1A=&$N<W1R
+M,2XT`"YR96PN9&%T80`N8G-S`"YC;VUM96YT````````````````````````
+M`````````````````````````````````!\````!````!@`````````T````
+M8FP!````````````!``````````;````"0``````````````9#("`/`6```,
+M`````0````0````(````*0````$````"`````````*!L`0`(=P``````````
+M```@`````````"4````)``````````````!420(`$!D```P````#````!```
+M``@````Q`````0```#(`````````J.,!`,P%``````````````$````!````
+M0`````$````R`````````'3I`0!G```````````````$`````0```%,````!
+M`````P````````#@Z0$`Y!8`````````````(`````````!/````"0``````
+M````````9&("`+`````,````!P````0````(````60````@````#````````
+M`.```@"P`0`````````````@`````````%X````!``````````````#@``(`
+MRP8``````````````0`````````1`````P``````````````JP<"`&<`````
+M``````````$``````````0````(``````````````$0*`@"@%P``#0````@`
+M```$````$`````D````#``````````````#D(0(`@!```````````````0``
+M`````````````````````````````````````````````P`!````````````
+M``````,``P`````````````````#``4``````````````````P`&````````
+M``````````,`!P`````````````````#``D``````````````````P`*``$`
+M``#0B0``J````!(``0`,````1'L```8````2``$`%P```)#O``"[````$@`!
+M`"(```!P80``=````!(``0`M````_.4``(\````2``$`.````'17``#;````
+M$@`!`$,```"H,P$`Y````!(``0!.````X`(``*0!```1``<`60```#CS```C
+M````$@`!`&0```!H60``,0```!(``0!O````E$X``#P````2``$`>@```(3L
+M```E````$@`!`(4```!4Z0``$P```!(``0"0````V-\```P````2``$`FP``
+M`/C-``"Z````$@`!`*8```!\U@``Y0```!(``0"Q````7`@``#P````2``$`
+MO````(3"``"6````$@`!`,<````TK0``BP```!(``0#2````')L```L````2
+M``$`W0```!A_```E````$@`!`.@````@\@``!@```!(``0#S````C,T```8`
+M```2``$`_@```$C>```7````$@`!``D!``!8_@``>P```!(``0`4`0``#`8`
+M`'4````2``$`'P$```R-```&````$@`!`"H!``#()@$`=0```!(``0`U`0``
+M"((```8````2``$`0`$``"B;```/````$@`!`$L!``!`#@``I`$``!$`!P!6
+M`0``/.L``'0````2``$`80$```R```!N````$@`!`&P!``"\`@``+````!(`
+M`0!W`0``N"@!`%@````2``$`@@$``*BK```A````$@`!`(T!````````````
+M`!````"N`0``B%X``$$````2``$`N0$``/3$``"6````$@`!`,0!``!88```
+M)````!(``0#/`0``Z)(``$@````2``$`V@$``!R6``!X````$@`!`.4!``#(
+MQ0``.0```!(``0#P`0``$((``&$````2``$`^P$``,A=```S````$@`!``8"
+M``"(>P``.0```!(``0`1`@``9)@``$H````2``$`'`(``+#K```@````$@`!
+M`"<"``"\Z@``8````!(``0`R`@``Z/X``#<````2``$`/0(``+C.``!7````
+M$@`!`$@"``!@60``!@```!(``0!3`@``T.L``'@````2``$`7@(```A0``#(
+M!0``$@`!`&D"```(EP``'@$``!(``0!T`@``J.<``"8````2``$`?P(``&@"
+M``!3````$@`!`(H"```<ZP``(````!(``0"5`@``O!<!``(!```2``$`H`(`
+M`!CR```&````$@`!`*L"``!@W0``+````!(``0"V`@``G,\``/$````2``$`
+MP0(```!@```9````$@`!`,P"``!(C0``FP```!(``0#7`@``O)$``'L````2
+M``$`X@(``*1Z```A````$@`!`.T"``!,'`$`B````!(``0#X`@``A'```/(!
+M```2``$``P,``*AB```!````$@`!``X#``#4'`$`2````!(``0`9`P``X'P`
+M`#4"```2``$`)`,``!@!``!0`0``$@`!`#,#``"L"0$`Y@(``!(``0`^`P``
+M*/(``(<````2``$`20,``-R6```1````$@`!`%0#```4&P$`.`$``!(``0!?
+M`P``X.T``,X````2``$`:@,``+SR```/````$@`!`'4#````E```#@```!(`
+M`0"``P``!,8``-\````2``$`BP,``(S%```Y````$@`!`)8#```(IP``4P``
+M`!(``0"A`P``T%4``!`````2``$`K`,``!Q@```[````$@`!`+<#``#H`@``
+M*`$``!(``0#-`P``(`,!`"$````2``$`V`,``'2"``"6````$@`!`.,#``!0
+M80``(````!(``0#N`P``Y(L``!8````2``$`^0,``-3^```2````$@`!``0$
+M``"@LP``*@```!(``0`/!```G.$``((#```2``$`&@0``"C?```+````$@`!
+M`"4$```X6@``B````!(``0`P!```Q(H``#@````2``$`.P0``-PJ`0`]````
+M$@`!`$8$```8X```^````!(``0!1!```P)8```$````2``$`7`0``"!>``!E
+M````$@`!`&<$```PD0``BP```!(``0!R!```E,0``%\````2``$`?00``)#0
+M``"G!0``$@`!`(@$``!L&@$`I@```!(``0"3!```-.D```8````2``$`G at 0`
+M`$"0```A````$@`!`*D$``#4\P``5P```!(``0"T!```;"4!`/4````2``$`
+MOP0``)B<``!%````$@`!`,H$```X70``*0```!(``0#5!```2.P``",````2
+M``$`X`0``#C6``!!````$@`!`.L$```,S```'P```!(``0#V!```$"D!`#X`
+M```2``$``04``!#R```&````$@`!``P%`````````````!`````9!0``@'P`
+M`&`````2``$`)`4``!AG``!%````$@`!`"\%``"P*0$`"P```!(``0`Z!0``
+M!.@``'<````2``$`104``&P$``#%````$@`!`%8%``!4'P$`\P,``!(``0!A
+M!0``?&```$0````2``$`;`4``+"```"/````$@`!`'<%``!HZ0``$0```!(`
+M`0""!0``C#0!`'$````2``$`C04``)!F``!7````$@`!`)@%```4C0``,0``
+M`!(``0"C!0``%*D``"`!```2``$`K at 4``,AZ``!Y````$@`!`+D%````$```
+MI`$``!$`!P#$!0``K/0``#@````2``$`SP4``$SP```L````$@`!`-H%``!X
+MB@``2@```!(``0#E!0``X)P``.4````2``$`\`4``*SL```T`0``$@`!`/L%
+M```,E0``7````!(``0`&!@``R)8``!,````2``$`$08``+#N``#@````$@`!
+M`!P&``!D'0$``0$``!(``0`G!@``'"L!`%0$```2``$`, at 8``"B8```Z````
+M$@`!`#T&``#$6```"P```!(``0!(!@``_(H``.@````2``$`4P8``!S;``!*
+M````$@`!`%X&``#LY@``)P```!(``0!I!@``,&,``"0````2``$`=`8``,!K
+M`0"B````$@`!`'\&``"XZ```.````!(``0"*!@``P!$``*0!```1``<`E08`
+M`(S,``!E````$@`!`*`&```XFP``#P```!(``0"K!@``8&<``"T!```2``$`
+MM at 8``#SE```A````$@`!`,$&```4YP``E````!(``0#,!@``U%8``&@````2
+M``$`UP8``, at I`0`3`0``$@`!`.(&```P;P``%````!(``0#M!@``>&4```\`
+M```2``$`^`8``!Q?``"J````$@`!``,'``#X9@``'0```!(``0`.!P``C.8`
+M`%\````2``$`&0<``+```0#Q`0``$@`!`"0'``#TS```!@```!(``0`O!P``
+MX",!`%L````2``$`.@<```1E```C````$@`!`$4'``!@!@``I`$``!$`!P!0
+M!P``P%H``(P!```2``$`6P<``$Q[```Y````$@`!`&8'``#H9@``#@```!(`
+M`0!Q!P`````````````0````D0<``)!H```P!@``$@`!`)P'````````"0``
+M`!$`!P"L!P``-`4``'4````2``$`O0<``#B2```J````$@`!`,@'``!DUP``
+M4@```!(``0#3!P``X.<``"(````2``$`W@<``*QB```!````$@`!`.D'``"X
+ME@``!@```!(``0#T!P``G)H```L````2``$`_P<``.2-``"(````$@`!``H(
+M``"4Z0``'@$``!(``0`5"```W&0```8````2``$`(`@`````````````$```
+M`"\(``"0D@``,P```!(``0`Z"```_/$``!0````2``$`10@``.3Q```6````
+M$@`!`%`(``!HVP``.````!(``0!;"```P&X``&X````2``$`9@@``(B5``!T
+M````$@`!`'$(```\Z0``%P```!(``0!\"```--\``*(````2``$`AP@``&SL
+M```7````$@`!`)((``#8DP``)@```!(``0"="```5/0``%8````2``$`J`@`
+M`"`R`0"%`0``$@`!`+,(``!LC@``N`$``!(``0"^"````&8``!<````2``$`
+MR0@``,"0``!`````$@`!`-0(``"L=```'P```!(``0#?"```?/,``%<````2
+M``$`Z@@``&22```L````$@`!`/4(``!8DP``@````!(``0``"0``R%\``"8`
+M```2``$`"PD``&`C`0`?````$@`!`!8)`````````````!`````E"0``:%P`
+M`"$````2``$`,`D``*#E``!9````$@`!`#L)```@"```I`$``!$`!P!&"0``
+M=)P```X````2``$`40D``/R+``!@````$@`!`%P)``#D````,P```!(``0!J
+M"0``)%T``!(````2``$`=0D``*`$``"D`0``$0`'`(`)```<G```5P```!(`
+M`0"+"0``7(P```L````2``$`E at D```P````<````$0`'`*@)``#,7@``'```
+M`!(``0"S"0``Y-\``#0````2``$`O at D``%AD``!X````$@`!`,D)```P-@$`
+M#`(``!(``0#4"0``T&0```L````2``$`WPD```CS```M````$@`!`.H)``"8
+M20``F0```!(``0#U"0``2",!`!8````2``$```H``,2;``!7````$@`!``L*
+M``"4E@``(P```!(``0`6"@``W/(``"D````2``$`(0H``"S,```>````$@`!
+M`"P*```<'0$`2````!(``0`W"@``_)4``"`````2``$`0 at H``$"!```&````
+M$@`!`$T*``#$"`$`L0```!(``0!8"@``:(P``*(````2``$`8PH``)3-``!A
+M````$@`!`&X*``#@"0``I`$``!$`!P!Y"@``Z&4``!<````2``$`A`H``+PI
+M`0`*````$@`!`(\*``!H6```7````!(``0":"@``*&4``$,````2``$`I0H`
+M`,3'```M!```$@`!`+`*``#D8@``2@```!(``0"["@``L)H```8````2``$`
+MQ at H``*#;```X`0``$@`!`-$*``"$G```$@```!(``0#<"@``L$L``#<````2
+M``$`YPH``.3=``!B````$@`!`/(*``"8"@``;P```!(``0#]"@``J)H```8`
+M```2``$`"`L``!`'``!+`0``$@`!`!,+```TW0``*@```!(``0`>"P``!&(`
+M`'@````2``$`*0L``&QE```+````$@`!`#0+``#DE```*````!(``0`_"P``
+M(!8!`'8````2``$`2 at L``)Q=```L````$@`!`%4+``!X"0$`-````!(``0!@
+M"P``$`0``%L````2``$`:PL``&#E``!`````$@`!`'8+`````````````!``
+M``"&"P``S+,``(0!```2``$`D0L``%!8```6````$@`!`)P+``!D)@$`8@``
+M`!(``0"G"P``_%T``"0````2``$`L at L``!#A``",````$@`!`+T+``"@E```
+M1````!(``0#("P``_,P``(X````2``$`TPL`````````````$````/,+``"$
+M!@``B@```!(``0#^"P``C%P``$T````2``$`"0P``-Q<``!`````$@`!`!0,
+M````D0``+P```!(``0`?#```G%D``)L````2``$`*@P``#"3```G````$@`!
+M`#4,``"XUP``H0(``!(``0!`#```\)8``!4````2``$`2PP``.3T```1`0``
+M$@`!`%8,``!,7```'````!(``0!A#``````````````0````;PP``"20```<
+M````$@`!`'H,``#\"```4P```!(``0"%#```L&(``#(````2``$`D`P``*2;
+M```?````$@`!`)L,``"PF```+````!(``0"F#```O&\``,@````2``$`L0P`
+M`!AF```?````$@`!`+P,``#H7@``-````!(``0#'#```(.4``!P````2``$`
+MT at P``,SR```/````$@`!`-T,``#$D@``)````!(``0#H#```P-T``"0````2
+M``$`\PP``+@$`0`+!```$@`!`/X,``#`8```+@```!(``0`)#0``\%\```X`
+M```2``$`%`T``,":``!;````$@`!`!\-```\)`$`+0$``!(``0`J#0``$)0`
+M`!D````2``$`-0T``$B!``#`````$@`!`$`-``!DD```60```!(``0!+#0``
+MQ)8```$````2``$`5 at T``,1[``"[````$@`!`&$-``"`$P``I`$``!$`!P!L
+M#0``/%<``#@````2``$`=PT``-!8``".````$@`!`((-``",W0``,P```!(`
+M`0"-#0``G"@!`!L````2``$`F`T``+3J```&````$@`!`*,-``!HE```.```
+M`!(``0"N#0``N)H```8````2``$`N0T``&`5`0#`````$@`!`,0-```0F@``
+MC````!(``0#/#0``R)T``"L)```2``$`V at T``$`5``"D`0``$0`'`.4-``!D
+M70``-0```!(``0#P#0``K`4``%T````2``$`^PT``$`G`0!:`0``$@`!``8.
+M``#<'@$`=@```!(``0`1#@``Y&0``!X````2``$`'`X``(AE```/````$@`!
+M`"<.``!HE0``(````!(``0`R#@``L/(```L````2``$`/0X``)AE``!-````
+M$@`!`$@.``#D80``(````!(``0!3#@``Y(<``!`````2``$`7 at X``%`)``!'
+M`0``$@`!`&D.``"TS@```0```!(``0!T#@``0'\``$H````2``$`?PX``'2;
+M```7````$@`!`(H.``"@8@``!@```!(``0"5#@``6,<``&L````2``$`H`X`
+M`%SS```?````$@`!`*L.````1P$`H@```!(``0"V#@``?&(``",````2``$`
+MP0X``%A/``!`````$@`!`,P.``"T10``X@,``!(``0#B#@``+/0``"<````2
+M``$`[0X``#AF``!7````$@`!`/@.``#X]0``7@@``!(``0`##P``8-X``,8`
+M```2``$`#@\``$S,```]````$@`!`!D/``",FP``%P```!(``0`D#P``C'\`
+M`'T````2``$`+P\``&@X``!\````$@`!`#H/``!$;P``=P```!(``0!%#P``
+M2)L``"D````2``$`4`\``/2F```2````$@`!`%L/```\5@``E@```!(``0!F
+M#P``#(,```$````2``$`<0\``/!@``!@````$@`!`'P/``"8P0``/P```!(`
+M`0"'#P``</$``'0````2``$`D@\``/#H``!$````$@`!`)T/```LE```.P``
+M`!(``0"H#P``:(,``'H$```2``$`LP\``'!W``"Y`@``$@`!`+X/``!\Z0``
+M%0```!(``0#)#P``],L``!8````2``$`U`\``'1<`0"J````$@`!`-\/``"P
+M3```D````!(``0#J#P``?.@``#L````2``$`]0\``-C<``!9````$@`!```0
+M```@_P``C@$``!(``0`+$```@",!`!X````2``$`%A```%S:``"^````$@`!
+M`"$0`````````````!`````P$```'%T```8````2``$`.Q```'R````S````
+M$@`!`$80``#0YP``#@```!(``0!1$```7*<``+@!```2``$`7!```-!.``"&
+M````$@`!`'40``"@(P$`/0```!(``0``>GHP,#5B-3 at T-@!Z>C`P,F1B,3%C
+M`'IZ,#)D8F8X-S4`>GHP,F1B8C%B,@!Z>C`P,F1B-#8P`'IZ,&(W8C at S-C@`
+M>GHP-6(X8S8U80!Z>C`P-6(T,&%D`'IZ,#5B.30R960`>GHP9#DT8V0P-`!Z
+M>C`P,3EF-#<P`'IZ,#)D8F4W,V0`>GHP,#5B-CDR8@!Z>C!B-F0R,S(U`'IZ
+M,#`U8C at U,V0`>GHP,#$V9#DR90!Z>C!C9F(Q.#<U`'IZ,#`R9&(S,6,`>GHP
+M,F1A8F)A8P!Z>C`P,&(V8S8X`'IZ,#`P8C9B9C@`>GHP,F1B-6)F,`!Z>C`Q
+M-F4Q9&9D`'IZ,&(W,&4Y.&,`>GHP-F4P9C9C,@!Z>C`P-C=D,F(Q`'IZ,&(V
+M8V$S,C4`>GHP,#5B-F-F9`!Z>C`Q-F4P9&9D`'IZ,#`P8C9F-C@`>GHP,#5B
+M-#AA9`!Z>C`R9&)F,6(R`'IZ,#`U8C at X8V(`>GHP,S-E8SAB9@!Z>C!D8C1C
+M.31D`'IZ,#)D8C-B86,`871H7VAA;%]D;6%?8F5A8V]N7W)E<W!O;G-E7W1I
+M;64`>GHP,&(V9C$V,0!Z>C!D8S4X-S$X`'IZ,&1B,#DQ,&4`>GHP,&(V93(W
+M80!Z>C`R9&)B86(R`'IZ,&(V9#%E9F8`>GHP,#5B-C1F9`!Z>C`P,&(V9#4R
+M`'IZ,&(V8SEE9F8`>GHP,F1B9#@W-0!Z>C`R9&(S,6(R`'IZ,#!B-S`Y,C,`
+M>GHP,#!B-F0Q9`!Z>C`P8C9D-#4P`'IZ,&(V8S(S,C4`>GHP,F1B9&%B,@!Z
+M>C`P,#5B-C,R`'IZ,#9D9C)F-3<`>GHP,#$V9&$U,`!Z>C`P,#8W9#,R`'IZ
+M,#!B-F0Y,C,`>GHP,#)D8C4Q8P!Z>C`Q-F1A-V8P`'IZ,#$V9&-B9F4`>GHP
+M,#$V9&5C,0!Z>C`P,39D9C)C`'IZ,&(X,30V,3(`>GHP,39D.3DR,`!Z>C`R
+M9&(Q8F%C`'IZ,&1C-S at W,3@`>GHP-6(W,#%E,`!Z>C`P,&(V8C$P`'IZ,&(W
+M,#EE9F8`>GHP,39D9C at Y8@!A=&A?:&%L7V%T=&%C:`!Z>C`V93$T9&0Q`'IZ
+M,#$V9&%B,F0`>GHP,F1B,3,U9`!Z>C!E,&(V9C(S`'IZ,#$V93(Y,60`>GHP
+M,#!B-F9E.`!Z>C`P,39D.30X`'IZ,#$V93(P.6(`>GHP8C<P,65F9@!Z>C`P
+M,&(V8SED`'IZ,#`P-6(U83(`>GHP,F1B,3<P80!A=&A?:&%L7V-O;7!U=&5T
+M>'1I;64`>GHP,F1B-6)A8P!Z>C`P-6(X,3-D`'IZ,#!B-F,Y,C,`>GHP8C9C
+M93DX8P!Z>C`P-6(W9CED`'IZ,&(W,#%D,#(`>GHP-F4P-#8P90!Z>C`R9&(U
+M-S8S`'IZ,#9F,C,R8V,`>GHP93`W.#,W.0!Z>C`P,F1A9C8R`'IZ,&(X-30V
+M,3(`>GHP,#!B-F(Y,`!Z>C`Q-F0Y969A`'IZ,#`R9&(R-C``>GHP,39D93`U
+M,0!Z>C`P,#5B-F(R`'IZ,#5B-V8Q,30`>GHP,S0W-#9B-`!Z>C`R9&)D9&9D
+M`'IZ,#`X968S,#D`>GHP,&(W,3<W9`!Z>C`P8C<P9C-D`'IZ,#$V9#@Y,C``
+M>GHP,F1B,6%B,@!Z>C`P,#5B-C(R`'IZ,#`P8C9F-S@`>GHP8C9B-#DU,`!Z
+M>C`P-6(W-C,P`&%T:%]H86Q?9G)E90!Z>C`U8C<Y8C%B`'IZ,#!B-S`W,V0`
+M>GHP8C5F8V$R-@!Z>C`Q-F1F8F8Q`&%T:%]H86Q?;6AZ,FEE964`>GHP,39E
+M,3 at Y8@!Z>C!D8S,T.31D`'IZ,#`R9&,V,&(`>GHP,F1B,S,U9`!Z>C!B-F,U
+M,V$T`'IZ,&8X968S,#@`>GHP9&$T8V0P-`!Z>C`U8C<T,64P`'IZ,#)D83EB
+M86,`>GHP,39E8SEA9`!Z>C`P8C<Q-S-D`'IZ,#$V9#ED-#$`>GHP9&,Q,F,Q
+M9@!Z>C`P-6(X-&9D`'IZ,#`U8CAA8F0`>GHP,&(W,#$R,P!Z>C`P-6(V-3)B
+M`'IZ,#)D8C,X-S4`>GHP,39E,S`Y8@!Z>C`P-6(V,&(R`'IZ,#)D8C$X-S4`
+M>GHP,F1B,3<V,P!Z>C!B-V8X,S8X`'IZ,&1C,S)C,68`>GHP,&(W,#$V,0!Z
+M>C`Q-F0W9#0Q`'IZ,#`Q-F-D,S(`>GHP9&(T.3$P90!Z>C`P-6(T.&5D`'IZ
+M,#`R9&,X,&(`>GHP,F1B,S-E9`!Z>C`P-6(X,&9D`'IZ,#)D8F9D9F0`>GHP
+M,39E-C0X80!Z>C!D8F8R8S%F`'IZ,#`R9&%F9C(`>GHP,#5B-S<Y9`!Z>C`P
+M,&(V964X`'IZ,#$V930T.&$`>GHP,&(V9C9B8P!Z>C`Q-F1A.3(P`'IZ,#5B
+M-S at Q93``>GHP93(W,V$T9`!Z>C`P,F1C83!B`'IZ,#)D8C%B9C``>GHP,#5B
+M-#1A9`!Z>C`V9&4T-C!E`'IZ,&(V9CEE9F8`>GHP,&(V8S9B8P!A=&A?:&%L
+M7V%D9&ET:6]N86Q?<W=B85]B86-K;V9F`'IZ,#`P,F1B.3(`871H7VAA;%]V
+M97)S:6]N`&%T:%]H86Q?:65E93)M:'H`>GHP,F1B-SEA90!Z>C!B-F-F,#`Y
+M`'IZ,#`Q-F4Q,F,`>GHP,#$V9#EE-`!Z>C`P-6(U8V(R`'IZ,#$V9&$R-3$`
+M>GHP-F9A,S)C8P!Z>C`V93`R9C4W`'IZ,#`U8C9E,S``871H7VAA;%]M86QL
+M;V,`>GHP,#!B-F1D,@!Z>C`U8C9C8F0U`'IZ,#$V9&(R-3$`>GHP93$W.#,W
+M.0!Z>C`Q-F1D,#4Q`'IZ,#)D8F0Q8C(`>GHP9&$Y8S1F-@!Z>C`R9&,Q-S8S
+M`'IZ,#$V9&8P-3$`>GHP,#$V9#DU,`!Z>C`P8C<P-F)C`'IZ,#`Q-F0X-S(`
+M>GHP-F1F-#8P90!Z>C`U8CAC,F5D`'IZ,#9F9C$W93<`>GHP8C9F.60P,@!Z
+M>C!D-&5F,S`X`'IZ,#$V9&)B9F4`>GHP,39E-30X80!Z>C`P,39D.#4P`'IZ
+M,#`P8C9F9C@`871H7VAA;%]M96UC<'D`>GHP,F1B8F1F9`!Z>C`V9&(U96(V
+M`'IZ,#$V96(Y860`>GHP,&(V8V5B8P!Z>C!D.6(X8C<Y`&%T:%]H86Q?<')O
+M8F4`>GHP,#)D8C`V,`!Z>C`Q-F5A.6%D`'IZ,#`P968S,#D`>GHP,F1B,S<V
+M,P!A=&A?:&%L7V)U:6QD;W!T<P!Z>C`R9&%F,S5D`'IZ,&1B-&-D,#0`>GHP
+M,39D9C(U,0!Z>C`P,&(V8S$P`'IZ,#$V9#DR-3$`>GHP8C<R,6%E9`!Z>C`V
+M-V-F8V%E`'IZ,#`P8C9C9C@`>GHP8V-E9C,P.`!Z>C`R9&%F86(R`'IZ,#5B
+M.3)A960`>GHP,#5B.&-C8@!Z>C!B-F0Y969F`'IZ,#)D8C$Q8C(`>GHP93$W
+M,V$T9`!Z>C`R9&)F9F(Q`'IZ,#)D8F8W-C,`>GHP,#5B-CAF9`!Z>C`P-6(T
+M-&5D`'IZ,&(W,3%A960`>GHP8C5F8V$S-`!Z>C!D.&(X8C<Y`'IZ,#$V9#AB
+M,F0`>GHP,39E,#@Y8@!Z>C`R9&)B.#<U`'IZ,#$V9#DW9C``>GHP8C at S.#,V
+M.`!Z>C`P8C9F96)C`'IZ,&4Y.3DS,3,`>GHP,&(V96$W80!Z>C`S,V4X9F)F
+M`'IZ,#`U8C<R,S``>GHP8V9A-3 at W-0!Z>C`R9&(Y.6%E`'IZ,#)D8CEA8C(`
+M>GHP,#!B-F)E.`!Z>C!D.3EC-&8V`'IZ,&1E9#AA-3<`>GHP,39D86)F90!Z
+M>C!B-S`Y9#`R`'IZ,#$Y9C-A,#$`>GHP-S`W,3=E-P!A=&A?:&%L7VUE;7IE
+M<F\`>GHP-F4P-&1D,0!Z>C!B-CAE.3AC`'IZ,#$V93)D9F0`>GHP,#!B-F0R
+M,@!Z>C`W,#(S,F-C`'IZ,&1C-30Y-&0`>GHP,&(W,&8W9`!A=&A?:&%L7W-W
+M7V)E86-O;E]R97-P;VYS95]T:6UE`'IZ,#EF-CED,F4`>GHP,#5B-C4W80!Z
+M>C`V9C<Q-V4W`'IZ,#9D835E8C8`>GHP8C=D-#8Q,@!Z>C`P8C9F.38Q`'IZ
+M,&(V8C!C.3``>GHP,F1B9#,U9`!Z>C`P-6(X.&9D`'IZ,#)D869D9F0`871H
+M7VAA;%]D96QA>0!Z>C`R9&(Q9&9D`'IZ,#8W9#)F-#$`>GHP,F1A9C at W-0!Z
+M>C!B.#`W-S0Q`'IZ,#$V9#AD-#$`>GHP,#)D864Y,@!Z>C!B-V,W-S0Q`'IZ
+M,#)D8F(S-60`>GHP,F1B,V1F9`!Z>C`R9&(U,V5D`'IZ,#`P8C9D83(`>GHP
+M,#!B-F4R,@!Z>C`U8C at P,#0Q`'IZ,&0X.6,T9C8`>GHP,#$V9#@T.`!Z>C`Q
+M-F0Y8C)D`'IZ,&4S-S-A-&0`>GHP,#$V93`R8P!Z>C`P8C<P-S=D`'IZ,#`U
+M8C8Y-V$`>GHP,#$V9&%E-`!Z>C`Q-F4Q,#EB`'IZ,#`U8C1A,F0`>GHP9&8W
+M.#,W.0!Z>C`R9&)D-S8S`'IZ,#`P8C9E-3(`>GHP-6(V8S9D8@!Z>C!C835F
+M,S(Y`'IZ,&1B,CDQ,&4`>GHP,F1B,V)F,`!Z>C`V9#<X831C`'IZ,#$V93`R
+M-3$`>GHP,#`R9&)B,@!Z>C`P,F1D.#9D`'IZ,#)D8C4Y864`>GHP,#8W9#(R
+M,0!Z>C`P-6(X.3-D`'IZ,#5B.#%B,6(`>GHP,39D.#=F,`!Z>C`R9&(Q,V5D
+M`'IZ,#!B-F0Q,C,`>GHP,#!B-F-E.`!Z>C`U8CAA865D`'IZ,#)D868Q8C(`
+M>GHP,#`U8C5E,@!Z>C`S,V5B9F)F`'IZ,#5B-C at V9&(`>GHP,#!B-F5F.`!Z
+M>C!B-S$Y865D`'IZ,#`U8C4X8C(`>GHP-6(W9&(Q8@!Z>C!B.#0W-S0Q`'IZ
+M,#`Q-F0W,S(`>GHP,F1A9&%B,@!Z>C!F-&1E,S`W`&%T:%]H86Q?:6YI=%]C
+M:&%N;F5L<P!Z>C`P8C9D-F)C`'IZ,&,T968S,#@`>GHP,#`R9&)D,@!Z>C!D
+M86(X8C<Y`'IZ,#$V93!B.#<`>GHP-6(Y,#)E9`!Z>C!D8S,X-S$X`'IZ,&%A
+M,F5E8S$`>GHP,#!B-F,Q9`!Z>C`U8CAE865D`'IZ,#`U8C=B.60`>GHP,#5B
+M-30T-@!Z>C`U8C8T-F1B`'IZ,#!B-F8Y,C,`>GHP9&1D.&$U-P!Z>C`Q-F4Q
+M,C4Q`'IZ,&1C-S0Y-&0`>GHP,F1B,S<P80!Z>C`P,#5B-C<R`'IZ,#9D9C1D
+M9#$`>GHP,F1B9C,U9`!Z>C`P,&(V8S<X`'IZ,#`Q-F0X,S(`>GHP,V4Y-S,U
+M,P!Z>C`R9&(U-S!A`'IZ,#`U8C9D-V$`>GHP,#)D8C(Y,@!Z>C`P-6(Y,&-B
+M`'IZ,#`U8C5C-#8`871H7VAA;%]P<FEN=&8`>GHP-F0Y-65B-@!Z>C`Q-F1F
+M8C at W`'IZ,#`Q-F1A-#@`>GHP,#)D8C`Y,@!A=&A?:&%L7V=E='=I<F5L97-S
+M;6]D97,`>GHP,39E,6(X-P!Y`````0,``)$````!`P``L`````$#``"_````
+M`0,``,4````!`P``S0````$#``#5`````0,``,T!```";0``Y`$```)H`0#\
+M`0```CT``)X"```"'0$`X`8```)<``#V!@```EP``#0'```!`@``'PL```$"
+M```R"P```0(``-,.```"O@``FA,```(*`0#@'P```@H!`.$J```!`@``\RH`
+M``$"```..0```0(``#XY```!`@``F3D```$"``#..0```0(``#XZ```!`@``
+M8#H```$"``!R.@```0(``.HZ```!`@``]#H```$"```*.P```0(``!0[```!
+M`@``.3L```$"``!!.P```0(``'$\```!`@``E#P```$"```:/0```0(``&L]
+M```!`@``ACT```$"```=/@```0(``"4^```!`@``F3X```$"``"G/@```0(`
+M`*\^```!`@``V#X```$"```9/P```0(``"$_```!`@``?3\```$"``#1/P``
+M`0(``.$_```!`@``#4````$"```40````0(``&5````!`@``>D````$"``"#
+M0````0(``)%````!`@``M$````$"``"]0````0(``#U!```!!0``7D$```$%
+M``!F00```04``!E"```!`@``(D(```$"``!?0@```0(``(-"```!`@``W4(`
+M``$"``#T0@```0(```Y#```!`@``148```)X`0"Z1@```0(``,!&```!`@``
+M#4D```$"```<20```0$``*U*```!`@``:TP```*T``#D3````04``.U,```!
+M!0``,4T```$%``#`30```0(``'Q/```!`@``'U````*^``!`4````0(``$90
+M```"U```Q%````(C`0!"40```BD``'!1```"%`$`HE$```(4`0#140```A0!
+M`"%2```"%`$`75(```(4`0`L50```A0!`*95```">@``V%4```)Z``!C5@``
+M`2P``'=6```!$@$`^E8```(=`0`Z7````F4``&!<```"U```?%P```+4``"M
+M7````D```$1=```"#@$`6%T```)J``![7@```C8!`#=?```"U```J%\```)$
+M`0"Y7P```JP```QA```"(0``+V$```)!`0!H80```B$``()A```"(0``N&$`
+M``)!`0#\80```B$``!9B```"(0``3&(```)!`0"78@```B$``-=B```"``$`
+M(V,```(8``!,8P```A\!`+9C```"'0$`W6,```(=`0`V90```=P``$5E```!
+M#P``764```(3`0#*90```AT!`/5H```"(P$`@6L```*G```W;````0(``&QL
+M```":0$`CFT```(=`0"R;0```D```+]M```"B```Z&T```).```';@```G0`
+M`#IN```"8P$`66X```(+``!X;@```@(!`%1O```"X@``B6\```(=`0"E;P``
+M`AT!`-%O```"X@``)'````(=`0!-<````AT!`%EP```"X@``O7````(=`0#=
+M<````AT!``=Q```"'0$`>'$```(=`0"8<0```AT!`,5Q```"'0$`Z7$```)`
+M```5<@```H@``"ER```"'0$`-G(```*(``"A<@```AT!`+1R```"0```+W8`
+M``$"``"`=P```0(``(IW```"U```E'<```$"``">=P```M0``/MW```"*0``
+M(W@```(I``"G>0```BD``,-Y```"*0``W'D```(I```]>@```N8``'!Z```"
+M*0``[GH```)````->P```AT!`!-[```"20``>7L```)+`0"U>P```OX``"]\
+M```""@$`;GP```*O``"7?P```I4``*A_```"-@$`VG\```(V`0#W?P```C8!
+M`/F````"'0$`*8$```)```!?@P```BD``'F#```"O@``FH,```$"``"@@P``
+M`M0``!6$```"=P$`5X0```(=`0#NA````AT!`"F%```",0$`A(4```(Q`0#!
+MA0```C$!`"2&```!`@``:88```)=`0"FA@```AT!`,Z&```"'0$`"8<```(Q
+M`0`]AP```F0!`&"'```",0$`P8<```)*`0#LAP```GH``,6(```"'0$`58D`
+M``+-```GB@```2P``#N*```!$@$`CXH```):`0"@B@```AT!`!60```"NP``
+M.)````+4``!4D````M0``)&0```"0```3I$```(Q`0#(D0```B@!`-R1```"
+M,```ZY$```+0```,D@```B@!`"Z2```"OP``*),```+P``!,DP```0(``'.3
+M```"U```!)4```+P```HE0```B$``$>5```"00$`@)4```(A``":E0```B$`
+M`-"5```"00$`%)8```(A```NE@```B$``&26```"00$`KY8```(A``!7F```
+M`@`!`*.8```"&```S)@```(?`0`[F0```AT!`&&9```"'0$`Y9H```&M``#M
+MF@```?(``/6:```!UP``#9L```(3`0!AFP```D```$B>```"Y@``29\```)W
+M`0!BH````BD``'*@```"*0``@*````$%``":H````04``,6@```!!0``UZ``
+M``$%```"H0```0(``!6A```!`@``+:$```$"``!!H0```0(``%FA```!`@``
+M7J$```$"```9I````@L!`-.D```"'0$`]Z0```)````'I0```AH``(2E```"
+M]P``(:8```)K```QI@```D@``&2F```"CP``@Z8```+$``"BI@```C$``!BG
+M```"/0$`2*<```(=`0!QIP```CT!`!*H```"'0$`4:@```(=`0"KJ````AT!
+M`."H```"'0$`[*@```(]`0#:J0```AH``.ZI```"'0$`^*D```(:``!>J@``
+M`AT!`'&J```"0```JJH```)_``#"J@```0(``,^J```"*0``X*H```$"```.
+MJP```BD``#BK```"*0``2JP```(=`0!GK````BL``%"M```"5`$`@*T```$"
+M```CKP```04``$2O```!!0``8:\```$%```IL````04``#VP```"*0``6;``
+M``$%``!JL````BD``(>P```"*0``F;````$%``"JL````BD``,>P```"*0``
+MU[````$%``#YL````04``!&Q```!!0``$[(```(^``#JM````A(``&^U```!
+M!@``=+4```(*`0"!M0```08``(:U```""@$`B[4```$&``"CM0```08``+*U
+M```!!@``N;4```$&``#"M0```08``-"U```!!@``Z+4```$&``#_M0```08`
+M``RV```!!@``';8```$&``!!M@```08``&2V```!!@``<K8```$&``!\M@``
+M`08``.VV```!!@``+K<```$&``"RMP```08``,"W```!!@``YK<```$&```)
+MN````08``"&X```!!@``)K@```$&``!/N````08``%2X```!!@``TK@```$&
+M``#?N````FT!`">Y```"_```7[L```$"``";O````0(``(N]```"8@``I,$`
+M``$"``"ZP0```0(``%O#```!`@``GL,```$"``"QPP```0(``-K#```!`@``
+M],,```$"```6Q````0(``"G$```!`@```,4```+>```1Q0```O```$[%```"
+M\```>L4```+P``"YQ0```DL!`/7%```"_@``B\8```(*`0#2Q@```E@``&O*
+M```!$@$`<<H```$L``"!R@```;$``+/,```"6@$`Q,P```(=`0`'SP```BD`
+M`"7/```!`@``-L\```$"``!#SP```0(``%#/```!`@``J\\```*^``#5SP``
+M`0(``-O/```"U```K]````)%``#/T````F4!`._0```"<`$`:=$```(7``"3
+MT0```CH``#_2```";P$`IM(```)O`0#6T@```F\!`!O3```";P$`:M,```)O
+M`0#5TP```0(``-K3```!`@``)=0```)=`0!NU````AT!`';4```".@``EM0`
+M``(=`0#+U````F\!`/O4```"&0$`)M4```*:``!+U0```FP!`%[5```"4@$`
+M<M4```(%`0"8U0```F\!`/'5```"HP``&=8```)V``!"U@```F<``&C6```"
+M90$`<-8```)Z``!-UP```AT!`+/:```!+```Q]H```$2`0`SVP```GD!`$3;
+M```"'0$`!=T```)````\W@```L8``.+A```!`@``NN,```(/`0`&Y0```@\!
+M`#3E```"U```4.4```+4```(YP```0(``"_G```"U```V.H```(A``#[Z@``
+M`D$!`#3K```"(0``3NL```(A``"$ZP```D$!`,CK```"(0``XNL```(A```8
+M[````D$!`&/L```"(0``>^P```(@``"W[````A,``.OM```"$P``S.X```$"
+M``"$[P```@`!`#_P```"&```:/````(?`0";\````AT!`,'P```"'0$`:?(`
+M``$F``!Q\@```9P``'CR```!-`$`@?(```&)``"(\@```3\!`*'R```"$P$`
+M]?(```)````D\P```BH``"SS```"R@``4_,```)X``!W]0```H0``%;V```"
+M90$`<_8```+F```S]P```E0``#OW```"0@``2/<```)P`0!%^````0(``%?X
+M```!`@``<?@```(=`0"'^````0(``*+X```!`@``N/@```(=`0#F^````E,`
+M``KZ```"4```6/H```+O``!H^@```BH!``O[```"(```//P```(=`0``_0``
+M`H```%[]```"#```;OT```*H``"`_0```D```)K]```"C@``S?T```(X``#L
+M_0```B<```O^```"/```^/X```)E`0!/_P```F4!`&<``0`"'0$`A@`!``(=
+M`0#%``$``N8``,X"`0`"'0$`X0(!``)````$`P$``F4!`,X#`0`"70``I`0!
+M``(I``#G!0$``KP``*0)`0`"4```R at D!``(*`0#;"0$``@H!``X*`0`!`@``
+MRPP!``)M`0#W#`$``A(``(P.`0`"_```CA$!``+4``#_$@$``CP!`#T4`0`"
+M/`$`/!8!``$"``!,%@$``0(``&T6`0`!`@``>18!``$"``#S&`$``0(``/T8
+M`0`!`@``@1H!``(I```\&P$``E$``'4;`0`"7```HQL!``)1``#I&P$``EP`
+M`"0<`0`"7```91P!``+&``#`'`$``L8```@=`0`"2P$`4!T!``+^```+'@$`
+M`@H!`%(>`0`"30``UR$!``$2`0#=(0$``2P``.LA`0`!L0``!R0!``)Y`0`8
+M)`$``AT!`(TD`0`"Q@``4B4!``+&``#)*`$``F8!`"LI`0`"9@$``RH!``(*
+M`0"Z*@$``BH``/(J`0`">```5BL!``$"``#Q+@$``0(``!$P`0`"9@$`:3`!
+M``*3``"(,`$``I,``,8P`0`"DP``T#`!``*3``#P,`$``I,```HQ`0`"DP``
+M(3$!``*3```P,0$``@@!`$LQ`0`"DP``7C$!``*3``"I,0$``I,``.HQ`0`"
+MDP``^3$!``((`0`4,@$``I,``&DR`0`"DP``<S(!``*3``!],@$``I,``(HR
+M`0`"DP``E#(!``*3``"=,@$``E8!`*HR`0`"R0``SS(!``*3``#G,@$``I,`
+M``$S`0`"DP``%S,!``*3```O,P$``I,``$8S`0`"5@$`4S,!``+)``"-,P$`
+M`E8!`)HS`0`"R0``VS,!``)F`0!#-0$``I,``%PU`0`"DP``>#4!``*3``"4
+M-0$``I,``+`U`0`"DP``I#8!``)F`0#1-@$``0(``-8V`0`!!```W#8!``)S
+M`0`--P$``0(``!(W`0`!!```&#<!``)S`0!=.`$``0(``&\X`0`!`@``AC@!
+M``(=`0"B.`$``0(``*DX`0`!`@``O#@!``(=`0#9.`$``0(``.(X`0`!`@``
+M]3@!``(=`0`B.0$``G\``#HY`0`!`@``1SD!``(I``!8.0$``0(``+PY`0`"
+M*0``ZCD!``(I``!R.@$``0(``/@\`0`!`@``+ST!``)N``!"/0$``FX``%D]
+M`0`!`@``<ST!``(=`0"-/0$``0(``)0]`0`!`@``JCT!``(=`0#+/0$``0(`
+M`-T]`0`!`@``]ST!``(=`0`8/@$``0(``"H^`0`!`@``1#X!``(=`0!9/@$`
+M`0(``*$^`0`";@``N#X!``)N``#4/@$``FX``.D^`0`";@``_CX!``)N```3
+M/P$``FX``"D_`0`!`@``0S\!``(=`0!=/P$``0(``(P_`0`";@``H3\!``)N
+M``"Y/P$``0(``-,_`0`"'0$`D4$!``(*`0"Z1`$``CP!`)I&`0`"/`$`PT8!
+M``)Z``#G1@$``GH``!-'`0`"O@``/T<!``*^``!>1P$``0$``&A'`0`!`0``
+M<D<!``$!``!\1P$``0$``(9'`0`!`0``D$<!``$!``#%1P$``0(``-='`0`!
+M`@``[D<!``(=`0`*2`$``0(``!%(`0`!`@``)$@!``(=`0!!2`$``0(``$I(
+M`0`!`@``74@!``(=`0`J20$``BD``*A)`0`"*0``MDD!``(I``#\20$``BD`
+M``I*`0`"*0``4DH!``(I``!@2@$``BD``,Y*`0`!`@``$DT!``$"```J30$`
+M`0(``$E-`0`!`@``:$T!``$"``"630$``FX``+!-`0`";@``RTT!``)N``#Z
+M30$``FX``!A.`0`";@``-DX!``)N``!43@$``FX``').`0`";@``D$X!``)N
+M``"X3@$``FX``-!.`0`";@``\$X!``)N```(3P$``FX``$1/`0`";@``54\!
+M``)N``!F3P$``FX``'I/`0`";@``GD\!``)N``"O3P$``FX``,!/`0`";@``
+MU$\!``)N``#H3P$``FX``/I/`0`!`@``/%`!``)N``!:4`$``FX``&Q0`0`!
+M`@``A5`!``(=`0"=4`$``0(``+=0`0`"'0$`SU`!``$"``#I4`$``AT!``%1
+M`0`!`@``&U$!``(=`0`Y40$``0(``%91`0`"'0$`BE,!``+4``"?4P$``M0`
+M`/)3`0`"U```)50!``+4```Z5`$``M0``(U4`0`"U```N%0!``+4``#-5`$`
+M`M0``"!5`0`"U```-UP!``)Z``!;7`$``GH``(=<`0`"O@``LUP!``*^``#<
+M7`$``0$``.9<`0`!`0``\%P!``$!``#Z7`$``0$```1=`0`!`0``#ET!``$!
+M``!!70$``0(``%-=`0`!`@``;5T!``(=`0"&70$``0(``(U=`0`!`@``HUT!
+M``(=`0#%70$``0(``,Y=`0`!`@``Y%T!``(=`0"R7@$``BD``#!?`0`"*0``
+M/E\!``(I``"$7P$``BD``))?`0`"*0``VE\!``(I``#H7P$``BD``.)@`0`!
+M`@``^F`!``$"```980$``0(``#AA`0`!`@``9F$!``)N``!^80$``FX``)!A
+M`0`!`@``LF$!``$"``#+80$``AT!`.-A`0`!`@``_6$!``(=`0`58@$``0(`
+M`"]B`0`"'0$`26(!``$"``!C8@$``AT!`(!B`0`!`@``FF(!``(=`0#>8@$`
+M`0(``(-K`0`">@``IVL!``)Z``#3:P$``KX``/]K`0`"O@``'FP!``$!```H
+M;`$``0$``#)L`0`!`0``/&P!``$!``!&;`$``0$``%!L`0`!`0````````$!
+M```$`````0$```@````!`0``#`````$!```0`````0$``!0````!`0``&```
+M``$!```<`````0$``"`````!`0``)`````$!```H`````0$``"P````!`0``
+M,`````$!```T`````0$``#@````!`0``/`````$!``#D`````0,``.@````!
+M`P``_`````$#`````0```0,``!0!```!`P``&`$```$#```L`0```0,``#`!
+M```!`P``1`$```$#``!(`0```0,``%P!```!`P``8`$```$#``!T`0```0,`
+M`'@!```!`P``C`$```$#``"0`0```0,``*0!```!`P``J`$```$#``"\`0``
+M`0,``,`!```!`P``U`$```$#``#8`0```0,``.P!```!`P``\`$```$#```$
+M`@```0,```@"```!`P``'`(```$#```@`@```0,``#0"```!`P``.`(```$#
+M``!,`@```0,``%`"```!`P``9`(```$#``!H`@```0,``'P"```!`P``@`(`
+M``$#``"4`@```0,``)@"```!`P``K`(```$#``"P`@```0,``,0"```!`P``
+MR`(```$#``#<`@```0,``.`"```!`P``]`(```$#``#X`@```0,```P#```!
+M`P``$`,```$#```D`P```0,``"@#```!`P``/`,```$#``!``P```0,``%0#
+M```!`P``6`,```$#``!L`P```0,``'`#```!`P``A`,```$#``"(`P```0,`
+M`)P#```!`P``H`,```$#``"T`P```0,``+@#```!`P``S`,```$#``#0`P``
+M`0,``.0#```!`P``Z`,```$#``#\`P```0,````$```!`P``%`0```$#```8
+M!````0,``"P$```!`P``,`0```$#``!$!````0,``$@$```!`P``7`0```$#
+M``!@!````0,``'0$```!`P``>`0```$#``",!````0,``)`$```!`P``I`0`
+M``$#``"H!````0,``+P$```!`P``P`0```$#``#4!````0,``-@$```!`P``
+M[`0```$#``#P!````0,```0%```!`P``"`4```$#```<!0```0,``"`%```!
+M`P``-`4```$#```X!0```0,``$P%```!`P``4`4```$#``!D!0```0,``&@%
+M```!`P``?`4```$#``"`!0```0,``)0%```!`P``F`4```$#``"L!0```0,`
+M`+`%```!`P``Q`4```$#``#(!0```0,``-P%```!`P``X`4```$#``#T!0``
+M`0,``/@%```!`P``#`8```$#```0!@```0,``"0&```!`P``*`8```$#```\
+M!@```0,``$`&```!`P``5`8```$#``!8!@```0,``&P&```!`P``<`8```$#
+M``"$!@```0,``(@&```!`P``G`8```$#``"@!@```0,``+0&```!`P``N`8`
+M``$#``#,!@```0,``-`&```!`P``Y`8```$#``#H!@```0,``/P&```!`P``
+M``<```$#```4!P```0,``!@'```!`P``+`<```$#```P!P```0,``$0'```!
+M`P``2`<```$#``!<!P```0,``&`'```!`P``=`<```$#``!X!P```0,``(P'
+M```!`P``D`<```$#``"D!P```0,``*@'```!`P``O`<```$#``#`!P```0,`
+M`-0'```!`P``V`<```$#``#L!P```0,``/`'```!`P``!`@```$#```("```
+M`0,``!P(```!`P``(`@```$#```T"````0,``#@(```!`P``3`@```$#``!0
+M"````0,``&0(```!`P``:`@```$#``!\"````0,``(`(```!`P``E`@```$#
+M``"8"````0,``*P(```!`P``L`@```$#``#$"````0,``,@(```!`P``W`@`
+M``$#``#@"````0,``/0(```!`P``^`@```$#```,"0```0,``!`)```!`P``
+M)`D```$#```H"0```0,``#P)```!`P``0`D```$#``!4"0```0,``%@)```!
+M`P``;`D```$#``!P"0```0,``(0)```!`P``B`D```$#``"<"0```0,``*`)
+M```!`P``M`D```$#``"X"0```0,``,P)```!`P``T`D```$#``#D"0```0,`
+M`.@)```!`P``_`D```$#````"@```0,``!0*```!`P``&`H```$#```L"@``
+M`0,``#`*```!`P``1`H```$#``!("@```0,``%P*```!`P``8`H```$#``!T
+M"@```0,``'@*```!`P``C`H```$#``"0"@```0,``*0*```!`P``J`H```$#
+M``"\"@```0,``,`*```!`P``U`H```$#``#8"@```0,``.P*```!`P``\`H`
+M``$#```$"P```0,```@+```!`P``\!````$%``#T$````04``/@0```!!0``
+M_!````$%````$0```04```01```!!0``"!$```$%```,$0```04``!`1```!
+M!0``%!$```$%```H$0```04``"P1```!!0``,!$```$%```T$0```04``#@1
+M```!!0``/!$```$%``!`$0```04``$01```!!0``2!$```$%``!@$0```04`
+M`&01```!!0``:!$```$%``!L$0```04``'`1```!!0``=!$```$%``!X$0``
+M`04``'P1```!!0``@!$```$%``"8$0```04``)P1```!!0``H!$```$%``"D
+M$0```04``*@1```!!0``K!$```$%``"P$0```04``+01```!!0``N!$```$%
+M``#0$0```04``-01```!!0``V!$```$%``#<$0```04``.`1```!!0``Y!$`
+M``$%``#H$0```04``.P1```!!0```!(```$%```($@```04```P2```!!0``
+M$!(```$%```4$@```04``!@2```!!0``'!(```$%```@$@```04``"02```!
+M!0``*!(```$%```L$@```04``$`2```!!0``1!(```$%``!($@```04``$P2
+M```!!0``4!(```$%``!4$@```04``%@2```!!0``7!(```$%``!X$@```04`
+M`'P2```!!0``@!(```$%``"$$@```04``(@2```!!0``C!(```$%``"0$@``
+M`04``+`2```!!0``M!(```$%``"X$@```04``+P2```!!0``P!(```$%``#H
+M$@```04``.P2```!!0``\!(```$%``#T$@```04``/@2```!!0``_!(```$%
+M````$P```04```03```!!0``(!,```$%```D$P```04``"@3```!!0``+!,`
+M``$%```P$P```04``#03```!!0``<!,```$%``!T$P```04``'@3```!!0``
+M?!,```$%``"`$P```04``(03```!!0``B!,```$%``",$P```04``)`3```!
+M!0``J!,```$%``"L$P```04``+`3```!!0``M!,```$%``"X$P```04``+P3
+M```!!0``P!,```$%``#$$P```04``, at 3```!!0``X!,```$%``#D$P```04`
+M`. at 3```!!0``[!,```$%``#P$P```04``/03```!!0``^!,```$%``#\$P``
+M`04````4```!!0``&!0```$%```<%````04``"`4```!!0``)!0```$%```H
+M%````04``"P4```!!0``,!0```$%```T%````04``#@4```!!0``4!0```$%
+M``!4%````04``%@4```!!0``7!0```$%``!@%````04``&04```!!0``:!0`
+M``$%``"`%````04``(@4```!!0``C!0```$%``"0%````04``)04```!!0``
+MF!0```$%``"<%````04``*`4```!!0``I!0```$%``"H%````04``,`4```!
+M!0``Q!0```$%``#(%````04``,P4```!!0``T!0```$%``#4%````04``- at 4
+M```!!0``W!0```$%``#X%````04``/P4```!!0```!4```$%```$%0```04`
+M``@5```!!0``#!4```$%```0%0```04``#`5```!!0``-!4```$%```X%0``
+M`04``#P5```!!0``0!4```$%``!H%0```04``&P5```!!0``<!4```$%``!T
+M%0```04``'@5```!!0``?!4```$%``"`%0```04``(05```!!0``H!4```$%
+M``"D%0```04``*@5```!!0``K!4```$%``"P%0```04``+05```!!0``Z!4`
+M``$%``#T%0```04````6```!!0``&!8```$!```<%@```0$``"`6```!`0``
+M)!8```$!```H%@```0$``"P6```!`0``,!8```$!```T%@```0$``#@6```!
+M`0``/!8```$!``!`%@```0$``$06```!`0``2!8```$!``!,%@```0$``%`6
+M```!`0``5!8```$!``!8%@```0$``%P6```!`0``8!8```$!``!D%@```0$`
+M`&@6```!`0``;!8```$!``!P%@```0$``'06```!`0``>!8```$!``!\%@``
+M`0$``(`6```!`0``A!8```$!``"(%@```0$``(P6```!`0``D!8```$!``"4
+M%@```0$``)@6```!`0``G!8```$!``"@%@```0$``*06```!`0``J!8```$!
+M``"L%@```0$``+`6```!`0``M!8```$!``"X%@```0$``+P6```!`0``P!8`
+M``$!``#$%@```0$``, at 6```!`0``]!8```$"``#X%@```0(``"@7```!`@``
+M*!@```'V```L&````5H``#`8```!L@``-!@```&D```X&````<,``#P8```!
+M2P``0!@```'.``!$&````5P!`$@8```!,P$`3!@```&O``!0&````34``%08
+M```!>P``6!@```%.``!<&````1P``&`8```!30$`9!@```%U`0!H&````2@`
+M`&P8```!@@``<!@```'N``!T&````3`!`'@8```!)```?!@```$S``"`&```
+M`5X``(08```!8@$`B!@```$#`0",&````:4``)`8```!10$`E!@```%(`0"8
+M&````?,``)P8```!S```H!@```$D`0"D&````84``*@8```!5P$`K!@```&P
+M``"P&````:<``+08```!?```N!@```&?``"\&````4P``,`8```!N```Q!@`
+M``$@`0#(&````?@``,P8```!F0``T!@```$<`0#4&````=4``- at 8```!%0$`
+MW!@```$M``#@&````:8``.08```!0`$`Z!@```$&`0#L&````0X!`/`8```!
+M-```]!@```%J``#X&````2P!`/P8```!T@```!D```%&```$&0```2\```@9
+M```!@0``#!D```$)```0&0```>```!09```!)0$`&!D```%C`0`<&0```5\`
+M`"`9```!"P``)!D```%)`0`H&0```0(!`"P9```!4P$`,!D```$[```T&0``
+M`1<!`#@9```!$0``/!D```&N``!`&0```64``$09```!X@``2!D```'D``!,
+M&0```;T``%`9```!1`$`5!D```&L``!8&0```6$!`%P9```!#0``8!D```$U
+M`0!D&0```:(``&@9```!#`$`;!D```'U``!P&0```94``'09```!-@$`>!D`
+M``$!``!\&0```2L!`(`9```!=`$`A!D```$4`0",&0```4`!`)`9```!!@$`
+ME!D```$.`0"8&0```30``)P9```!:@``Z"4```$M`0#L)0```4H!`/`E```!
+M/@$`]"4```%@`0#X)0```6P``/PE```!AP```"8```%B```$)@```2X```@F
+M```!5P``#"8```%8```0)@```3(``!0F```!4`$`&"8```'W```<)@```6L!
+M`"`F```!=P``)"8```%:`0`H)@```>L``"PF```!G0``,"8```&J```T)@``
+M`1$!`#@F```!'@``/"8```'Q``!`)@```18``$0F```!3`$`2"8```$;``!,
+M)@```24``%`F```!G@``5"8```%?`0!8)@```4X!`%PF```!6P$`8"8```$A
+M`0!D)@```=T``&@F```!Z```;"8```'8``!P)@```?L``'0F```!<P``>"8`
+M``&-``!\)@```6D``(`F```!,@$`A"8```&4``"()@```38``(PF```!(@$`
+MD"8```$>`0"4)@```7```)@F```!S0``G"8```$8`0"@)@```=$``*0F```!
+MM0``J"8```'0``"L)@```2@!`+`F```!OP``M"8```$P``"X)@```58``+PF
+M```!R```P"8```$O`0#$)@```3H!`, at F```!$`$`S"8```$9``#0)@```5(`
+M`-0F```!&@$`V"8```&/``#<)@```48!`.`F```!Q```Y"8```'M``#H)@``
+M`3$``.PF```!Z0``\"8```$B``#T)@```4<``/@F```!A@``_"8```'+````
+M)P```;L```0G```!/0$`""<```&Z```,)P```?\``!`G```!^0``%"<```$[
+M`0`8)P```0@``!PG```!E@``("<```%F```D)P```8P``"@G```!8```+"<`
+M``'9```P)P```=X``#0G```!\```."<```$!```\)P```00!`$`G```!%@$`
+M1"<```$Q`0!,)P```;4``%`G```!T```5"<```$H`0!8)P```;\``%PG```!
+M,```6#L```$!``!<.P```0$``&`[```!`0``9#L```$!``!H.P```0$``&P[
+M```!`0``<#L```$!``!T.P```0$``,@\```!40``S#P```%V``#0/````5@!
+M`-0\```!80``V#P```''``#</````:D``.`\```!!P$`Y#P```%*``#H/```
+M`9(``.P\```!30``\#P```'L``#T/````4,!`/@\```!@```_#P```'G````
+M/0```=,```0]```!>0$`"#T```%Q`0`,/0```:L``!`]```!+@$`%#T```%R
+M```8/0```0T!`!P]```!(P``(#T```%"`0`D/0```3@!`"@]```!1P$`+#T`
+M``%5```P/0```2<!`#0]```!Z@``.#T```'E```\/0```1```$`]```!40$`
+M1#T```%Q``!(/0```<\``$P]```!5@$`4#T```')``!4/0```8H``%@]```!
+M&P$`7#T```'C``!@/0```0X``&0]```!D0``:#T```$*``!L/0```8L``'`]
+M```!)@$`=#T```&@``!X/0```0D!`'P]```!F```@#T```&A``"$/0```0$!
+M`(@]```!1```C#T```$I`0"0/0```3<!`)0]```!_0``F#T```%V`0"</0``
+M`3\``*`]```!MP``I#T```&;``"H/0```68!`*P]```!0@``L#T```&#``"T
+M/0```6H!`+@]```!.```O#T```%!``#`/0```2<``,0]```!-P``R#T```$\
+M``#,/0```74``-`]```!%0``U#T```%H``#8/0```>$``-P]```!8P``X#T`
+M``$/`0#D/0```64!`.@]```!P0``[#T```%Y``#P/0```4,``/0]```!'0``
+M^#T```%R`0#\/0```?H````^```!P@``!#X```&7```(/@```1\```P^```!
+M60$`$#X```%D```4/@```<8``!@^```!M@``'#X```'%```@/@```=8``"0^
+M```!;P$`+#X```$!`0`P/@```40``#0^```!*0$`.#X```$W`0`\/@```?T`
+M`/Q$```!`0```$4```$!```$10```0$```A%```!`0``#$4```$!```010``
+M`0$``$!%```!`0``1$4```$!``!(10```0$``$Q%```!`0``4$4```$!``!4
+M10```0$``%A%```!`0``7$4```$!``!@10```0$``&1%```!`0``:$4```$!
+M``!L10```0$``'!%```!`0``=$4```$!``!X10```0$``'Q%```!`0``@$4`
+M``$!``!P40```0$``'11```!`0``>%$```$!``!\40```0$``(!1```!`0``
+MA%$```$!``"H7@```0$``*Q>```!`0``L%X```$!``"T7@```0$``+A>```!
+M`0``O%X```$!``#`7@```0$``,1>```!`0``N&H```$!``"\:@```0$``,!J
+M```!`0``Q&H```$!``#(:@```0$``,QJ```!`0``T&H```$!``#4:@```0$`
+M`.AV```!`0``['8```$!``#P=@```0$``/1V```!`0``^'8```$!``#\=@``
+M`0$```!W```!`0``!'<```$!```,`````0,``!`````!`P``%`````$#```8
+M`````0,``!P````!`P``(`````$#```\`0```04``$0!```!!0``3`$```$%
+M``!4`0```04``%P!```!!0``9`$```$%``!L`0```04``'0!```!!0``?`$`
+M``$%``"$`0```04``(P!```!!0``E`$```$%``"<`0```04``*0!```!!0``
+0K`$```$%``"T`0```04`````
+`
+end
diff -N -u -r src.preview/sys/contrib/dev/ath/public/i386-elf.inc src/sys/contrib/dev/ath/public/i386-elf.inc
--- src.preview/sys/contrib/dev/ath/public/i386-elf.inc 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/public/i386-elf.inc 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,58 @@
+#
+# Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+# redistribution must be conditioned upon including a substantially
+# similar Disclaimer requirement for further binary redistribution.
+# 3. Neither the names of the above-listed copyright holders nor the names
+# of any contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU General Public License ("GPL") version 2 as published by the Free
+# Software Foundation.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+#
+# $Id: i386-elf.inc,v 1.1.1.1 2004/12/08 18:06:08 sam Exp $
+#
+
+#
+# Compilation configuration for building i386-elf.
+# This assumes the build platform is also i386-elf.
+#
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX=
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+ifndef CONFIG_FRAME_POINTER
+COPTS+= -fomit-frame-pointer
+endif
diff -N -u -r src.preview/sys/contrib/dev/ath/public/i386-elf.opt_ah.h src/sys/contrib/dev/ath/public/i386-elf.opt_ah.h
--- src.preview/sys/contrib/dev/ath/public/i386-elf.opt_ah.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/public/i386-elf.opt_ah.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,6 @@
+#define AH_SUPPORT_AR5210 1
+#define AH_SUPPORT_AR5211 1
+#define AH_SUPPORT_AR5212 1
+#define AH_SUPPORT_5111 1
+#define AH_SUPPORT_5112 1
+#define AH_SUPPORT_2413 1
diff -N -u -r src.preview/sys/contrib/dev/ath/version.h src/sys/contrib/dev/ath/version.h
--- src.preview/sys/contrib/dev/ath/version.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/contrib/dev/ath/version.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $Id: version.h,v 1.1.1.6 2004/12/08 18:04:16 sam Exp $
+ */
+#define ATH_HAL_VERSION "0.9.14.9"
diff -N -u -r src.preview/sys/dev/netif/Makefile src/sys/dev/netif/Makefile
--- src.preview/sys/dev/netif/Makefile 2005-08-31 18:55:28.000000000 -0400
+++ src/sys/dev/netif/Makefile 2005-09-26 10:54:04.000000000 -0400
@@ -1,8 +1,8 @@
# $DragonFly: src/sys/dev/netif/Makefile,v 1.14 2005/08/31 22:55:28 swildner Exp $
#
-SUBDIR= an ar aue axe bfe bge cue dc ed em ep fwe fxp gx ipw iwi kue lge lnc \
- mii_layer my nge nv owi pcn ray re rl sbni sbsh sf sis sk \
- sr ste ti tl tx txp vr vx wb wi xe xl
+SUBDIR= an ar ath aue axe bfe bge cue dc ed em ep fwe fxp gx kue lge lnc \
+ mii_layer my nge nv pcn re rl sbni sbsh sf sis sk sr ste ti tl \
+ tx txp vr vx wb xe xl
.include <bsd.subdir.mk>
diff -N -u -r src.preview/sys/dev/netif/ath/Makefile src/sys/dev/netif/ath/Makefile
--- src.preview/sys/dev/netif/ath/Makefile 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/Makefile 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+# redistribution must be conditioned upon including a substantially
+# similar Disclaimer requirement for further binary redistribution.
+# 3. Neither the names of the above-listed copyright holders nor the names
+# of any contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU General Public License ("GPL") version 2 as published by the Free
+# Software Foundation.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+#
+# $FreeBSD: src/sys/modules/ath/Makefile,v 1.1 2003/06/23 17:02:43 sam Exp $
+#
+
+
+KMOD= if_ath
+SRCS= if_ath.c if_ath_pci.c
+SRCS+= opt_bdg.h device_if.h bus_if.h pci_if.h opt_inet.h
+
+HAL= ${.CURDIR}/../../../contrib/dev/ath
+CFLAGS+= -g -I. -I${HAL}/freebsd -I${HAL}
+
+SUBDIR= ath_rate ath_hal
+
+.include <bsd.kmod.mk>
diff -N -u -r src.preview/sys/dev/netif/ath/ath_hal/Makefile src/sys/dev/netif/ath/ath_hal/Makefile
--- src.preview/sys/dev/netif/ath/ath_hal/Makefile 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_hal/Makefile 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,70 @@
+#
+# Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+# redistribution must be conditioned upon including a substantially
+# similar Disclaimer requirement for further binary redistribution.
+# 3. Neither the names of the above-listed copyright holders nor the names
+# of any contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU General Public License ("GPL") version 2 as published by the Free
+# Software Foundation.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+#
+# $FreeBSD: /repoman/r/ncvs/src/sys/modules/ath_hal/Makefile,v 1.3 2004/12/08 17:38:37 sam Exp $
+#
+
+#
+# Hardware Access Layer (HAL) for the Atheros Wireless NIC driver.
+#
+# This module contains the hardware-specific bits for the network
+# interface driver. It is built as a separate module to simplify
+# maintenance and isolate the bits that are not (currently) distributed
+# in source form.
+#
+HAL= ${.CURDIR}/../../../../contrib/dev/ath
+
+.PATH: ${HAL}/freebsd
+
+KMOD= ath_hal
+SRCS= ah_osdep.c
+SRCS+= bus_if.h device_if.h pci_if.h ah_if.h opt_ah.h
+OBJS= hal.o
+MFILES= kern/bus_if.m kern/device_if.m bus/pci/pci_if.m \
+ contrib/dev/ath/freebsd/ah_if.m
+
+CFLAGS+= -I. -I../../.. -I${HAL}/freebsd -I${HAL}
+
+.if defined(HAL_SRC)
+.include "${HAL}/freebsd/Makefile.inc"
+.else
+
+hal.o: ${HAL}/public/i386-elf.hal.o.uu
+ uudecode -p < ${HAL}/public/i386-elf.hal.o.uu > ${.TARGET}
+opt_ah.h: ${HAL}/public/i386-elf.opt_ah.h
+ cp ${HAL}/public/i386-elf.opt_ah.h ${.TARGET}
+.endif
+
+.include <bsd.kmod.mk>
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/Makefile src/sys/dev/netif/ath/ath_rate/Makefile
--- src.preview/sys/dev/netif/ath/ath_rate/Makefile 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/Makefile 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,7 @@
+# $DragonFly: src/sys/dev/netif/Makefile,v 1.13 2005/03/06 18:25:08 dillon Exp $
+#
+
+SUBDIR= ammr onoe sample
+
+.include <bsd.subdir.mk>
+
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/ammr/Makefile src/sys/dev/netif/ath/ath_rate/ammr/Makefile
--- src.preview/sys/dev/netif/ath/ath_rate/ammr/Makefile 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/ammr/Makefile 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2004 Sam Leffler, Errno Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+# redistribution must be conditioned upon including a substantially
+# similar Disclaimer requirement for further binary redistribution.
+# 3. Neither the names of the above-listed copyright holders nor the names
+# of any contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU General Public License ("GPL") version 2 as published by the Free
+# Software Foundation.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+#
+# $FreeBSD: /repoman/r/ncvs/src/sys/modules/ath_rate_amrr/Makefile,v 1.1 2004/12/08 17:38:37 sam Exp $
+#
+
+.PATH: ${.CURDIR}/../../dev/ath/ath_rate/amrr
+
+KMOD= ath_rate_ammr
+SRCS= amrr.c
+SRCS+= opt_bdg.h device_if.h bus_if.h pci_if.h opt_inet.h
+
+HAL= ${.CURDIR}/../../../../../contrib/dev/ath
+CFLAGS+= -I. -I${HAL}/freebsd -I${HAL}
+
+.include <bsd.kmod.mk>
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/ammr/amrr.c src/sys/dev/netif/ath/ath_rate/ammr/amrr.c
--- src.preview/sys/dev/netif/ath/ath_rate/ammr/amrr.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/ammr/amrr.c 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,545 @@
+/*-
+ * Copyright (c) 2004 INRIA
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * AMRR rate control. See:
+ * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
+ * "IEEE 802.11 Rate Adaptation: A Practical Approach" by
+ * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
+ */
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <netproto/802_11/ieee80211_var.h>
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include "../../if_athvar.h"
+#include "../../if_athrate.h"
+#include "amrr.h"
+#include "contrib/dev/ath/ah_desc.h"
+
+#define AMRR_DEBUG
+#ifdef AMRR_DEBUG
+#define DPRINTF(sc, _fmt, ...) do { \
+ if (0) \
+ printf(_fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, _fmt, ...)
+#endif
+
+static int ath_rateinterval = 1000; /* rate ctl interval (ms) */
+static int ath_rate_max_success_threshold = 10;
+static int ath_rate_min_success_threshold = 1;
+
+static void ath_ratectl(void *);
+static void ath_rate_update(struct ath_softc *, struct ieee80211_node *,
+ int rate);
+static void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *);
+static void ath_rate_ctl(void *, struct ieee80211_node *);
+
+void
+ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+{
+ /* NB: assumed to be zero'd by caller */
+ ath_rate_update(sc, &an->an_node, 0);
+}
+
+void
+ath_rate_node_cleanup(struct ath_softc *sc __unused,
+ struct ath_node *an __unused)
+{
+}
+
+void
+ath_rate_findrate(struct ath_softc *sc __unused, struct ath_node *an,
+ int shortPreamble, size_t frameLen __unused,
+ u_int8_t *rix, int *try0, u_int8_t *txrate)
+{
+ struct amrr_node *amn = ATH_NODE_AMRR(an);
+
+ *rix = amn->amn_tx_rix0;
+ *try0 = amn->amn_tx_try0;
+ if (shortPreamble)
+ *txrate = amn->amn_tx_rate0sp;
+ else
+ *txrate = amn->amn_tx_rate0;
+}
+
+void
+ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
+ struct ath_desc *ds, int shortPreamble __unused,
+ u_int8_t rix __unused)
+{
+ struct amrr_node *amn = ATH_NODE_AMRR(an);
+
+ ath_hal_setupxtxdesc(sc->sc_ah, ds
+ , amn->amn_tx_rate1sp, amn->amn_tx_try1 /* series 1 */
+ , amn->amn_tx_rate2sp, amn->amn_tx_try2 /* series 2 */
+ , amn->amn_tx_rate3sp, amn->amn_tx_try3 /* series 3 */
+ );
+}
+
+void
+ath_rate_tx_complete(struct ath_softc *sc __unused,
+ struct ath_node *an, const struct ath_desc *ds, const struct ath_desc *ds0 __unused)
+{
+ struct amrr_node *amn = ATH_NODE_AMRR(an);
+ int sr = ds->ds_txstat.ts_shortretry;
+ int lr = ds->ds_txstat.ts_longretry;
+ int retry_count = sr + lr;
+
+ amn->amn_tx_try0_cnt++;
+ if (retry_count == 1) {
+ amn->amn_tx_try1_cnt++;
+ } else if (retry_count == 2) {
+ amn->amn_tx_try1_cnt++;
+ amn->amn_tx_try2_cnt++;
+ } else if (retry_count == 3) {
+ amn->amn_tx_try1_cnt++;
+ amn->amn_tx_try2_cnt++;
+ amn->amn_tx_try3_cnt++;
+ } else if (retry_count > 3) {
+ amn->amn_tx_try1_cnt++;
+ amn->amn_tx_try2_cnt++;
+ amn->amn_tx_try3_cnt++;
+ amn->amn_tx_failure_cnt++;
+ }
+}
+
+void
+ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
+{
+ if (isnew)
+ ath_rate_ctl_start(sc, &an->an_node);
+}
+
+static void
+node_reset (struct amrr_node *amn)
+{
+ amn->amn_tx_try0_cnt = 0;
+ amn->amn_tx_try1_cnt = 0;
+ amn->amn_tx_try2_cnt = 0;
+ amn->amn_tx_try3_cnt = 0;
+ amn->amn_tx_failure_cnt = 0;
+ amn->amn_success = 0;
+ amn->amn_recovery = 0;
+ amn->amn_success_threshold = ath_rate_min_success_threshold;
+}
+
+
+/**
+ * The code below assumes that we are dealing with hardware multi rate retry
+ * I have no idea what will happen if you try to use this module with another
+ * type of hardware. Your machine might catch fire or it might work with
+ * horrible performance...
+ */
+static void
+ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate)
+{
+ struct ath_node *an = ATH_NODE(ni);
+ struct amrr_node *amn = ATH_NODE_AMRR(an);
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ u_int8_t rix;
+
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+
+ DPRINTF(sc, "%s: set xmit rate for %6D to %dM\n",
+ __func__, (ni->ni_macaddr), ":",
+ ni->ni_rates.rs_nrates > 0 ?
+ (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0);
+
+ ni->ni_txrate = rate;
+ /* XXX management/control frames always go at the lowest speed */
+ an->an_tx_mgtrate = rt->info[0].rateCode;
+ an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble;
+ /*
+ * Before associating a node has no rate set setup
+ * so we can't calculate any transmit codes to use.
+ * This is ok since we should never be sending anything
+ * but management frames and those always go at the
+ * lowest hardware rate.
+ */
+ if (ni->ni_rates.rs_nrates > 0) {
+ amn->amn_tx_rix0 = sc->sc_rixmap[
+ ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL];
+ amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode;
+ amn->amn_tx_rate0sp = amn->amn_tx_rate0 |
+ rt->info[amn->amn_tx_rix0].shortPreamble;
+ if (sc->sc_mrretry) {
+ amn->amn_tx_try0 = 1;
+ amn->amn_tx_try1 = 1;
+ amn->amn_tx_try2 = 1;
+ amn->amn_tx_try3 = 1;
+ if (--rate >= 0) {
+ rix = sc->sc_rixmap[
+ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
+ amn->amn_tx_rate1 = rt->info[rix].rateCode;
+ amn->amn_tx_rate1sp = amn->amn_tx_rate1 |
+ rt->info[rix].shortPreamble;
+ } else {
+ amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0;
+ }
+ if (--rate >= 0) {
+ rix = sc->sc_rixmap[
+ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
+ amn->amn_tx_rate2 = rt->info[rix].rateCode;
+ amn->amn_tx_rate2sp = amn->amn_tx_rate2 |
+ rt->info[rix].shortPreamble;
+ } else {
+ amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0;
+ }
+ if (rate > 0) {
+ /* NB: only do this if we didn't already do it above */
+ amn->amn_tx_rate3 = rt->info[0].rateCode;
+ amn->amn_tx_rate3sp =
+ an->an_tx_mgtrate | rt->info[0].shortPreamble;
+ } else {
+ amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0;
+ }
+ } else {
+ amn->amn_tx_try0 = ATH_TXMAXTRY;
+ /* theorically, these statements are useless because
+ * the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY
+ */
+ amn->amn_tx_try1 = 0;
+ amn->amn_tx_try2 = 0;
+ amn->amn_tx_try3 = 0;
+ amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0;
+ amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0;
+ amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0;
+ }
+ }
+ node_reset (amn);
+}
+
+/*
+ * Set the starting transmit rate for a node.
+ */
+static void
+ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
+{
+#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
+ struct ieee80211com *ic = &sc->sc_ic;
+ int srate;
+
+ KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates"));
+ if (ic->ic_fixed_rate == -1) {
+ /*
+ * No fixed rate is requested. For 11b start with
+ * the highest negotiated rate; otherwise, for 11g
+ * and 11a, we start "in the middle" at 24Mb or 36Mb.
+ */
+ srate = ni->ni_rates.rs_nrates - 1;
+ if (sc->sc_curmode != IEEE80211_MODE_11B) {
+ /*
+ * Scan the negotiated rate set to find the
+ * closest rate.
+ */
+ /* NB: the rate set is assumed sorted */
+ for (; srate >= 0 && RATE(srate) > 72; srate--)
+ ;
+ KASSERT(srate >= 0, ("bogus rate set"));
+ }
+ } else {
+ /*
+ * A fixed rate is to be used; ic_fixed_rate is an
+ * index into the supported rate set. Convert this
+ * to the index into the negotiated rate set for
+ * the node. We know the rate is there because the
+ * rate set is checked when the station associates.
+ */
+ const struct ieee80211_rateset *rs =
+ &ic->ic_sup_rates[ic->ic_curmode];
+ int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
+ /* NB: the rate set is assumed sorted */
+ srate = ni->ni_rates.rs_nrates - 1;
+ for (; srate >= 0 && RATE(srate) != r; srate--)
+ ;
+ KASSERT(srate >= 0,
+ ("fixed rate %d not in rate set", ic->ic_fixed_rate));
+ }
+ ath_rate_update(sc, ni, srate);
+#undef RATE
+}
+
+static void
+ath_rate_cb(void *arg, struct ieee80211_node *ni)
+{
+ ath_rate_update(ni->ni_ic->ic_ifp->if_softc, ni, (int)(uintptr_t) arg);
+}
+
+/*
+ * Reset the rate control state for each 802.11 state transition.
+ */
+void
+ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
+{
+ struct amrr_softc *asc = (struct amrr_softc *) sc->sc_rc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni;
+
+ if (state == IEEE80211_S_INIT) {
+ callout_stop(&asc->timer);
+ return;
+ }
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ /*
+ * Reset local xmit state; this is really only
+ * meaningful when operating in station mode.
+ */
+ ni = ic->ic_bss;
+ if (state == IEEE80211_S_RUN) {
+ ath_rate_ctl_start(sc, ni);
+ } else {
+ ath_rate_update(sc, ni, 0);
+ }
+ } else {
+ /*
+ * When operating as a station the node table holds
+ * the AP's that were discovered during scanning.
+ * For any other operating mode we want to reset the
+ * tx rate state of each node.
+ */
+ ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, 0);
+ ath_rate_update(sc, ic->ic_bss, 0);
+ }
+ if (ic->ic_fixed_rate == -1 && state == IEEE80211_S_RUN) {
+ int interval;
+ /*
+ * Start the background rate control thread if we
+ * are not configured to use a fixed xmit rate.
+ */
+ interval = ath_rateinterval;
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ interval /= 2;
+ callout_reset(&asc->timer, (interval * hz) / 1000,
+ ath_ratectl, &sc->sc_if);
+ }
+}
+
+/*
+ * Examine and potentially adjust the transmit rate.
+ */
+static void
+ath_rate_ctl(void *arg, struct ieee80211_node *ni)
+{
+ struct ath_softc *sc = arg;
+ struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni));
+ int old_rate;
+
+#define is_success(amn) \
+(amn->amn_tx_try1_cnt < (amn->amn_tx_try0_cnt/10))
+#define is_enough(amn) \
+(amn->amn_tx_try0_cnt > 10)
+#define is_failure(amn) \
+(amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt/3))
+#define is_max_rate(ni) \
+((ni->ni_txrate + 1) >= ni->ni_rates.rs_nrates)
+#define is_min_rate(ni) \
+(ni->ni_txrate == 0)
+
+ old_rate = ni->ni_txrate;
+
+ DPRINTF (sc, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d\n",
+ amn->amn_tx_try0_cnt,
+ amn->amn_tx_try1_cnt,
+ amn->amn_tx_try2_cnt,
+ amn->amn_tx_try3_cnt,
+ amn->amn_success_threshold);
+ if (is_success (amn) && is_enough (amn)) {
+ amn->amn_success++;
+ if (amn->amn_success == amn->amn_success_threshold &&
+ !is_max_rate (ni)) {
+ amn->amn_recovery = 1;
+ amn->amn_success = 0;
+ ni->ni_txrate++;
+ DPRINTF (sc, "increase rate to %d\n", ni->ni_txrate);
+ } else {
+ amn->amn_recovery = 0;
+ }
+ } else if (is_failure (amn)) {
+ amn->amn_success = 0;
+ if (!is_min_rate (ni)) {
+ if (amn->amn_recovery) {
+ /* recovery failure. */
+ amn->amn_success_threshold *= 2;
+ amn->amn_success_threshold = min (amn->amn_success_threshold,
+ (u_int)ath_rate_max_success_threshold);
+ DPRINTF (sc, "decrease rate recovery thr: %d\n", amn->amn_success_threshold);
+ } else {
+ /* simple failure. */
+ amn->amn_success_threshold = ath_rate_min_success_threshold;
+ DPRINTF (sc, "decrease rate normal thr: %d\n", amn->amn_success_threshold);
+ }
+ amn->amn_recovery = 0;
+ ni->ni_txrate--;
+ } else {
+ amn->amn_recovery = 0;
+ }
+
+ }
+ if (is_enough (amn) || old_rate != ni->ni_txrate) {
+ /* reset counters. */
+ amn->amn_tx_try0_cnt = 0;
+ amn->amn_tx_try1_cnt = 0;
+ amn->amn_tx_try2_cnt = 0;
+ amn->amn_tx_try3_cnt = 0;
+ amn->amn_tx_failure_cnt = 0;
+ }
+ if (old_rate != ni->ni_txrate) {
+ ath_rate_update(sc, ni, ni->ni_txrate);
+ }
+}
+
+static void
+ath_ratectl(void *arg)
+{
+ struct ifnet *ifp = arg;
+ struct ath_softc *sc = ifp->if_softc;
+ struct amrr_softc *asc = (struct amrr_softc *) sc->sc_rc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ int interval;
+
+ if (ifp->if_flags & IFF_RUNNING) {
+ sc->sc_stats.ast_rate_calls++;
+
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ ath_rate_ctl(sc, ic->ic_bss); /* NB: no reference */
+ else
+ ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_ctl, sc);
+ }
+ interval = ath_rateinterval;
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ interval /= 2;
+ callout_reset(&asc->timer, (interval * hz) / 1000,
+ ath_ratectl, &sc->sc_if);
+}
+
+static void
+ath_rate_sysctlattach(struct ath_softc *sc)
+{
+ struct sysctl_ctx_list *ctx = &sc->sysctl_ctx;
+ struct sysctl_oid *tree = sc->sysctl_tree;
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "rate_interval", CTLFLAG_RW, &ath_rateinterval, 0,
+ "rate control: operation interval (ms)");
+ /* XXX bounds check values */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "max_sucess_threshold", CTLFLAG_RW,
+ &ath_rate_max_success_threshold, 0, "");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "min_sucess_threshold", CTLFLAG_RW,
+ &ath_rate_min_success_threshold, 0, "");
+}
+
+struct ath_ratectrl *
+ath_rate_attach(struct ath_softc *sc)
+{
+ struct amrr_softc *asc;
+
+ asc = malloc(sizeof(struct amrr_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (asc == NULL)
+ return NULL;
+ asc->arc.arc_space = sizeof(struct amrr_node);
+ callout_init(&asc->timer);
+ ath_rate_sysctlattach(sc);
+
+ return &asc->arc;
+}
+
+void
+ath_rate_detach(struct ath_ratectrl *arc)
+{
+ struct amrr_softc *asc = (struct amrr_softc *) arc;
+
+ callout_stop(&asc->timer);
+ free(asc, M_DEVBUF);
+}
+
+/*
+ * Module glue.
+ */
+static int
+amrr_modevent(module_t mod __unused, int type, void *unused __unused)
+{
+ switch (type) {
+ case MOD_LOAD:
+ printf("ath_rate: <AMRR rate control algorithm> version 0.1\n");
+ return 0;
+ case MOD_UNLOAD:
+ return 0;
+ }
+ return EINVAL;
+}
+
+static moduledata_t amrr_mod = {
+ "ath_rate",
+ amrr_modevent,
+ 0
+};
+DECLARE_MODULE(ath_rate, amrr_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(ath_rate, 1);
+MODULE_DEPEND(ath_rate, wlan, 1, 1, 1);
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/ammr/amrr.h src/sys/dev/netif/ath/ath_rate/ammr/amrr.h
--- src.preview/sys/dev/netif/ath/ath_rate/ammr/amrr.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/ammr/amrr.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2004 INRIA
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/ath/ath_rate/amrr/amrr.h,v 1.2 2004/12/31 22:41:45 sam Exp $
+ */
+
+#ifndef _DEV_ATH_RATE_AMRR_H
+#define _DEV_ATH_RATE_AMRR_H
+
+/* per-device state */
+struct amrr_softc {
+ struct ath_ratectrl arc; /* base state */
+ struct callout timer; /* periodic timer */
+};
+
+/* per-node state */
+struct amrr_node {
+ /* AMRR statistics for this node */
+ u_int amn_tx_try0_cnt;
+ u_int amn_tx_try1_cnt;
+ u_int amn_tx_try2_cnt;
+ u_int amn_tx_try3_cnt;
+ u_int amn_tx_failure_cnt;
+ /* AMRR algorithm state for this node */
+ u_int amn_success_threshold;
+ u_int amn_success;
+ u_int amn_recovery;
+ /* rate index et al. */
+ u_int8_t amn_tx_rix0; /* series 0 rate index */
+ u_int8_t amn_tx_rate0; /* series 0 h/w rate */
+ u_int8_t amn_tx_rate1; /* series 1 h/w rate */
+ u_int8_t amn_tx_rate2; /* series 2 h/w rate */
+ u_int8_t amn_tx_rate3; /* series 3 h/w rate */
+ u_int8_t amn_tx_rate0sp; /* series 0 short preamble h/w rate */
+ u_int8_t amn_tx_rate1sp; /* series 1 short preamble h/w rate */
+ u_int8_t amn_tx_rate2sp; /* series 2 short preamble h/w rate */
+ u_int8_t amn_tx_rate3sp; /* series 3 short preamble h/w rate */
+ u_int8_t amn_tx_try0; /* series 0 try count */
+ u_int amn_tx_try1; /* series 1 try count */
+ u_int amn_tx_try2; /* series 2 try count */
+ u_int amn_tx_try3; /* series 3 try count */
+};
+#define ATH_NODE_AMRR(an) ((struct amrr_node *)&an[1])
+#endif /* _DEV_ATH_RATE_AMRR_H */
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/onoe/Makefile src/sys/dev/netif/ath/ath_rate/onoe/Makefile
--- src.preview/sys/dev/netif/ath/ath_rate/onoe/Makefile 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/onoe/Makefile 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2004 Sam Leffler, Errno Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+# redistribution must be conditioned upon including a substantially
+# similar Disclaimer requirement for further binary redistribution.
+# 3. Neither the names of the above-listed copyright holders nor the names
+# of any contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU General Public License ("GPL") version 2 as published by the Free
+# Software Foundation.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+#
+#
+
+KMOD= ath_rate_onoe
+SRCS= onoe.c
+SRCS+= opt_bdg.h device_if.h bus_if.h pci_if.h opt_inet.h
+
+HAL= ${.CURDIR}/../../../../../contrib/dev/ath
+CFLAGS+= -I. -I${HAL}/freebsd -I${HAL}
+
+.include <bsd.kmod.mk>
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/onoe/onoe.c src/sys/dev/netif/ath/ath_rate/onoe/onoe.c
--- src.preview/sys/dev/netif/ath/ath_rate/onoe/onoe.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/onoe/onoe.c 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,539 @@
+/*-
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * Atsushi Onoe's rate control algorithm.
+ */
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <netproto/802_11/ieee80211_var.h>
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include "../../if_athvar.h"
+#include "../../if_athrate.h"
+#include "onoe.h"
+#include "contrib/dev/ath/ah_desc.h"
+
+#define ONOE_DEBUG
+#ifdef ONOE_DEBUG
+enum {
+ ATH_DEBUG_RATE = 0x00000010, /* rate control */
+};
+#define DPRINTF(sc, _fmt, ...) do { \
+ if (sc->sc_debug & ATH_DEBUG_RATE) \
+ printf(_fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, _fmt, ...)
+#endif
+
+/*
+ * Default parameters for the rate control algorithm. These are
+ * all tunable with sysctls. The rate controller runs periodically
+ * (each ath_rateinterval ms) analyzing transmit statistics for each
+ * neighbor/station (when operating in station mode this is only the AP).
+ * If transmits look to be working well over a sampling period then
+ * it gives a "raise rate credit". If transmits look to not be working
+ * well than it deducts a credit. If the credits cross a threshold then
+ * the transmit rate is raised. Various error conditions force the
+ * the transmit rate to be dropped.
+ *
+ * The decision to issue/deduct a credit is based on the errors and
+ * retries accumulated over the sampling period. ath_rate_raise defines
+ * the percent of retransmits for which a credit is issued/deducted.
+ * ath_rate_raise_threshold defines the threshold on credits at which
+ * the transmit rate is increased.
+ *
+ * XXX this algorithm is flawed.
+ */
+static int ath_rateinterval = 1000; /* rate ctl interval (ms) */
+static int ath_rate_raise = 10; /* add credit threshold */
+static int ath_rate_raise_threshold = 10; /* rate ctl raise threshold */
+
+static void ath_ratectl(void *);
+static void ath_rate_update(struct ath_softc *, struct ieee80211_node *,
+ int rate);
+static void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *);
+static void ath_rate_ctl(void *, struct ieee80211_node *);
+
+void
+ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+{
+ /* NB: assumed to be zero'd by caller */
+ ath_rate_update(sc, &an->an_node, 0);
+}
+
+void
+ath_rate_node_cleanup(struct ath_softc *sc __unused,
+ struct ath_node *an __unused)
+{
+}
+
+void
+ath_rate_findrate(struct ath_softc *sc __unused, struct ath_node *an,
+ int shortPreamble, size_t frameLen __unused,
+ u_int8_t *rix, int *try0, u_int8_t *txrate)
+{
+ struct onoe_node *on = ATH_NODE_ONOE(an);
+
+ *rix = on->on_tx_rix0;
+ *try0 = on->on_tx_try0;
+ if (shortPreamble)
+ *txrate = on->on_tx_rate0sp;
+ else
+ *txrate = on->on_tx_rate0;
+}
+
+void
+ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
+ struct ath_desc *ds, int shortPreamble __unused,
+ u_int8_t rix __unused)
+{
+ struct onoe_node *on = ATH_NODE_ONOE(an);
+
+ ath_hal_setupxtxdesc(sc->sc_ah, ds
+ , on->on_tx_rate1sp, 2 /* series 1 */
+ , on->on_tx_rate2sp, 2 /* series 2 */
+ , on->on_tx_rate3sp, 2 /* series 3 */
+ );
+}
+
+void
+ath_rate_tx_complete(struct ath_softc *sc __unused,
+ struct ath_node *an, const struct ath_desc *ds, const struct ath_desc *ds0)
+{
+ struct onoe_node *on = ATH_NODE_ONOE(an);
+
+ if (ds->ds_txstat.ts_status == 0)
+ on->on_tx_ok++;
+ else
+ on->on_tx_err++;
+ on->on_tx_retr += ds->ds_txstat.ts_shortretry
+ + ds->ds_txstat.ts_longretry;
+}
+
+void
+ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
+{
+ if (isnew)
+ ath_rate_ctl_start(sc, &an->an_node);
+}
+
+static void
+ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate)
+{
+ struct ath_node *an = ATH_NODE(ni);
+ struct onoe_node *on = ATH_NODE_ONOE(an);
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ u_int8_t rix;
+
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+
+#if 0
+ if ( !sc || !an || !on || !rt || !rt->info ) {
+ printf("ath_rate_update: %p %p %p %p %p\n",
+ sc, an, on, rt, (rt) ? rt->info : 0 );
+ return;
+ }
+
+ DPRINTF(sc, "%s: set xmit rate for %s to %dM\n",
+ __func__, /* ether_sprintf(ni->ni_macaddr) */ "xx",
+ ni->ni_rates.rs_nrates > 0 ?
+ (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0);
+#endif
+
+ ni->ni_txrate = rate;
+ /* XXX management/control frames always go at the lowest speed */
+ an->an_tx_mgtrate = rt->info[0].rateCode;
+ an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble;
+ /*
+ * Before associating a node has no rate set setup
+ * so we can't calculate any transmit codes to use.
+ * This is ok since we should never be sending anything
+ * but management frames and those always go at the
+ * lowest hardware rate.
+ */
+ if (ni->ni_rates.rs_nrates == 0)
+ goto done;
+ on->on_tx_rix0 = sc->sc_rixmap[
+ ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL];
+ on->on_tx_rate0 = rt->info[on->on_tx_rix0].rateCode;
+
+ on->on_tx_rate0sp = on->on_tx_rate0 |
+ rt->info[on->on_tx_rix0].shortPreamble;
+ if (sc->sc_mrretry) {
+ /*
+ * Hardware supports multi-rate retry; setup two
+ * step-down retry rates and make the lowest rate
+ * be the ``last chance''. We use 4, 2, 2, 2 tries
+ * respectively (4 is set here, the rest are fixed
+ * in the xmit routine).
+ */
+ on->on_tx_try0 = 1 + 3; /* 4 tries at rate 0 */
+ if (--rate >= 0) {
+ rix = sc->sc_rixmap[
+ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
+ on->on_tx_rate1 = rt->info[rix].rateCode;
+ on->on_tx_rate1sp = on->on_tx_rate1 |
+ rt->info[rix].shortPreamble;
+ } else {
+ on->on_tx_rate1 = on->on_tx_rate1sp = 0;
+ }
+ if (--rate >= 0) {
+ rix = sc->sc_rixmap[
+ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
+ on->on_tx_rate2 = rt->info[rix].rateCode;
+ on->on_tx_rate2sp = on->on_tx_rate2 |
+ rt->info[rix].shortPreamble;
+ } else {
+ on->on_tx_rate2 = on->on_tx_rate2sp = 0;
+ }
+ if (rate > 0) {
+ /* NB: only do this if we didn't already do it above */
+ on->on_tx_rate3 = rt->info[0].rateCode;
+ on->on_tx_rate3sp =
+ an->an_tx_mgtrate | rt->info[0].shortPreamble;
+ } else {
+ on->on_tx_rate3 = on->on_tx_rate3sp = 0;
+ }
+ } else {
+ on->on_tx_try0 = ATH_TXMAXTRY; /* max tries at rate 0 */
+ on->on_tx_rate1 = on->on_tx_rate1sp = 0;
+ on->on_tx_rate2 = on->on_tx_rate2sp = 0;
+ on->on_tx_rate3 = on->on_tx_rate3sp = 0;
+ }
+done:
+ on->on_tx_ok = on->on_tx_err = on->on_tx_retr = on->on_tx_upper = 0;
+}
+
+/*
+ * Set the starting transmit rate for a node.
+ */
+static void
+ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
+{
+#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
+ struct ieee80211com *ic = &sc->sc_ic;
+ int srate;
+
+ KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates"));
+ if (ic->ic_fixed_rate == -1) {
+ /*
+ * No fixed rate is requested. For 11b start with
+ * the highest negotiated rate; otherwise, for 11g
+ * and 11a, we start "in the middle" at 24Mb or 36Mb.
+ */
+ srate = ni->ni_rates.rs_nrates - 1;
+ if (sc->sc_curmode != IEEE80211_MODE_11B) {
+ /*
+ * Scan the negotiated rate set to find the
+ * closest rate.
+ */
+ /* NB: the rate set is assumed sorted */
+ for (; srate >= 0 && RATE(srate) > 72; srate--)
+ ;
+ KASSERT(srate >= 0, ("bogus rate set"));
+ }
+ } else {
+ /*
+ * A fixed rate is to be used; ic_fixed_rate is an
+ * index into the supported rate set. Convert this
+ * to the index into the negotiated rate set for
+ * the node. We know the rate is there because the
+ * rate set is checked when the station associates.
+ */
+ const struct ieee80211_rateset *rs =
+ &ic->ic_sup_rates[ic->ic_curmode];
+ int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
+ /* NB: the rate set is assumed sorted */
+ srate = ni->ni_rates.rs_nrates - 1;
+ for (; srate >= 0 && RATE(srate) != r; srate--)
+ ;
+ KASSERT(srate >= 0,
+ ("fixed rate %d not in rate set", ic->ic_fixed_rate));
+ }
+ ath_rate_update(sc, ni, srate);
+#undef RATE
+
+static void
+ath_rate_cb(void *arg, struct ieee80211_node *ni)
+{
+ struct ath_softc *sc = arg;
+ ath_rate_update(sc, ni, 0);
+}
+
+/*
+ * Reset the rate control state for each 802.11 state transition.
+ */
+void
+ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
+{
+ struct onoe_softc *osc = (struct onoe_softc *) sc->sc_rc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni;
+
+ if (state == IEEE80211_S_INIT) {
+ callout_stop(&osc->timer);
+ return;
+ }
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ /*
+ * Reset local xmit state; this is really only
+ * meaningful when operating in station mode.
+ */
+ ni = ic->ic_bss;
+ if (state == IEEE80211_S_RUN) {
+ ath_rate_ctl_start(sc, ni);
+ } else {
+ ath_rate_update(sc, ni, 0);
+ }
+ } else {
+ /*
+ * When operating as a station the node table holds
+ * the AP's that were discovered during scanning.
+ * For any other operating mode we want to reset the
+ * tx rate state of each node.
+ */
+ ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, sc);
+ ath_rate_update(sc, ic->ic_bss, 0);
+ }
+ if (ic->ic_fixed_rate == -1 && state == IEEE80211_S_RUN) {
+ int interval;
+ /*
+ * Start the background rate control thread if we
+ * are not configured to use a fixed xmit rate.
+ */
+ interval = ath_rateinterval;
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ interval /= 2;
+ callout_reset(&osc->timer, (interval * hz) / 1000,
+ ath_ratectl, &sc->sc_if);
+ }
+}
+
+/*
+ * Examine and potentially adjust the transmit rate.
+ */
+static void
+ath_rate_ctl(void *arg, struct ieee80211_node *ni)
+{
+ struct ath_softc *sc = arg;
+ struct onoe_node *on = ATH_NODE_ONOE(ATH_NODE(ni));
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ int dir = 0, nrate, enough;
+
+ /*
+ * Rate control
+ * XXX: very primitive version.
+ */
+ enough = (on->on_tx_ok + on->on_tx_err >= 10);
+
+ /* no packet reached -> down */
+ if (on->on_tx_err > 0 && on->on_tx_ok == 0)
+ dir = -1;
+
+ /* all packets needs retry in average -> down */
+ if (enough && on->on_tx_ok < on->on_tx_retr)
+ dir = -1;
+
+ /* no error and less than rate_raise% of packets need retry -> up */
+ if (enough && on->on_tx_err == 0 &&
+ on->on_tx_retr < (on->on_tx_ok * ath_rate_raise) / 100)
+ dir = 1;
+
+#if 0
+ DPRINTF(sc, "%s: ok %d err %d retr %d upper %d dir %d\n",
+ /* ether_sprintf(ni->ni_macaddr) */ "xx",
+ on->on_tx_ok, on->on_tx_err, on->on_tx_retr,
+ on->on_tx_upper, dir);
+#endif
+
+ nrate = ni->ni_txrate;
+ switch (dir) {
+ case 0:
+ if (enough && on->on_tx_upper > 0)
+ on->on_tx_upper--;
+ break;
+ case -1:
+ if (nrate > 0) {
+ nrate--;
+ sc->sc_stats.ast_rate_drop++;
+ }
+ on->on_tx_upper = 0;
+ break;
+ case 1:
+ /* raise rate if we hit rate_raise_threshold */
+ if (++on->on_tx_upper < ath_rate_raise_threshold)
+ break;
+ on->on_tx_upper = 0;
+ if (nrate + 1 < rs->rs_nrates) {
+ nrate++;
+ sc->sc_stats.ast_rate_raise++;
+ }
+ break;
+ }
+
+ if (nrate != ni->ni_txrate) {
+#if 0
+ DPRINTF(sc, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n",
+ __func__,
+ (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL) / 2,
+ (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2,
+ on->on_tx_ok, on->on_tx_err, on->on_tx_retr);
+#endif
+ ath_rate_update(sc, ni, nrate);
+ } else if (enough)
+ on->on_tx_ok = on->on_tx_err = on->on_tx_retr = 0;
+}
+
+static void
+ath_ratectl(void *arg)
+{
+ struct ifnet *ifp = arg;
+ struct ath_softc *sc = ifp->if_softc;
+ struct onoe_softc *osc = (struct onoe_softc *) sc->sc_rc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ int interval;
+
+ if (ifp->if_flags & IFF_RUNNING) {
+ sc->sc_stats.ast_rate_calls++;
+
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ ath_rate_ctl(sc, ic->ic_bss); /* NB: no reference */
+ else
+ ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_ctl, sc);
+ }
+ interval = ath_rateinterval;
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ interval /= 2;
+ callout_reset(&osc->timer, (interval * hz) / 1000,
+ ath_ratectl, &sc->sc_if);
+}
+
+static void
+ath_rate_sysctlattach(struct ath_softc *sc)
+{
+ struct sysctl_ctx_list *ctx = &sc->sysctl_ctx;
+ struct sysctl_oid *tree = sc->sysctl_tree;
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "rate_interval", CTLFLAG_RW, &ath_rateinterval, 0,
+ "rate control: operation interval (ms)");
+ /* XXX bounds check values */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "rate_raise", CTLFLAG_RW, &ath_rate_raise, 0,
+ "rate control: retry threshold to credit rate raise (%%)");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "rate_raise_threshold", CTLFLAG_RW, &ath_rate_raise_threshold,0,
+ "rate control: # good periods before raising rate");
+}
+
+struct ath_ratectrl *
+ath_rate_attach(struct ath_softc *sc)
+{
+ struct onoe_softc *osc;
+
+ osc = malloc(sizeof(struct onoe_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (osc == NULL)
+ return NULL;
+ osc->arc.arc_space = sizeof(struct onoe_node);
+ callout_init(&osc->timer);
+ ath_rate_sysctlattach(sc);
+
+ return &osc->arc;
+}
+
+void
+ath_rate_detach(struct ath_ratectrl *arc)
+{
+ struct onoe_softc *osc = (struct onoe_softc *) arc;
+
+ callout_stop(&osc->timer);
+ free(osc, M_DEVBUF);
+}
+
+/*
+ * Module glue.
+ */
+static int
+onoe_modevent(module_t mod __unused, int type, void *unused __unused)
+{
+ switch (type) {
+ case MOD_LOAD:
+ printf("ath_rate: <Atsushi Onoe's rate control algorithm>\n");
+ return 0;
+ case MOD_UNLOAD:
+ return 0;
+ }
+ return EINVAL;
+}
+
+static moduledata_t onoe_mod = {
+ "ath_rate",
+ onoe_modevent,
+ 0
+};
+DECLARE_MODULE(ath_rate, onoe_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(ath_rate, 1);
+MODULE_DEPEND(ath_rate, wlan, 1, 1, 1);
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/onoe/onoe.h src/sys/dev/netif/ath/ath_rate/onoe/onoe.h
--- src.preview/sys/dev/netif/ath/ath_rate/onoe/onoe.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/onoe/onoe.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/ath/ath_rate/onoe/onoe.h,v 1.2 2004/12/31 22:41:45 sam Exp $
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_RATE_ONOE_H
+#define _DEV_ATH_RATE_ONOE_H
+
+/* per-device state */
+struct onoe_softc {
+ struct ath_ratectrl arc; /* base state */
+ struct callout timer; /* periodic timer */
+};
+
+/* per-node state */
+struct onoe_node {
+ u_int on_tx_ok; /* tx ok pkt */
+ u_int on_tx_err; /* tx !ok pkt */
+ u_int on_tx_retr; /* tx retry count */
+ int on_tx_upper; /* tx upper rate req cnt */
+ u_int8_t on_tx_rix0; /* series 0 rate index */
+ u_int8_t on_tx_try0; /* series 0 try count */
+ u_int8_t on_tx_rate0; /* series 0 h/w rate */
+ u_int8_t on_tx_rate1; /* series 1 h/w rate */
+ u_int8_t on_tx_rate2; /* series 2 h/w rate */
+ u_int8_t on_tx_rate3; /* series 3 h/w rate */
+ u_int8_t on_tx_rate0sp; /* series 0 short preamble h/w rate */
+ u_int8_t on_tx_rate1sp; /* series 1 short preamble h/w rate */
+ u_int8_t on_tx_rate2sp; /* series 2 short preamble h/w rate */
+ u_int8_t on_tx_rate3sp; /* series 3 short preamble h/w rate */
+};
+#define ATH_NODE_ONOE(an) ((struct onoe_node *)&an[1])
+#endif /* _DEV_ATH_RATE_ONOE_H */
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/sample/Makefile src/sys/dev/netif/ath/ath_rate/sample/Makefile
--- src.preview/sys/dev/netif/ath/ath_rate/sample/Makefile 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/sample/Makefile 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2004 Sam Leffler, Errno Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+# redistribution must be conditioned upon including a substantially
+# similar Disclaimer requirement for further binary redistribution.
+# 3. Neither the names of the above-listed copyright holders nor the names
+# of any contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU General Public License ("GPL") version 2 as published by the Free
+# Software Foundation.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+#
+# $FreeBSD: /repoman/r/ncvs/src/sys/modules/ath_rate_amrr/Makefile,v 1.1 2004/12/08 17:38:37 sam Exp $
+#
+
+KMOD= ath_rate
+SRCS= sample.c
+SRCS+= opt_bdg.h device_if.h bus_if.h pci_if.h opt_inet.h
+
+HAL= ${.CURDIR}/../../../../../contrib/dev/ath
+CFLAGS+= -g -I. -I${HAL}/freebsd -I${HAL}
+
+.include <bsd.kmod.mk>
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/sample/sample.c src/sys/dev/netif/ath/ath_rate/sample/sample.c
--- src.preview/sys/dev/netif/ath/ath_rate/sample/sample.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/sample/sample.c 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,855 @@
+/*-
+ * Copyright (c) 2005 John Bicket
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * John Bicket's SampleRate control algorithm.
+ */
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <netproto/802_11/ieee80211_var.h>
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include "../../if_athvar.h"
+#include "../../if_athrate.h"
+#include "sample.h"
+#include "contrib/dev/ath/ah_desc.h"
+
+#define SAMPLE_DEBUG
+#ifdef SAMPLE_DEBUG
+enum {
+ ATH_DEBUG_RATE = 0x00000010, /* rate control */
+};
+#define DPRINTF(sc, _fmt, ...) do { \
+ if (sc->sc_debug & ATH_DEBUG_RATE) \
+ printf(_fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, _fmt, ...)
+#endif
+
+/*
+ * This file is an implementation of the SampleRate algorithm
+ * in "Bit-rate Selection in Wireless Networks"
+ * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)
+ *
+ * SampleRate chooses the bit-rate it predicts will provide the most
+ * throughput based on estimates of the expected per-packet
+ * transmission time for each bit-rate. SampleRate periodically sends
+ * packets at bit-rates other than the current one to estimate when
+ * another bit-rate will provide better performance. SampleRate
+ * switches to another bit-rate when its estimated per-packet
+ * transmission time becomes smaller than the current bit-rate's.
+ * SampleRate reduces the number of bit-rates it must sample by
+ * eliminating those that could not perform better than the one
+ * currently being used. SampleRate also stops probing at a bit-rate
+ * if it experiences several successive losses.
+ *
+ * The difference between the algorithm in the thesis and the one in this
+ * file is that the one in this file uses a ewma instead of a window.
+ *
+ */
+
+#define STALE_FAILURE_TIMEOUT_MS 10000
+
+static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
+
+static __inline int size_to_bin(int size)
+{
+ int x = 0;
+ for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) {
+ if (size <= packet_size_bins[x]) {
+ return x;
+ }
+ }
+ return NUM_PACKET_SIZE_BINS-1;
+}
+static __inline int bin_to_size(int ndx) {
+ return packet_size_bins[ndx];
+}
+
+static __inline int rate_to_ndx(struct sample_node *sn, int rate) {
+ int x = 0;
+ for (x = 0; x < sn->num_rates; x++) {
+ if (sn->rates[x].rate == rate) {
+ return x;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Setup rate codes for management/control frames. We force
+ * all such frames to the lowest rate.
+ */
+static void
+ath_rate_setmgtrates(struct ath_softc *sc, struct ath_node *an)
+{
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+
+ /* setup rates for management frames */
+ /* XXX management/control frames always go at lowest speed */
+ an->an_tx_mgtrate = rt->info[0].rateCode;
+ an->an_tx_mgtratesp = an->an_tx_mgtrate
+ | rt->info[0].shortPreamble;
+}
+
+void
+ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+{
+ DPRINTF(sc, "%s:\n", __func__);
+ /* NB: assumed to be zero'd by caller */
+ ath_rate_setmgtrates(sc, an);
+}
+
+void
+ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an __unused)
+{
+ DPRINTF(sc, "%s:\n", __func__);
+}
+
+
+/*
+ * returns the ndx with the lowest average_tx_time,
+ * or -1 if all the average_tx_times are 0.
+ */
+static __inline int best_rate_ndx(struct sample_node *sn, int size_bin,
+ int require_acked_before)
+{
+ int x = 0;
+ int best_rate_ndx_val = 0;
+ int best_rate_tt = 0;
+ for (x = 0; x < sn->num_rates; x++) {
+ int tt = sn->stats[size_bin][x].average_tx_time;
+ if (tt <= 0 || (require_acked_before &&
+ !sn->stats[size_bin][x].packets_acked)) {
+ continue;
+ }
+ if (!best_rate_tt || best_rate_tt > tt) {
+ best_rate_tt = tt;
+ best_rate_ndx_val = x;
+ }
+ }
+ return (best_rate_tt) ? best_rate_ndx_val : -1;
+}
+
+/*
+ * pick a ndx s.t. the perfect_tx_time
+ * is less than the best bit-rate's average_tx_time
+ * and the ndx has not had four successive failures.
+ */
+static __inline int pick_sample_ndx(struct sample_node *sn, int size_bin)
+{
+ int x = 0;
+ int current_ndx = 0;
+ unsigned current_tt = 0;
+
+ current_ndx = sn->current_rate[size_bin];
+ if (current_ndx < 0) {
+ /* no successes yet, send at the lowest bit-rate */
+ return 0;
+ }
+
+ current_tt = sn->stats[size_bin][current_ndx].average_tx_time;
+
+ for (x = 0; x < sn->num_rates; x++) {
+ int ndx = (sn->last_sample_ndx[size_bin] + 1 + x) % sn->num_rates;
+ /*
+ * clear any stale stuff out.
+ */
+ if (ticks - sn->stats[size_bin][ndx].last_tx > ((hz * STALE_FAILURE_TIMEOUT_MS)/1000)) {
+ sn->stats[size_bin][ndx].average_tx_time = sn->stats[size_bin][ndx].perfect_tx_time;
+ sn->stats[size_bin][ndx].successive_failures = 0;
+ sn->stats[size_bin][ndx].tries = 0;
+ sn->stats[size_bin][ndx].total_packets = 0;
+ sn->stats[size_bin][ndx].packets_acked = 0;
+ }
+
+ if (ndx != current_ndx &&
+ sn->stats[size_bin][ndx].perfect_tx_time < current_tt &&
+ sn->stats[size_bin][ndx].successive_failures < 4) {
+ sn->last_sample_ndx[size_bin] = ndx;
+ return ndx;
+ }
+ }
+ return current_ndx;
+}
+
+void
+ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
+ int shortPreamble, size_t frameLen,
+ u_int8_t *rix, int *try0, u_int8_t *txrate)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
+ struct ieee80211com *ic = &sc->sc_ic;
+ int ndx, size_bin, mrr, best_ndx;
+ unsigned average_tx_time;
+
+ mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) &&
+ !(frameLen > ic->ic_rtsthreshold);
+ size_bin = size_to_bin(frameLen);
+ best_ndx = best_rate_ndx(sn, size_bin, !mrr);
+
+ if (best_ndx >= 0) {
+ average_tx_time = sn->stats[size_bin][best_ndx].average_tx_time;
+ } else {
+ average_tx_time = 0;
+ }
+ if (sn->static_rate_ndx != -1) {
+ ndx = sn->static_rate_ndx;
+ *try0 = ATH_TXMAXTRY;
+ } else {
+ ndx = 0;
+ *try0 = mrr ? 2 : ATH_TXMAXTRY;
+
+ DPRINTF(sc, "%s: %6D size %d mrr %d packets_sent %d best_ndx %d "
+ "sample tt %d packets since %d\n"
+ , __func__, an->an_node.ni_macaddr, ":"
+ , packet_size_bins[size_bin]
+ , mrr
+ , sn->packets_sent[size_bin]
+ , best_ndx
+ , sn->sample_tt[size_bin]
+ , sn->packets_since_sample[size_bin]
+ );
+ if (!sn->packets_sent[size_bin]) {
+ /* no packets sent */
+ if (best_ndx == -1) {
+ ndx = sn->num_rates - 1;
+ if (sc->sc_curmode != IEEE80211_MODE_11B) {
+ for (; ndx >= 0 && sn->rates[ndx].rate > 72; ndx--)
+ ;
+
+ }
+ } else {
+ ndx = best_ndx;
+ }
+ } else if (best_ndx == -1) {
+ /* no packet has succeeded yet */
+ if (mrr) {
+ /*
+ * no packet has succeeded, try the
+ * highest bitrate that hasn't failed
+ */
+ for (ndx = sn->num_rates-1; ndx >= 0; ndx--) {
+ if (sn->stats[size_bin][ndx].successive_failures == 0) {
+ break;
+ }
+ }
+ } else {
+ ndx = sn->num_rates - 1;
+ if (sc->sc_curmode != IEEE80211_MODE_11B) {
+ for (; ndx >= 0 && sn->rates[ndx].rate > 72; ndx--)
+ ;
+
+ }
+ }
+ } else if (sn->sample_tt[size_bin] < (sn->packets_since_sample[size_bin]*ssc->ath_sample_rate/100) * average_tx_time &&
+ sn->packets_since_sample[size_bin] > 15) {
+ /*
+ * we want to limit the time measuring the performance
+ * of other bit-rates to ath_sample_rate% of the
+ * total transmission time.
+ */
+ ndx = pick_sample_ndx(sn, size_bin);
+ if (ndx != sn->current_rate[size_bin]) {
+ DPRINTF(sc, "%s: %6D size %d last sample tt %d sampling %d packets since %d\n",
+ __func__,
+ an->an_node.ni_macaddr, ":",
+ packet_size_bins[size_bin],
+ sn->sample_tt[size_bin],
+ sn->rates[ndx].rate,
+ sn->packets_since_sample[size_bin]);
+ sn->current_sample_ndx[size_bin] = ndx;
+ } else {
+ sn->current_sample_ndx[size_bin] = -1;
+ }
+ sn->packets_since_sample[size_bin] = 0;
+
+ } else {
+ sn->packets_since_sample[size_bin]++;
+ /*
+ * don't switch bit-rates every packet. only
+ * switch during the first few packets we send
+ * or after 100 packets, or if the current
+ * bit-rate begins to perform twice as bad as
+ * another one.
+ */
+ if (sn->packets_sent[size_bin] < 20 ||
+ ticks - ((hz*2000)/1000) > sn->jiffies_since_switch[size_bin] ||
+ average_tx_time * 2 < sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time ) {
+ if (sn->packets_sent[size_bin] > 20) {
+ DPRINTF(sc, "%s: %6D size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mmr %d\n",
+ __func__,
+ an->an_node.ni_macaddr, ":",
+ packet_size_bins[size_bin],
+ sn->rates[sn->current_rate[size_bin]].rate,
+ sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time,
+ sn->stats[size_bin][sn->current_rate[size_bin]].perfect_tx_time,
+ sn->rates[best_ndx].rate,
+ sn->stats[size_bin][best_ndx].average_tx_time,
+ sn->stats[size_bin][best_ndx].perfect_tx_time,
+ sn->packets_since_switch[size_bin],
+ mrr);
+ }
+ sn->packets_since_switch[size_bin] = 0;
+ sn->current_rate[size_bin] = best_ndx;
+ sn->jiffies_since_switch[size_bin] = ticks;
+ }
+ ndx = sn->current_rate[size_bin];
+ sn->packets_since_switch[size_bin]++;
+ }
+
+ }
+
+ if (ndx < 0) {
+ ndx = 0;
+ }
+ *rix = sn->rates[ndx].rix;
+ if (shortPreamble) {
+ *txrate = sn->rates[ndx].shortPreambleRateCode;
+ } else {
+ *txrate = sn->rates[ndx].rateCode;
+ }
+ sn->packets_sent[size_bin]++;
+ an->an_node.ni_txrate = ndx;
+}
+
+void
+ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
+ struct ath_desc *ds, int shortPreamble, u_int8_t rix __unused)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ int rateCode = -1;
+ int frame_size, size_bin, best_ndx, ndx;
+
+ frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
+ KASSERT(frame_size != 0, ("no frame size"));
+ size_bin = size_to_bin(frame_size);
+ best_ndx = best_rate_ndx(sn, size_bin, 0);
+
+ if (best_ndx == -1 || !sn->stats[size_bin][best_ndx].packets_acked) {
+ /*
+ * no packet has succeeded, so also try at the
+ * lowest bitate.
+ */
+ ndx = 0;
+ } else {
+ /*
+ * we're trying a different bit-rate, and it could be lossy,
+ * so if it fails try at the best bit-rate.
+ */
+ ndx = best_ndx;
+ }
+ KASSERT(0 <= ndx && ndx < IEEE80211_RATE_MAXSIZE,
+ ("invalid ndx %d", ndx));
+ if (shortPreamble) {
+ rateCode = sn->rates[ndx].shortPreambleRateCode;
+ } else {
+ rateCode = sn->rates[ndx].rateCode;
+ }
+ ath_hal_setupxtxdesc(sc->sc_ah, ds
+ , rateCode, 3 /* series 1 */
+ , sn->rates[0].rateCode, 3 /* series 2 */
+ , 0, 0 /* series 3 */
+ );
+}
+
+static void
+update_stats(struct ath_softc *sc, struct ath_node *an,
+ int frame_size,
+ int ndx0, int tries0,
+ int ndx1, int tries1,
+ int ndx2, int tries2,
+ int ndx3, int tries3,
+ int short_tries, int tries, int status)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
+ int tt = 0;
+ int tries_so_far = 0;
+ int size_bin = 0;
+ int size = 0;
+ int rate = 0;
+
+ size_bin = size_to_bin(frame_size);
+ size = bin_to_size(size_bin);
+ rate = sn->rates[ndx0].rate;
+
+ tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx0].rix,
+ short_tries-1,
+ MIN(tries0, tries) - 1);
+ tries_so_far += tries0;
+ if (tries1 && tries0 < tries) {
+ tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx1].rix,
+ short_tries-1,
+ MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
+ }
+ tries_so_far += tries1;
+
+ if (tries2 && tries0 + tries1 < tries) {
+ tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx2].rix,
+ short_tries-1,
+ MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
+ }
+
+ tries_so_far += tries2;
+
+ if (tries3 && tries0 + tries1 + tries2 < tries) {
+ tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx3].rix,
+ short_tries-1,
+ MIN(tries3 + tries_so_far, tries) - tries_so_far - 1);
+ }
+#ifdef SAMPLE_DEBUG
+ if (short_tries + tries > 3 || status) {
+ DPRINTF(sc, "%s: %6D size %d rate %d ndx %d tries (%d/%d) tries0 %d tt %d avg_tt %d perfect_tt %d status %d\n",
+ __func__, an->an_node.ni_macaddr, ":",
+ size,
+ rate, ndx0, short_tries, tries, tries0, tt,
+ sn->stats[size_bin][ndx0].average_tx_time,
+ sn->stats[size_bin][ndx0].perfect_tx_time,
+ status);
+ }
+#endif /* SAMPLE_DEBUG */
+ if (sn->stats[size_bin][ndx0].total_packets < (100 / (100 - ssc->ath_smoothing_rate))) {
+ /* just average the first few packets */
+ int avg_tx = sn->stats[size_bin][ndx0].average_tx_time;
+ int packets = sn->stats[size_bin][ndx0].total_packets;
+ sn->stats[size_bin][ndx0].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
+ } else {
+ /* use a ewma */
+ sn->stats[size_bin][ndx0].average_tx_time =
+ ((sn->stats[size_bin][ndx0].average_tx_time * ssc->ath_smoothing_rate) +
+ (tt * (100 - ssc->ath_smoothing_rate))) / 100;
+ }
+
+ if (status) {
+ /*
+ * this packet failed - count this as a failure
+ * for larger packets also, since we assume
+ * if a small packet fails at a lower bit-rate
+ * then a larger one will also.
+ */
+ int y;
+ for (y = size_bin; y < NUM_PACKET_SIZE_BINS; y++) {
+ sn->stats[y][ndx0].successive_failures++;
+ sn->stats[y][ndx0].last_tx = ticks;
+ }
+ } else {
+ sn->stats[size_bin][ndx0].packets_acked++;
+ sn->stats[size_bin][ndx0].successive_failures = 0;
+ }
+ sn->stats[size_bin][ndx0].tries += tries;
+ sn->stats[size_bin][ndx0].last_tx = ticks;
+ sn->stats[size_bin][ndx0].total_packets++;
+
+
+ if (ndx0 == sn->current_sample_ndx[size_bin]) {
+ DPRINTF(sc, "%s: %6D size %d sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d) status %d\n",
+ __func__, an->an_node.ni_macaddr, ":",
+ size, rate, short_tries, tries, tt,
+ sn->stats[size_bin][ndx0].average_tx_time,
+ sn->stats[size_bin][ndx0].perfect_tx_time,
+ status);
+ sn->sample_tt[size_bin] = tt;
+ sn->current_sample_ndx[size_bin] = -1;
+ }
+}
+
+void
+ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
+ const struct ath_desc *ds, const struct ath_desc *ds0)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ const struct ar5212_desc *ads = (const struct ar5212_desc *)&ds->ds_ctl0;
+ int final_rate, short_tries, long_tries, frame_size;
+ int ndx = -1;
+
+ final_rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
+ short_tries = ds->ds_txstat.ts_shortretry + 1;
+ long_tries = ds->ds_txstat.ts_longretry + 1;
+ frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
+ if (frame_size == 0) /* NB: should not happen */
+ frame_size = 1500;
+
+ if (sn->num_rates <= 0) {
+ DPRINTF(sc, "%s: %6D size %d status %d rate/try %d/%d "
+ "no rates yet\n",
+ __func__, an->an_node.ni_macaddr, ":",
+ bin_to_size(size_to_bin(frame_size)),
+ ds->ds_txstat.ts_status,
+ short_tries, long_tries);
+ return;
+ }
+
+ if (sc->sc_mrretry && ds->ds_txstat.ts_status) {
+ /* this packet failed */
+ DPRINTF(sc, "%s: %6D size %d rate/try %d/%d %d/%d %d/%d %d/%d status %s retries (%d/%d)\n",
+ __func__,
+ an->an_node.ni_macaddr, ":",
+ bin_to_size(size_to_bin(frame_size)),
+ sc->sc_hwmap[ads->xmit_rate0].ieeerate,
+ ads->xmit_tries0,
+ sc->sc_hwmap[ads->xmit_rate1].ieeerate,
+ ads->xmit_tries1,
+ sc->sc_hwmap[ads->xmit_rate2].ieeerate,
+ ads->xmit_tries2,
+ sc->sc_hwmap[ads->xmit_rate3].ieeerate,
+ ads->xmit_tries3,
+ ds->ds_txstat.ts_status ? "FAIL" : "OK",
+ short_tries,
+ long_tries);
+ }
+
+ if (!(ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)) {
+ /* only one rate was used */
+ ndx = rate_to_ndx(sn, final_rate);
+ DPRINTF(sc, "%s: %6D size %d status %d rate/try %d/%d/%d\n",
+ __func__, an->an_node.ni_macaddr, ":",
+ bin_to_size(size_to_bin(frame_size)),
+ ds->ds_txstat.ts_status,
+ ndx, short_tries, long_tries);
+ if (ndx >= 0 && ndx < sn->num_rates) {
+ update_stats(sc, an, frame_size,
+ ndx, long_tries,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ short_tries, long_tries, ds->ds_txstat.ts_status);
+ }
+ } else {
+ int rate0, tries0, ndx0;
+ int rate1, tries1, ndx1;
+ int rate2, tries2, ndx2;
+ int rate3, tries3, ndx3;
+ int finalTSIdx = ads->final_ts_index;
+
+ /*
+ * Process intermediate rates that failed.
+ */
+
+ rate0 = sc->sc_hwmap[ads->xmit_rate0].ieeerate;
+ tries0 = ads->xmit_tries0;
+ ndx0 = rate_to_ndx(sn, rate0);
+
+ if ( ndx0 < 0 ) /* garbage rate, ignore */
+ ndx0 = tries0 = rate0 = 0;
+
+ rate1 = sc->sc_hwmap[ads->xmit_rate1].ieeerate;
+ tries1 = ads->xmit_tries1;
+ ndx1 = rate_to_ndx(sn, rate1);
+
+ if ( ndx1 < 0 ) /* garbage rate, ignore */
+ ndx1 = tries1 = rate1 = 0;
+
+ rate2 = sc->sc_hwmap[ads->xmit_rate2].ieeerate;
+ tries2 = ads->xmit_tries2;
+ ndx2 = rate_to_ndx(sn, rate2);
+
+ if ( ndx2 < 0 ) /* garbage rate, ignore */
+ ndx2 = tries2 = rate2 = 0;
+
+ rate3 = sc->sc_hwmap[ads->xmit_rate3].ieeerate;
+ tries3 = ads->xmit_tries3;
+ ndx3 = rate_to_ndx(sn, rate3);
+
+ if ( ndx3 < 0 ) /* garbage rate, ignore */
+ ndx3 = tries3 = rate3 = 0;
+
+#if 1
+ DPRINTF(sc, "%s: %6D size %d finaltsidx %d tries %d status %d rate/try %d/%d %d/%d %d/%d %d/%d\n",
+ __func__, an->an_node.ni_macaddr, ":",
+ bin_to_size(size_to_bin(frame_size)),
+ finalTSIdx,
+ long_tries,
+ ds->ds_txstat.ts_status,
+ rate0, tries0,
+ rate1, tries1,
+ rate2, tries2,
+ rate3, tries3);
+#endif
+
+ if (tries0) {
+ update_stats(sc, an, frame_size,
+ ndx0, tries0,
+ ndx1, tries1,
+ ndx2, tries2,
+ ndx3, tries3,
+ short_tries, ds->ds_txstat.ts_longretry + 1,
+ ds->ds_txstat.ts_status);
+ }
+
+ if (tries1 && finalTSIdx > 0) {
+ update_stats(sc, an, frame_size,
+ ndx1, tries1,
+ ndx2, tries2,
+ ndx3, tries3,
+ 0, 0,
+ short_tries, ds->ds_txstat.ts_longretry + 1 - tries0,
+ ds->ds_txstat.ts_status);
+ }
+
+ if (tries2 && finalTSIdx > 1) {
+ update_stats(sc, an, frame_size,
+ ndx2, tries2,
+ ndx3, tries3,
+ 0, 0,
+ 0, 0,
+ short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1,
+ ds->ds_txstat.ts_status);
+ }
+
+ if (tries3 && finalTSIdx > 2) {
+ update_stats(sc, an, frame_size,
+ ndx3, tries3,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1 - tries2,
+ ds->ds_txstat.ts_status);
+ }
+ }
+}
+
+void
+ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
+{
+ DPRINTF(sc, "%s: %6D isnew %d\n", __func__,
+ an->an_node.ni_macaddr, ":", isnew);
+ if (isnew)
+ ath_rate_ctl_reset(sc, &an->an_node);
+}
+
+/*
+ * Initialize the tables for a node.
+ */
+static void
+ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
+{
+#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_node *an = ATH_NODE(ni);
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ int x, y, srate;
+
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+ sn->static_rate_ndx = -1;
+ if (ic->ic_fixed_rate != -1) {
+ /*
+ * A fixed rate is to be used; ic_fixed_rate is an
+ * index into the supported rate set. Convert this
+ * to the index into the negotiated rate set for
+ * the node. We know the rate is there because the
+ * rate set is checked when the station associates.
+ */
+ const struct ieee80211_rateset *rs =
+ &ic->ic_sup_rates[ic->ic_curmode];
+ int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
+ /* NB: the rate set is assumed sorted */
+ srate = ni->ni_rates.rs_nrates - 1;
+ for (; srate >= 0 && RATE(srate) != r; srate--)
+ ;
+ KASSERT(srate >= 0,
+ ("fixed rate %d not in rate set", ic->ic_fixed_rate));
+ sn->static_rate_ndx = srate;
+ }
+
+ DPRINTF(sc, "%s: %6D size 1600 rate/tt", __func__, ni->ni_macaddr, ":");
+
+ sn->num_rates = ni->ni_rates.rs_nrates;
+ for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+ sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+ sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
+ sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode;
+ sn->rates[x].shortPreambleRateCode =
+ rt->info[sn->rates[x].rix].rateCode |
+ rt->info[sn->rates[x].rix].shortPreamble;
+
+ DPRINTF(sc, " %d/%d", sn->rates[x].rate,
+ calc_usecs_unicast_packet(sc, 1600, sn->rates[x].rix,
+ 0,0));
+ }
+ DPRINTF(sc, "%s\n", "");
+
+ /* set the visible bit-rate to the lowest one available */
+ ni->ni_txrate = 0;
+ sn->num_rates = ni->ni_rates.rs_nrates;
+
+ for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
+ int size = bin_to_size(y);
+ sn->packets_sent[y] = 0;
+ sn->current_sample_ndx[y] = -1;
+ sn->last_sample_ndx[y] = 0;
+
+ for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+ sn->stats[y][x].successive_failures = 0;
+ sn->stats[y][x].tries = 0;
+ sn->stats[y][x].total_packets = 0;
+ sn->stats[y][x].packets_acked = 0;
+ sn->stats[y][x].last_tx = 0;
+
+ sn->stats[y][x].perfect_tx_time =
+ calc_usecs_unicast_packet(sc, size,
+ sn->rates[x].rix,
+ 0, 0);
+ sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time;
+ }
+ }
+#undef RATE
+}
+
+static void
+rate_cb(void *arg, struct ieee80211_node *ni)
+{
+ struct ath_softc *sc = arg;
+
+ ath_rate_newassoc(sc, ATH_NODE(ni), 1);
+}
+
+/*
+ * Reset the rate control state for each 802.11 state transition.
+ */
+void
+ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ if (state == IEEE80211_S_RUN) {
+ if (ic->ic_opmode != IEEE80211_M_STA) {
+ /*
+ * Sync rates for associated stations and neighbors.
+ */
+ ieee80211_iterate_nodes(&ic->ic_sta, rate_cb, sc);
+ }
+ ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1);
+ }
+}
+
+static void
+ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *osc)
+{
+ struct sysctl_ctx_list *ctx = &sc->sysctl_ctx;
+ struct sysctl_oid *tree = sc->sysctl_tree;
+ crit_enter();
+ /* XXX bounds check [0..100] */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "smoothing_rate", CTLFLAG_RW, &osc->ath_smoothing_rate, 0,
+ "rate control: retry threshold to credit rate raise (%%)");
+ /* XXX bounds check [2..100] */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "sample_rate", CTLFLAG_RW, &osc->ath_sample_rate,0,
+ "rate control: # good periods before raising rate");
+ crit_exit();
+}
+
+struct ath_ratectrl *
+ath_rate_attach(struct ath_softc *sc)
+{
+ struct sample_softc *osc;
+
+ DPRINTF(sc, "%s:\n", __func__);
+ osc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (osc == NULL)
+ return NULL;
+ osc->arc.arc_space = sizeof(struct sample_node);
+ osc->ath_smoothing_rate = 95; /* ewma percentage (out of 100) */
+ osc->ath_sample_rate = 10; /* send a different bit-rate 1/X packets */
+ ath_rate_sysctlattach(sc, osc);
+ return &osc->arc;
+}
+
+void
+ath_rate_detach(struct ath_ratectrl *arc)
+{
+ struct sample_softc *osc = (struct sample_softc *) arc;
+
+ free(osc, M_DEVBUF);
+}
+
+/*
+ * Module glue.
+ */
+static int
+sample_modevent(module_t mod __unused, int type, void *unused __unused)
+{
+ switch (type) {
+ case MOD_LOAD:
+ if (bootverbose)
+ printf("ath_rate: version 1.2 <SampleRate bit-rate selection algorithm>\n");
+ return 0;
+ case MOD_UNLOAD:
+ return 0;
+ }
+ return EINVAL;
+}
+
+static moduledata_t sample_mod = {
+ "ath_rate",
+ sample_modevent,
+ 0
+};
+DECLARE_MODULE(ath_rate, sample_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(ath_rate, 1);
+MODULE_DEPEND(ath_rate, ath_hal, 1, 1, 1); /* Atheros HAL */
+MODULE_DEPEND(ath_rate, wlan, 1, 1, 1);
diff -N -u -r src.preview/sys/dev/netif/ath/ath_rate/sample/sample.h src/sys/dev/netif/ath/ath_rate/sample/sample.h
--- src.preview/sys/dev/netif/ath/ath_rate/sample/sample.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/ath_rate/sample/sample.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,250 @@
+/*-
+ * Copyright (c) 2005 John Bicket
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_RATE_SAMPLE_H
+#define _DEV_ATH_RATE_SAMPLE_H
+
+/* per-device state */
+struct sample_softc {
+ struct ath_ratectrl arc; /* base state */
+ int ath_smoothing_rate; /* ewma percentage (out of 100) */
+ int ath_sample_rate; /* send a different bit-rate 1/X packets */
+};
+#define ATH_SOFTC_SAMPLE(sc) ((struct sample_softc *)sc->sc_rc)
+
+struct rate_info {
+ int rate;
+ int rix;
+ int rateCode;
+ int shortPreambleRateCode;
+};
+
+
+struct rate_stats {
+ int successive_failures;
+ int tries;
+ int total_packets;
+ int packets_acked;
+ unsigned perfect_tx_time; /* transmit time for 0 retries */
+ int last_tx;
+};
+
+/*
+ * for now, we track performance for three different packet
+ * size buckets
+ */
+#define NUM_PACKET_SIZE_BINS 3
+static int packet_size_bins[NUM_PACKET_SIZE_BINS] = {250, 1600, 3000};
+
+/* per-node state */
+struct sample_node {
+ int static_rate_ndx;
+ int num_rates;
+
+ struct rate_info rates[IEEE80211_RATE_MAXSIZE];
+
+ struct rate_stats stats[NUM_PACKET_SIZE_BINS][IEEE80211_RATE_MAXSIZE];
+ int last_sample_ndx[NUM_PACKET_SIZE_BINS];
+
+ int current_sample_ndx[NUM_PACKET_SIZE_BINS];
+ int packets_sent[NUM_PACKET_SIZE_BINS];
+
+ int current_rate[NUM_PACKET_SIZE_BINS];
+ int packets_since_switch[NUM_PACKET_SIZE_BINS];
+ unsigned jiffies_since_switch[NUM_PACKET_SIZE_BINS];
+
+ int packets_since_sample[NUM_PACKET_SIZE_BINS];
+ unsigned sample_tt[NUM_PACKET_SIZE_BINS];
+};
+#define ATH_NODE_SAMPLE(an) ((struct sample_node *)&an[1])
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define WIFI_CW_MIN 31
+#define WIFI_CW_MAX 1023
+
+struct ar5212_desc {
+ /*
+ * tx_control_0
+ */
+ u_int32_t frame_len:12;
+ u_int32_t reserved_12_15:4;
+ u_int32_t xmit_power:6;
+ u_int32_t rts_cts_enable:1;
+ u_int32_t veol:1;
+ u_int32_t clear_dest_mask:1;
+ u_int32_t ant_mode_xmit:4;
+ u_int32_t inter_req:1;
+ u_int32_t encrypt_key_valid:1;
+ u_int32_t cts_enable:1;
+
+ /*
+ * tx_control_1
+ */
+ u_int32_t buf_len:12;
+ u_int32_t more:1;
+ u_int32_t encrypt_key_index:7;
+ u_int32_t frame_type:4;
+ u_int32_t no_ack:1;
+ u_int32_t comp_proc:2;
+ u_int32_t comp_iv_len:2;
+ u_int32_t comp_icv_len:2;
+ u_int32_t reserved_31:1;
+
+ /*
+ * tx_control_2
+ */
+ u_int32_t rts_duration:15;
+ u_int32_t duration_update_enable:1;
+ u_int32_t xmit_tries0:4;
+ u_int32_t xmit_tries1:4;
+ u_int32_t xmit_tries2:4;
+ u_int32_t xmit_tries3:4;
+
+ /*
+ * tx_control_3
+ */
+ u_int32_t xmit_rate0:5;
+ u_int32_t xmit_rate1:5;
+ u_int32_t xmit_rate2:5;
+ u_int32_t xmit_rate3:5;
+ u_int32_t rts_cts_rate:5;
+ u_int32_t reserved_25_31:7;
+
+ /*
+ * tx_status_0
+ */
+ u_int32_t frame_xmit_ok:1;
+ u_int32_t excessive_retries:1;
+ u_int32_t fifo_underrun:1;
+ u_int32_t filtered:1;
+ u_int32_t rts_fail_count:4;
+ u_int32_t data_fail_count:4;
+ u_int32_t virt_coll_count:4;
+ u_int32_t send_timestamp:16;
+
+ /*
+ * tx_status_1
+ */
+ u_int32_t done:1;
+ u_int32_t seq_num:12;
+ u_int32_t ack_sig_strength:8;
+ u_int32_t final_ts_index:2;
+ u_int32_t comp_success:1;
+ u_int32_t xmit_antenna:1;
+ u_int32_t reserved_25_31_x:7;
+} __packed;
+
+/*
+ * Calculate the transmit duration of a frame.
+ */
+static unsigned calc_usecs_unicast_packet(struct ath_softc *sc,
+ int length,
+ int rix, int short_retries, int long_retries) {
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+
+ /* pg 205 ieee.802.11.pdf */
+ unsigned t_slot = 20;
+ unsigned t_difs = 50;
+ unsigned t_sifs = 10;
+ struct ieee80211com *ic = &sc->sc_ic;
+ int tt = 0;
+ int x = 0;
+ int cw = WIFI_CW_MIN;
+ int cix = rt->info[rix].controlRate;
+ int rts = 0;
+ int cts = 0;
+
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+
+ if (rt->info[rix].phy == IEEE80211_T_OFDM) {
+ t_slot = 9;
+ t_sifs = 9;
+ t_difs = 28;
+ }
+
+ if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+ rt->info[rix].phy == IEEE80211_T_OFDM) {
+ if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+ rts = 1;
+ else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+ cts = 1;
+
+ cix = rt->info[sc->sc_protrix].controlRate;
+
+ }
+
+ if (length > ic->ic_rtsthreshold) {
+ rts = 1;
+ }
+
+ if (rts || cts) {
+ int ctsrate = rt->info[cix].rateCode;
+ int ctsduration = 0;
+ ctsrate |= rt->info[cix].shortPreamble;
+ if (rts) /* SIFS + CTS */
+ ctsduration += rt->info[cix].spAckDuration;
+
+ ctsduration += ath_hal_computetxtime(sc->sc_ah,
+ rt, length, rix, AH_TRUE);
+
+ if (cts) /* SIFS + ACK */
+ ctsduration += rt->info[cix].spAckDuration;
+
+ tt += (short_retries + 1) * ctsduration;
+ }
+ tt += t_difs;
+ tt += (long_retries+1)*(t_sifs + rt->info[cix].spAckDuration);
+ tt += (long_retries+1)*ath_hal_computetxtime(sc->sc_ah, rt, length,
+ rix, AH_TRUE);
+ for (x = 0; x <= short_retries + long_retries; x++) {
+ cw = MIN(WIFI_CW_MAX, (cw + 1) * 2);
+ tt += (t_slot * cw/2);
+ }
+ return tt;
+}
+#endif /* _DEV_ATH_RATE_SAMPLE_H */
diff -N -u -r src.preview/sys/dev/netif/ath/if_ath.c src/sys/dev/netif/ath/if_ath.c
--- src.preview/sys/dev/netif/ath/if_ath.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/if_ath.c 2005-09-23 11:57:00.000000000 -0400
@@ -0,0 +1,5115 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+ * DragonFly Port - Copyright (c) 2005 Andrew Atrens
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/thread.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/thread2.h>
+
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#ifndef IFQ_SET_MAXLEN
+#include <net/ifq_var.h>
+#endif
+#include <net/if_llc.h>
+
+
+#include <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/ieee80211_ioctl.h>
+#include <netproto/802_11/ieee80211_radiotap.h>
+#include <netproto/802_11/if_wavelan_ieee.h>
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#define AR_DEBUG
+#include "if_athvar.h"
+#include "../../../contrib/dev/ath/ah_desc.h"
+#include "../../../contrib/dev/ath/ah_devid.h"
+
+
+/* unalligned little endian access */
+#define LE_READ_2(p) \
+ ((u_int16_t) \
+ ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8)))
+#define LE_READ_4(p) \
+ ((u_int32_t) \
+ ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \
+ (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)))
+
+enum {
+ ATH_LED_TX,
+ ATH_LED_RX,
+ ATH_LED_POLL,
+};
+
+static void ath_init(void *);
+static void ath_stop_locked(struct ifnet *);
+static void ath_stop(struct ifnet *);
+static void ath_start(struct ifnet *);
+static int ath_reset(struct ifnet *);
+static int ath_media_change(struct ifnet *);
+static void ath_watchdog(struct ifnet *);
+static int ath_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *cr);
+static void ath_fatal_proc(void *, int);
+static void ath_rxorn_proc(void *, int);
+static void ath_bmiss_proc(void *, int);
+static int ath_key_alloc(struct ieee80211com *,
+ const struct ieee80211_key *,
+ ieee80211_keyix *, ieee80211_keyix *);
+static int ath_key_delete(struct ieee80211com *,
+ const struct ieee80211_key *);
+static int ath_key_set(struct ieee80211com *, const struct ieee80211_key *,
+ const u_int8_t mac[IEEE80211_ADDR_LEN]);
+static void ath_key_update_begin(struct ieee80211com *);
+static void ath_key_update_end(struct ieee80211com *);
+static void ath_mode_init(struct ath_softc *);
+static void ath_setslottime(struct ath_softc *);
+static void ath_updateslot(struct ifnet *);
+static int ath_beaconq_setup(struct ath_hal *);
+static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
+static void ath_beacon_setup(struct ath_softc *, struct ath_buf *);
+static void ath_beacon_proc(void *, int);
+static void ath_bstuck_proc(void *, int);
+static void ath_beacon_free(struct ath_softc *);
+static void ath_beacon_config(struct ath_softc *);
+static void ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *, ath_bufhead *);
+static int ath_desc_alloc(struct ath_softc *);
+static void ath_desc_free(struct ath_softc *);
+static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *);
+static void ath_node_free(struct ieee80211_node *);
+static u_int8_t ath_node_getrssi(const struct ieee80211_node *);
+static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
+static void ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
+ struct ieee80211_node *ni,
+ int subtype, int rssi, u_int32_t rstamp);
+static void ath_setdefantenna(struct ath_softc *, u_int);
+static void ath_rx_proc(void *, int);
+static struct ath_txq *ath_txq_setup(struct ath_softc*, int qtype, int subtype);
+static int ath_tx_setup(struct ath_softc *, int, int);
+static int ath_wme_update(struct ieee80211com *);
+static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *);
+static void ath_tx_cleanup(struct ath_softc *);
+static int ath_tx_start(struct ath_softc *, struct ieee80211_node *,
+ struct ath_buf *, struct mbuf *);
+static void ath_tx_proc_q0(void *, int);
+static void ath_tx_proc_q0123(void *, int);
+static void ath_tx_proc(void *, int);
+static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
+static void ath_draintxq(struct ath_softc *);
+static void ath_stoprecv(struct ath_softc *);
+static int ath_startrecv(struct ath_softc *);
+static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *);
+static void ath_next_scan(void *);
+static void ath_calibrate(void *);
+static int ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static void ath_setup_stationkey(struct ieee80211_node *);
+static void ath_newassoc(struct ieee80211_node *, int);
+static int ath_getchannels(struct ath_softc *, u_int cc,
+ HAL_BOOL outdoor, HAL_BOOL xchanmode);
+static void ath_led_event(struct ath_softc *, int);
+static void ath_update_txpow(struct ath_softc *);
+
+static int ath_rate_setup(struct ath_softc *, u_int mode);
+static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);
+
+static void ath_sysctlattach(struct ath_softc *);
+static void ath_bpfattach(struct ath_softc *);
+static void ath_announce(struct ath_softc *);
+
+SYSCTL_DECL(_hw_ath);
+
+/* XXX validate sysctl values */
+
+static int ath_dwelltime = 200; /* 5 channels/second */
+SYSCTL_INT(_hw_ath, OID_AUTO, dwell, CTLFLAG_RW, &ath_dwelltime,
+ 0, "channel dwell time (ms) for AP/station scanning");
+TUNABLE_INT("hw.ath.dwell", &ath_dwelltime);
+
+static int ath_calinterval = 30; /* calibrate every 30 secs */
+SYSCTL_INT(_hw_ath, OID_AUTO, calibrate, CTLFLAG_RW, &ath_calinterval,
+ 0, "chip calibration interval (secs)");
+TUNABLE_INT("hw.ath.calibrate", &ath_calinterval);
+
+static int ath_outdoor = AH_TRUE; /* outdoor operation */
+SYSCTL_INT(_hw_ath, OID_AUTO, outdoor, CTLFLAG_RD, &ath_outdoor,
+ 0, "outdoor operation");
+TUNABLE_INT("hw.ath.outdoor", &ath_outdoor);
+static int ath_xchanmode = AH_TRUE; /* extended channel use */
+SYSCTL_INT(_hw_ath, OID_AUTO, xchanmode, CTLFLAG_RD, &ath_xchanmode,
+ 0, "extended channel mode");
+TUNABLE_INT("hw.ath.xchanmode", &ath_xchanmode);
+static int ath_countrycode = CTRY_DEFAULT; /* country code */
+TUNABLE_INT("hw.ath.countrycode", &ath_countrycode);
+
+static int ath_regdomain = 0; /* regulatory domain */
+TUNABLE_INT("hw.ath.regdomain", &ath_regdomain);
+
+#ifdef AR_DEBUG
+
+static int ath_debug = 0;
+TUNABLE_INT("hw.ath.debug", &ath_debug);
+
+enum {
+ ATH_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
+ ATH_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */
+ ATH_DEBUG_RECV = 0x00000004, /* basic recv operation */
+ ATH_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */
+ ATH_DEBUG_RATE = 0x00000010, /* rate control */
+ ATH_DEBUG_RESET = 0x00000020, /* reset processing */
+ ATH_DEBUG_MODE = 0x00000040, /* mode init/setup */
+ ATH_DEBUG_BEACON = 0x00000080, /* beacon handling */
+ ATH_DEBUG_WATCHDOG = 0x00000100, /* watchdog timeout */
+ ATH_DEBUG_INTR = 0x00001000, /* ISR */
+ ATH_DEBUG_TX_PROC = 0x00002000, /* tx ISR proc */
+ ATH_DEBUG_RX_PROC = 0x00004000, /* rx ISR proc */
+ ATH_DEBUG_BEACON_PROC = 0x00008000, /* beacon ISR proc */
+ ATH_DEBUG_CALIBRATE = 0x00010000, /* periodic calibration */
+ ATH_DEBUG_KEYCACHE = 0x00020000, /* key cache management */
+ ATH_DEBUG_STATE = 0x00040000, /* 802.11 state transitions */
+ ATH_DEBUG_NODE = 0x00080000, /* node management */
+ ATH_DEBUG_LED = 0x00100000, /* led management */
+ ATH_DEBUG_FATAL = 0x80000000, /* fatal errors */
+ ATH_DEBUG_ANY = 0xffffffff
+};
+#define IFF_DUMPPKTS(sc, m) \
+ ((sc->sc_debug & (m)) || \
+ (sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
+
+#if 0
+#define DPRINTF(sc, m, fmt, ...) do { \
+ if (sc->sc_debug & (m)) \
+ printf(fmt, __VA_ARGS__); \
+} while (0)
+#endif
+#define KEYPRINTF(sc, ix, hk, mac) do { \
+ if (sc->sc_debug & ATH_DEBUG_KEYCACHE) \
+ ath_keyprint(__func__, ix, hk, mac); \
+} while (0)
+static void ath_printrxbuf(struct ath_buf *bf, int);
+static void ath_printtxbuf(struct ath_buf *bf, int);
+
+
+#define DPRINTF(_sc,_m,X) if (_sc->sc_debug & _m) printf X
+#else
+#define IFF_DUMPPKTS(sc, m) \
+ ((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
+#define DPRINTF(_m, X)
+#define KEYPRINTF(sc, k, ix, mac)
+#endif
+
+
+int
+ath_attach(u_int16_t devid, struct ath_softc *sc)
+{
+ struct ifnet *ifp;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = NULL;
+ HAL_STATUS status;
+ int error = 0;
+ unsigned i;
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: devid 0x%x\n", __func__, devid));
+
+ ifp = sc->sc_ifp = &sc->sc_if;
+ if (ifp == NULL) {
+ device_printf(sc->sc_dev, "can not if_alloc()\n");
+ error = ENOSPC;
+ goto bad;
+ }
+
+ /* set these up early for if_printf use */
+ if_initname(ifp, device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev));
+
+ ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, &status);
+ if (ah == NULL) {
+ if_printf(ifp, "unable to attach hardware; HAL status %u\n",
+ status);
+ error = ENXIO;
+ goto bad;
+ }
+ if (ah->ah_abi != HAL_ABI_VERSION) {
+ if_printf(ifp, "HAL ABI mismatch detected (0x%x != 0x%x)\n",
+ ah->ah_abi, HAL_ABI_VERSION);
+ error = ENXIO;
+ goto bad;
+ }
+ if_printf(ifp, "mac %d.%d phy %d.%d",
+ ah->ah_macVersion, ah->ah_macRev,
+ ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf);
+ if (ah->ah_analog5GhzRev)
+ printf(" 5ghz radio %d.%d",
+ ah->ah_analog5GhzRev >> 4, ah->ah_analog5GhzRev & 0xf);
+ if (ah->ah_analog2GhzRev)
+ printf(" 2ghz radio %d.%d",
+ ah->ah_analog2GhzRev >> 4, ah->ah_analog2GhzRev & 0xf);
+ printf("\n");
+ sc->sc_ah = ah;
+ sc->sc_invalid = 0; /* ready to go, enable interrupt handling */
+
+ /*
+ * Check if the MAC has multi-rate retry support.
+ * We do this by trying to setup a fake extended
+ * descriptor. MAC's that don't have support will
+ * return false w/o doing anything. MAC's that do
+ * support it will return true w/o doing anything.
+ */
+ sc->sc_mrretry = ath_hal_setupxtxdesc(ah, NULL, 0,0, 0,0, 0,0);
+
+ /*
+ * Check if the device has hardware counters for PHY
+ * errors. If so we need to enable the MIB interrupt
+ * so we can act on stat triggers.
+ */
+ if (ath_hal_hwphycounters(ah))
+ sc->sc_needmib = 1;
+
+ /*
+ * Get the hardware key cache size.
+ */
+ sc->sc_keymax = ath_hal_keycachesize(ah);
+ if (sc->sc_keymax > sizeof(sc->sc_keymap) * NBBY) {
+ if_printf(ifp,
+ "Warning, using only %zu of %u key cache slots\n",
+ sizeof(sc->sc_keymap) * NBBY, sc->sc_keymax);
+ }
+ /*
+ * Reset the key cache since some parts do not
+ * reset the contents on initial power up.
+ */
+ for (i = 0; i < sc->sc_keymax; i++)
+ ath_hal_keyreset(ah, i);
+ /*
+ * Mark key cache slots associated with global keys
+ * as in use. If we knew TKIP was not to be used we
+ * could leave the +32, +64, and +32+64 slots free.
+ * XXX only for splitmic.
+ */
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ setbit(sc->sc_keymap, i);
+ setbit(sc->sc_keymap, i+32);
+ setbit(sc->sc_keymap, i+64);
+ setbit(sc->sc_keymap, i+32+64);
+ }
+
+ /*
+ * Check if the device has hardware counters for PHY
+ * errors. If so we need to enable the MIB interrupt
+ * so we can act on stat triggers.
+ */
+ if (ath_hal_hwphycounters(ah))
+ sc->sc_needmib = 1;
+
+ /*
+ * Collect the channel list using the default country
+ * code and including outdoor channels. The 802.11 layer
+ * is resposible for filtering this list based on settings
+ * like the phy mode.
+ */
+ error = ath_getchannels(sc, ath_countrycode, ath_outdoor, ath_xchanmode);
+ if (error != 0)
+ goto bad;
+ /*
+ * Copy these back; they are set as a side effect
+ * of constructing the channel list.
+ */
+ ath_hal_getregdomain(ah, &ath_regdomain);
+ ath_hal_getcountrycode(ah, &ath_countrycode);
+
+ sysctl_ctx_init(&sc->sysctl_ctx);
+
+ sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+ SYSCTL_STATIC_CHILDREN(_hw),
+ OID_AUTO,
+ device_get_nameunit(sc->sc_dev),
+ CTLFLAG_RD,
+ 0, "");
+
+ /*
+ * Setup rate tables for all potential media types.
+ */
+ ath_rate_setup(sc, IEEE80211_MODE_11A);
+ ath_rate_setup(sc, IEEE80211_MODE_11B);
+ ath_rate_setup(sc, IEEE80211_MODE_11G);
+ ath_rate_setup(sc, IEEE80211_MODE_TURBO_A);
+ ath_rate_setup(sc, IEEE80211_MODE_TURBO_G);
+ /* NB: setup here so ath_rate_update is happy */
+ ath_setcurmode(sc, IEEE80211_MODE_11A);
+
+ /*
+ * Allocate tx+rx descriptors and populate the lists.
+ */
+ error = ath_desc_alloc(sc);
+ if (error != 0) {
+ if_printf(ifp, "failed to allocate descriptors: %d\n", error);
+ goto bad;
+ }
+ callout_init(&sc->sc_scan_ch);
+ callout_init(&sc->sc_cal_ch);
+
+ ATH_TXBUF_LOCK_INIT(sc);
+
+ TASK_INIT(&sc->sc_rxtask, 0, ath_rx_proc, sc);
+ TASK_INIT(&sc->sc_rxorntask, 0, ath_rxorn_proc, sc);
+ TASK_INIT(&sc->sc_fataltask, 0, ath_fatal_proc, sc);
+ TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc);
+ TASK_INIT(&sc->sc_bstucktask, 0, ath_bstuck_proc, sc);
+
+ /*
+ * Allocate hardware transmit queues: one queue for
+ * beacon frames and one data queue for each QoS
+ * priority. Note that the hal handles reseting
+ * these queues at the needed time.
+ *
+ * XXX PS-Poll
+ */
+ sc->sc_bhalq = ath_beaconq_setup(ah);
+ if (sc->sc_bhalq == (u_int) -1) {
+ if_printf(ifp, "unable to setup a beacon xmit queue!\n");
+ error = EIO;
+ goto bad2;
+ }
+ sc->sc_cabq = ath_txq_setup(sc, HAL_TX_QUEUE_CAB, 0);
+ if (sc->sc_cabq == NULL) {
+ if_printf(ifp, "unable to setup CAB xmit queue!\n");
+ error = EIO;
+ goto bad2;
+ }
+ /* NB: insure BK queue is the lowest priority h/w queue */
+ if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) {
+ if_printf(ifp, "unable to setup xmit queue for %s traffic!\n",
+ ieee80211_wme_acnames[WME_AC_BK]);
+ error = EIO;
+ goto bad2;
+ }
+ if (!ath_tx_setup(sc, WME_AC_BE, HAL_WME_AC_BE) ||
+ !ath_tx_setup(sc, WME_AC_VI, HAL_WME_AC_VI) ||
+ !ath_tx_setup(sc, WME_AC_VO, HAL_WME_AC_VO)) {
+ /*
+ * Not enough hardware tx queues to properly do WME;
+ * just punt and assign them all to the same h/w queue.
+ * We could do a better job of this if, for example,
+ * we allocate queues when we switch from station to
+ * AP mode.
+ */
+ if (sc->sc_ac2q[WME_AC_VI] != NULL)
+ ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_VI]);
+ if (sc->sc_ac2q[WME_AC_BE] != NULL)
+ ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_BE]);
+ sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK];
+ sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK];
+ sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK];
+ }
+
+ /*
+ * Special case certain configurations. Note the
+ * CAB queue is handled by these specially so don't
+ * include them when checking the txq setup mask.
+ */
+ switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) {
+ case 0x01:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc);
+ break;
+ case 0x0f:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc);
+ break;
+ default:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc);
+ break;
+ }
+
+ /*
+ * Setup rate control. Some rate control modules
+ * call back to change the anntena state so expose
+ * the necessary entry points.
+ * XXX maybe belongs in struct ath_ratectrl?
+ */
+ sc->sc_setdefantenna = ath_setdefantenna;
+ sc->sc_rc = ath_rate_attach(sc);
+ if (sc->sc_rc == NULL) {
+ error = EIO;
+ goto bad2;
+ }
+
+ sc->sc_blinking = 0;
+ sc->sc_ledstate = 1;
+ sc->sc_ledon = 0; /* low true */
+ sc->sc_ledidle = (2700*hz)/1000; /* 2.7sec */
+ callout_init(&sc->sc_ledtimer);
+ /*
+ * Auto-enable soft led processing for IBM cards and for
+ * 5211 minipci cards. Users can also manually enable/disable
+ * support with a sysctl.
+ */
+ sc->sc_softled = (/*devid == AR5212_DEVID_IBM || devid == AR5211_DEVID*/0);
+ if (sc->sc_softled) {
+ ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
+ ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon);
+ }
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
+ ifp->if_start = ath_start;
+ ifp->if_watchdog = ath_watchdog;
+ ifp->if_ioctl = ath_ioctl;
+ ifp->if_init = (void(*)(void *)) ath_init;
+#ifdef IFQ_SET_MAXLEN
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+#else
+ ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
+#endif
+
+
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+#ifdef IFQ_SET_MAXLEN
+ IFQ_SET_READY(&ifp->if_snd);
+#else
+ ifq_set_ready(&ifp->if_snd);
+#endif
+
+ ic->ic_ifp = ifp;
+ ic->ic_reset = ath_reset;
+ ic->ic_newassoc = ath_newassoc;
+ ic->ic_updateslot = ath_updateslot;
+ ic->ic_wme.wme_update = ath_wme_update;
+ /* XXX not right but it's not used anywhere important */
+ ic->ic_phytype = IEEE80211_T_OFDM;
+ ic->ic_opmode = IEEE80211_M_STA;
+ ic->ic_caps =
+ IEEE80211_C_IBSS /* ibss, nee adhoc, mode */
+ | IEEE80211_C_HOSTAP /* hostap mode */
+ | IEEE80211_C_MONITOR /* monitor mode */
+ | IEEE80211_C_SHPREAMBLE /* short preamble supported */
+ | IEEE80211_C_SHSLOT /* short slot */
+ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */
+ ;
+ /*
+ * Query the hal to figure out h/w crypto support.
+ */
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_WEP))
+ ic->ic_caps |= IEEE80211_C_WEP;
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_OCB))
+ ic->ic_caps |= IEEE80211_C_AES;
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_CCM))
+ ic->ic_caps |= IEEE80211_C_AES_CCM;
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_CKIP))
+ ic->ic_caps |= IEEE80211_C_CKIP;
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_TKIP)) {
+ ic->ic_caps |= IEEE80211_C_TKIP;
+ /*
+ * Check if h/w does the MIC and/or whether the
+ * separate key cache entries are required to
+ * handle both tx+rx MIC keys.
+ */
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC))
+ ic->ic_caps |= IEEE80211_C_TKIPMIC;
+ if (ath_hal_tkipsplit(ah))
+ sc->sc_splitmic = 1;
+ }
+ sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR);
+ sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah);
+ /*
+ * TPC support can be done either with a global cap or
+ * per-packet support. The latter is not available on
+ * all parts. We're a bit pedantic here as all parts
+ * support a global cap.
+ */
+ if (ath_hal_hastpc(ah) || ath_hal_hastxpowlimit(ah))
+ ic->ic_caps |= IEEE80211_C_TXPMGT;
+
+ /*
+ * Mark WME capability only if we have sufficient
+ * hardware queues to do proper priority scheduling.
+ */
+ if (sc->sc_ac2q[WME_AC_BE] != sc->sc_ac2q[WME_AC_BK])
+ ic->ic_caps |= IEEE80211_C_WME;
+ /*
+ * Check for frame bursting capability.
+ */
+ if (ath_hal_hasbursting(ah))
+ ic->ic_caps |= IEEE80211_C_BURST;
+
+ /*
+ * Indicate we need the 802.11 header padded to a
+ * 32-bit boundary for 4-address and QoS frames.
+ */
+ ic->ic_flags |= IEEE80211_F_DATAPAD;
+
+ /*
+ * Query the hal about antenna support.
+ */
+ sc->sc_defant = ath_hal_getdefantenna(ah);
+
+ /*
+ * Not all chips have the VEOL support we want to
+ * use with IBSS beacons; check here for it.
+ */
+ sc->sc_hasveol = ath_hal_hasveol(ah);
+
+ /* get mac address from hardware */
+ ath_hal_getmac(ah, ic->ic_myaddr);
+
+ /* call MI attach routine. */
+ ieee80211_ifattach(ic);
+ /* override default methods */
+ ic->ic_node_alloc = ath_node_alloc;
+ sc->sc_node_free = ic->ic_node_free;
+ ic->ic_node_free = ath_node_free;
+ ic->ic_node_getrssi = ath_node_getrssi;
+ sc->sc_recv_mgmt = ic->ic_recv_mgmt;
+ ic->ic_recv_mgmt = ath_recv_mgmt;
+ sc->sc_newstate = ic->ic_newstate;
+ ic->ic_newstate = ath_newstate;
+ ic->ic_crypto.cs_max_keyix = sc->sc_keymax;
+ ic->ic_crypto.cs_key_alloc = ath_key_alloc;
+ ic->ic_crypto.cs_key_delete = ath_key_delete;
+ ic->ic_crypto.cs_key_set = ath_key_set;
+ ic->ic_crypto.cs_key_update_begin = ath_key_update_begin;
+ ic->ic_crypto.cs_key_update_end = ath_key_update_end;
+ /* complete initialization */
+ ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
+
+ ath_bpfattach(sc);
+ /*
+ * Setup dynamic sysctl's now that country code and
+ * regdomain are available from the hal.
+ */
+ ath_sysctlattach(sc);
+
+ if (bootverbose)
+ ieee80211_announce(ic);
+ ath_announce(sc);
+ return 0;
+bad2:
+ ath_tx_cleanup(sc);
+ ath_desc_free(sc);
+bad:
+ if (ah)
+ ath_hal_detach(ah);
+#if notyet
+ if (ifp != NULL)
+ if_free(ifp);
+#endif
+ sc->sc_invalid = 1;
+ return error;
+}
+
+int
+ath_detach(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
+
+ ath_stop(ifp);
+ bpfdetach(ifp);
+ /*
+ * NB: the order of these is important:
+ * o call the 802.11 layer before detaching the hal to
+ * insure callbacks into the driver to delete global
+ * key cache entries can be handled
+ * o reclaim the tx queue data structures after calling
+ * the 802.11 layer as we'll get called back to reclaim
+ * node state and potentially want to use them
+ * o to cleanup the tx queues the hal is called, so detach
+ * it last
+ * Other than that, it's straightforward...
+ */
+ ieee80211_ifdetach(&sc->sc_ic);
+ ath_rate_detach(sc->sc_rc);
+ ath_desc_free(sc);
+ ath_tx_cleanup(sc);
+ ath_hal_detach(sc->sc_ah);
+#if notyet
+ if_free(ifp);
+#endif
+
+ return 0;
+}
+
+void
+ath_suspend(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
+
+ ath_stop(ifp);
+}
+
+void
+ath_resume(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
+
+ if (ifp->if_flags & IFF_UP) {
+ ath_init(ifp); /* XXX fix me (sc) */
+ if (ifp->if_flags & IFF_RUNNING)
+ ath_start(ifp);
+ }
+ if (sc->sc_softled) {
+ ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin);
+ ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
+ }
+}
+
+void
+ath_shutdown(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
+
+ ath_stop(ifp);
+}
+
+/*
+ * Interrupt handler. Most of the actual processing is deferred.
+ */
+void
+ath_intr(void *arg)
+{
+ struct ath_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_INT status;
+
+ if (sc->sc_invalid) {
+ /*
+ * The hardware is not ready/present, don't touch anything.
+ * Note this can happen early on if the IRQ is shared.
+ */
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: invalid; ignored\n", __func__));
+ return;
+ }
+ if (!ath_hal_intrpend(ah)) /* shared irq, not for us */
+ return;
+ if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) {
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: if_flags 0x%x\n",
+ __func__, ifp->if_flags));
+ ath_hal_getisr(ah, &status); /* clear ISR */
+ ath_hal_intrset(ah, 0); /* disable further intr's */
+ return;
+ }
+ /*
+ * Figure out the reason(s) for the interrupt. Note
+ * that the hal returns a pseudo-ISR that may include
+ * bits we haven't explicitly enabled so we mask the
+ * value to insure we only process bits we requested.
+ */
+ ath_hal_getisr(ah, &status); /* NB: clears ISR too */
+ DPRINTF(sc, ATH_DEBUG_INTR, ("%s: mask 0x%x status 0x%x\n", __func__, sc->sc_imask, status));
+ status &= sc->sc_imask; /* discard unasked for bits */
+ DPRINTF(sc, ATH_DEBUG_INTR, ("%s: masked status 0x%x\n", __func__, status));
+ if (status & HAL_INT_FATAL) {
+ /*
+ * Fatal errors are unrecoverable. Typically
+ * these are caused by DMA errors. Unfortunately
+ * the exact reason is not (presently) returned
+ * by the hal.
+ */
+ sc->sc_stats.ast_hardware++;
+ ath_hal_intrset(ah, 0); /* disable intr's until reset */
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_fataltask);
+ } else if (status & HAL_INT_RXORN) {
+ sc->sc_stats.ast_rxorn++;
+ ath_hal_intrset(ah, 0); /* disable intr's until reset */
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_rxorntask);
+ } else {
+ if (status & HAL_INT_SWBA) {
+ /*
+ * Software beacon alert--time to send a beacon.
+ * Handle beacon transmission directly; deferring
+ * this is too slow to meet timing constraints
+ * under load.
+ */
+ DPRINTF(sc, ATH_DEBUG_BEACON,("SWBA\n"));
+ ath_beacon_proc(sc, 0);
+ }
+ if (status & HAL_INT_RXEOL) {
+ /*
+ * NB: the hardware should re-read the link when
+ * RXE bit is written, but it doesn't work at
+ * least on older hardware revs.
+ */
+ sc->sc_stats.ast_rxeol++;
+ sc->sc_rxlink = NULL;
+ }
+ if (status & HAL_INT_TXURN) {
+ sc->sc_stats.ast_txurn++;
+ /* bump tx trigger level */
+ ath_hal_updatetxtriglevel(ah, AH_TRUE);
+ }
+ if (status & HAL_INT_RX)
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_rxtask);
+ if (status & HAL_INT_TX)
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_txtask);
+ if (status & HAL_INT_BMISS) {
+ sc->sc_stats.ast_bmiss++;
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_bmisstask);
+ }
+ if (status & HAL_INT_MIB) {
+ sc->sc_stats.ast_mib++;
+ /*
+ * Disable interrupts until we service the MIB
+ * interrupt; otherwise it will continue to fire.
+ */
+ ath_hal_intrset(ah, 0);
+ /*
+ * Let the hal handle the event. We assume it will
+ * clear whatever condition caused the interrupt.
+ */
+ ath_hal_mibevent(ah,
+ &ATH_NODE(sc->sc_ic.ic_bss)->an_halstats);
+ ath_hal_intrset(ah, sc->sc_imask);
+ }
+ }
+}
+
+static void
+ath_fatal_proc(void *arg, int pending __unused)
+{
+ struct ath_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ device_printf(sc->sc_dev, "hardware error; resetting\n");
+ ath_reset(ifp);
+}
+
+static void
+ath_rxorn_proc(void *arg, int pending __unused)
+{
+ struct ath_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ device_printf(sc->sc_dev, "rx FIFO overrun; resetting\n");
+ ath_reset(ifp);
+}
+
+static void
+ath_bmiss_proc(void *arg, int pending)
+{
+ struct ath_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: pending %u\n", __func__, pending));
+ KASSERT(ic->ic_opmode == IEEE80211_M_STA,
+ ("unexpect operating mode %u", ic->ic_opmode));
+ if (ic->ic_state == IEEE80211_S_RUN) {
+ /*
+ * Rather than go directly to scan state, try to
+ * reassociate first. If that fails then the state
+ * machine will drop us into scanning after timing
+ * out waiting for a probe response.
+ */
+ ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
+ }
+}
+
+static u_int
+ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ static const u_int modeflags[] = {
+ 0, /* IEEE80211_MODE_AUTO */
+ CHANNEL_A, /* IEEE80211_MODE_11A */
+ CHANNEL_B, /* IEEE80211_MODE_11B */
+ CHANNEL_PUREG, /* IEEE80211_MODE_11G */
+ 0, /* IEEE80211_MODE_FH */
+ CHANNEL_T, /* IEEE80211_MODE_TURBO_A */
+ CHANNEL_108G /* IEEE80211_MODE_TURBO_G */
+ };
+ enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan);
+
+ KASSERT(mode < N(modeflags), ("unexpected phy mode %u", mode));
+ KASSERT(modeflags[mode] != 0, ("mode %u undefined", mode));
+ return modeflags[mode];
+#undef N
+}
+
+static void
+ath_init(void *arg)
+{
+ struct ath_softc *sc = (struct ath_softc *) arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_STATUS status;
+ ATH_LOCK_INFO;
+ crit_enter();
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: if_flags 0x%x\n",
+ __func__, ifp->if_flags));
+
+ ATH_LOCK(sc);
+ /*
+ * Stop anything previously setup. This is safe
+ * whether this is the first time through or not.
+ */
+ ath_stop_locked(ifp);
+
+ /*
+ * The basic interface to setting the hardware in a good
+ * state is ``reset''. On return the hardware is known to
+ * be powered up and with interrupts disabled. This must
+ * be followed by initialization of the appropriate bits
+ * and then setup of the interrupt mask.
+ */
+ sc->sc_curchan.channel = ic->ic_curchan->ic_freq;
+ sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_curchan);
+ if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_FALSE, &status)) {
+ if_printf(ifp, "unable to reset hardware; hal status %u\n",
+ status);
+ goto done;
+ }
+
+ /*
+ * This is needed only to setup initial state
+ * but it's best done after a reset.
+ */
+ ath_update_txpow(sc);
+ /*
+ * Likewise this is set during reset so update
+ * state cached in the driver.
+ */
+ sc->sc_diversity = ath_hal_getdiversity(ah);
+
+ /*
+ * Setup the hardware after reset: the key cache
+ * is filled as needed and the receive engine is
+ * set going. Frame transmit is handled entirely
+ * in the frame output path; there's nothing to do
+ * here except setup the interrupt mask.
+ */
+ if (ath_startrecv(sc) != 0) {
+ if_printf(ifp, "unable to start recv logic\n");
+ goto done;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ sc->sc_imask = HAL_INT_RX | HAL_INT_TX
+ | HAL_INT_RXEOL | HAL_INT_RXORN
+ | HAL_INT_FATAL | HAL_INT_GLOBAL;
+ /*
+ * Enable MIB interrupts when there are hardware phy counters.
+ * Note we only do this (at the moment) for station mode.
+ */
+ if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA)
+ sc->sc_imask |= HAL_INT_MIB;
+ ath_hal_intrset(ah, sc->sc_imask);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ic->ic_state = IEEE80211_S_INIT;
+
+ /*
+ * The hardware should be ready to go now so it's safe
+ * to kick the 802.11 state machine as it's likely to
+ * immediately call back to us to send mgmt frames.
+ */
+ ath_chan_change(sc, ic->ic_curchan);
+ if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+ if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ } else
+ ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+done:
+ ATH_UNLOCK(sc);
+ crit_exit();
+}
+
+static void
+ath_stop_locked(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: invalid %u if_flags 0x%x\n",
+ __func__, sc->sc_invalid, ifp->if_flags));
+
+ ATH_LOCK_ASSERT(sc);
+ if (ifp->if_flags & IFF_RUNNING) {
+ /*
+ * Shutdown the hardware and driver:
+ * reset 802.11 state machine
+ * turn off timers
+ * disable interrupts
+ * turn off the radio
+ * clear transmit machinery
+ * clear receive machinery
+ * drain and release tx queues
+ * reclaim beacon resources
+ * power down hardware
+ *
+ * Note that some of this work is not possible if the
+ * hardware is gone (invalid).
+ */
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+ ifp->if_flags &= ~IFF_RUNNING;
+ ifp->if_timer = 0;
+ if (!sc->sc_invalid) {
+ if (sc->sc_softled) {
+ callout_stop(&sc->sc_ledtimer);
+ ath_hal_gpioset(ah, sc->sc_ledpin,
+ !sc->sc_ledon);
+ sc->sc_blinking = 0;
+ }
+ ath_hal_intrset(ah, 0);
+ }
+ ath_draintxq(sc);
+ if (!sc->sc_invalid) {
+ ath_stoprecv(sc);
+ ath_hal_phydisable(ah);
+ } else
+ sc->sc_rxlink = NULL;
+#ifdef IFQ_PURGE
+ IFQ_PURGE(&ifp->if_snd);
+#else
+ ifq_purge(&ifp->if_snd);
+#endif
+ ath_beacon_free(sc);
+ }
+}
+
+static void
+ath_stop(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+ ATH_LOCK_INFO;
+ crit_enter();
+
+ ATH_LOCK(sc);
+ ath_stop_locked(ifp);
+ if (!sc->sc_invalid) {
+ /*
+ * Set the chip in full sleep mode. Note that we are
+ * careful to do this only when bringing the interface
+ * completely to a stop. When the chip is in this state
+ * it must be carefully woken up or references to
+ * registers in the PCI clock domain may freeze the bus
+ * (and system). This varies by chip and is mostly an
+ * issue with newer parts that go to sleep more quickly.
+ */
+ ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP, 0);
+ }
+ ATH_UNLOCK(sc);
+ crit_exit();
+}
+
+/*
+ * Reset the hardware w/o losing operational state. This is
+ * basically a more efficient way of doing ath_stop, ath_init,
+ * followed by state transitions to the current 802.11
+ * operational state. Used to recover from various errors and
+ * to reset or reload hardware state.
+ */
+static int
+ath_reset(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211_channel *c;
+ HAL_STATUS status;
+
+ /*
+ * Convert to a HAL channel description with the flags
+ * constrained to reflect the current operating mode.
+ */
+ c = ic->ic_curchan;
+ sc->sc_curchan.channel = c->ic_freq;
+ sc->sc_curchan.channelFlags = ath_chan2flags(ic, c);
+
+ ath_hal_intrset(ah, 0); /* disable interrupts */
+ ath_draintxq(sc); /* stop xmit side */
+ ath_stoprecv(sc); /* stop recv side */
+ /* NB: indicate channel change so we do a full reset */
+ if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_TRUE, &status))
+ if_printf(ifp, "%s: unable to reset hardware; hal status %u\n",
+ __func__, status);
+ ath_update_txpow(sc); /* update tx power state */
+ sc->sc_diversity = ath_hal_getdiversity(ah);
+ if (ath_startrecv(sc) != 0) /* restart recv */
+ if_printf(ifp, "%s: unable to start recv logic\n", __func__);
+ /*
+ * We may be doing a reset in response to an ioctl
+ * that changes the channel so update any state that
+ * might change as a result.
+ */
+ ath_chan_change(sc, c);
+ if (ic->ic_state == IEEE80211_S_RUN)
+ ath_beacon_config(sc); /* restart beacons */
+
+ ath_start(ifp); /* restart xmit */
+ return 0;
+}
+
+static void
+ath_start(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni;
+ struct ath_buf *bf;
+ struct mbuf *m;
+ struct ieee80211_frame *wh;
+ struct ether_header *eh;
+ ATH_TXBUF_LOCK_INFO;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid)
+ return;
+ for (;;) {
+ /*
+ * Grab a TX buffer and associated resources.
+ */
+ ATH_TXBUF_LOCK(sc);
+ bf = STAILQ_FIRST(&sc->sc_txbuf);
+ if (bf != NULL)
+ STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ if (bf == NULL) {
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: out of xmit buffers\n",
+ __func__));
+ sc->sc_stats.ast_tx_qstop++;
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ /*
+ * Poll the management queue for frames; they
+ * have priority over normal data frames.
+ */
+ IF_DEQUEUE(&ic->ic_mgtq, m);
+ if (m == NULL) {
+ /*
+ * No data frames go out unless we're associated.
+ */
+ if (ic->ic_state != IEEE80211_S_RUN) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: ignore data packet, state %u\n",
+ __func__, ic->ic_state));
+ sc->sc_stats.ast_tx_discard++;
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ break;
+ }
+#ifdef IFQ_DEQUEUE
+ IFQ_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */
+#else
+ m = ifq_dequeue(&ifp->if_snd); /* XXX: LOCK */
+#endif
+ if (m == NULL) {
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ break;
+ }
+ /*
+ * Find the node for the destination so we can do
+ * things like power save and fast frames aggregation.
+ */
+ if (m->m_len < sizeof(struct ether_header) &&
+ (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
+ ic->ic_stats.is_tx_nobuf++; /* XXX */
+ ni = NULL;
+ goto bad;
+ }
+ eh = mtod(m, struct ether_header *);
+ ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+ if (ni == NULL) {
+ /* NB: ieee80211_find_txnode does stat+msg */
+ m_freem(m);
+ goto bad;
+ }
+ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
+ (m->m_flags & M_PWR_SAV) == 0) {
+ /*
+ * Station in power save mode; pass the frame
+ * to the 802.11 layer and continue. We'll get
+ * the frame back when the time is right.
+ */
+ ieee80211_pwrsave(ic, ni, m);
+ goto reclaim;
+ }
+ /* calculate priority so we can find the tx queue */
+ if (ieee80211_classify(ic, m, ni)) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ ("%s: discard, classification failure\n",
+ __func__));
+ m_freem(m);
+ goto bad;
+ }
+ ifp->if_opackets++;
+ BPF_MTAP(ifp, m);
+ /*
+ * Encapsulate the packet in prep for transmission.
+ */
+ m = ieee80211_encap(ic, m, ni);
+ if (m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: encapsulation failure\n",
+ __func__));
+ sc->sc_stats.ast_tx_encap++;
+ goto bad;
+ }
+ } else {
+ /*
+ * Hack! The referenced node pointer is in the
+ * rcvif field of the packet header. This is
+ * placed there by ieee80211_mgmt_output because
+ * we need to hold the reference with the frame
+ * and there's no other way (other than packet
+ * tags which we consider too expensive to use)
+ * to pass it along.
+ */
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
+
+ wh = mtod(m, struct ieee80211_frame *);
+ if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
+ IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
+ /* fill time stamp */
+ u_int64_t tsf;
+ u_int32_t *tstamp;
+
+ tsf = ath_hal_gettsf64(ah);
+ /* XXX: adjust 100us delay to xmit */
+ tsf += 100;
+ tstamp = (u_int32_t *)&wh[1];
+ tstamp[0] = htole32(tsf & 0xffffffff);
+ tstamp[1] = htole32(tsf >> 32);
+ }
+ sc->sc_stats.ast_tx_mgmt++;
+ }
+
+ if (ath_tx_start(sc, ni, bf, m)) {
+ bad:
+ ifp->if_oerrors++;
+ reclaim:
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ continue;
+ }
+
+ sc->sc_tx_timer = 5;
+ ifp->if_timer = 1;
+ }
+}
+
+static int
+ath_media_change(struct ifnet *ifp)
+{
+#define IS_UP(ifp) \
+ ((ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING))
+ int error;
+
+ error = ieee80211_media_change(ifp);
+ if (error == ENETRESET) {
+ if (IS_UP(ifp))
+ ath_init(ifp->if_softc); /* XXX lose error */
+ error = 0;
+ }
+ return error;
+#undef IS_UP
+}
+
+#ifdef AR_DEBUG
+static void
+ath_keyprint(const char *tag, u_int ix,
+ const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ static const char *ciphers[] = {
+ "WEP",
+ "AES-OCB",
+ "AES-CCM",
+ "CKIP",
+ "TKIP",
+ "CLR",
+ };
+ size_t i, n;
+
+ printf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]);
+ for (i = 0, n = hk->kv_len; i < n; i++)
+ printf("%02x", hk->kv_val[i]);
+ printf(" mac %6D", (mac), ":");
+ if (hk->kv_type == HAL_CIPHER_TKIP) {
+ printf(" mic ");
+ for (i = 0; i < sizeof(hk->kv_mic); i++)
+ printf("%02x", hk->kv_mic[i]);
+ }
+ printf("\n");
+}
+#endif
+
+/*
+ * Set a TKIP key into the hardware. This handles the
+ * potential distribution of key state to multiple key
+ * cache slots for TKIP.
+ */
+static int
+ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
+ HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+#define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
+ static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
+ struct ath_hal *ah = sc->sc_ah;
+
+ KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP,
+ ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher));
+ KASSERT(sc->sc_splitmic, ("key cache !split"));
+ if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
+ /*
+ * TX key goes at first index, RX key at the rx index.
+ * The hal handles the MIC keys at index+64.
+ */
+ memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic));
+ KEYPRINTF(sc, k->wk_keyix, hk, zerobssid);
+ if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid))
+ return 0;
+
+ memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
+ KEYPRINTF(sc, k->wk_keyix+32, hk, mac);
+ /* XXX delete tx key on failure? */
+ return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac);
+ } else if (k->wk_flags & IEEE80211_KEY_XR) {
+ /*
+ * TX/RX key goes at first index.
+ * The hal handles the MIC keys are index+64.
+ */
+ memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ?
+ k->wk_txmic : k->wk_rxmic, sizeof(hk->kv_mic));
+ KEYPRINTF(sc, k->wk_keyix, hk, mac);
+ return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
+ }
+ return 0;
+#undef IEEE80211_KEY_XR
+}
+
+/*
+ * Set a net80211 key into the hardware. This handles the
+ * potential distribution of key state to multiple key
+ * cache slots for TKIP with hardware MIC support.
+ */
+static int
+ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k,
+ const u_int8_t mac0[IEEE80211_ADDR_LEN],
+ struct ieee80211_node *bss)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ static const u_int8_t ciphermap[] = {
+ HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */
+ HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */
+ HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */
+ HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */
+ (u_int8_t) -1, /* 4 is not allocated */
+ HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */
+ HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */
+ };
+ struct ath_hal *ah = sc->sc_ah;
+ const struct ieee80211_cipher *cip = k->wk_cipher;
+ u_int8_t gmac[IEEE80211_ADDR_LEN];
+ const u_int8_t *mac;
+ HAL_KEYVAL hk;
+
+ memset(&hk, 0, sizeof(hk));
+ /*
+ * Software crypto uses a "clear key" so non-crypto
+ * state kept in the key cache are maintained and
+ * so that rx frames have an entry to match.
+ */
+ if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
+ KASSERT(cip->ic_cipher < N(ciphermap),
+ ("invalid cipher type %u", cip->ic_cipher));
+ hk.kv_type = ciphermap[cip->ic_cipher];
+ hk.kv_len = k->wk_keylen;
+ memcpy(hk.kv_val, k->wk_key, k->wk_keylen);
+ } else
+ hk.kv_type = HAL_CIPHER_CLR;
+
+ if ((k->wk_flags & IEEE80211_KEY_GROUP) && sc->sc_mcastkey) {
+ /*
+ * Group keys on hardware that supports multicast frame
+ * key search use a mac that is the sender's address with
+ * the high bit set instead of the app-specified address.
+ */
+ IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr);
+ gmac[0] |= 0x80;
+ mac = gmac;
+ } else
+ mac = mac0;
+
+ if (hk.kv_type == HAL_CIPHER_TKIP &&
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
+ sc->sc_splitmic) {
+ return ath_keyset_tkip(sc, k, &hk, mac);
+ } else {
+ KEYPRINTF(sc, k->wk_keyix, &hk, mac);
+ return ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
+ }
+#undef N
+}
+
+/*
+ * Allocate tx/rx key slots for TKIP. We allocate two slots for
+ * each key, one for decrypt/encrypt and the other for the MIC.
+ */
+static u_int16_t
+key_alloc_2pair(struct ath_softc *sc,
+ ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ u_int i, keyix;
+
+ KASSERT(sc->sc_splitmic, ("key cache !split"));
+ /* XXX could optimize */
+ for (i = 0; i < N(sc->sc_keymap)/4; i++) {
+ u_int8_t b = sc->sc_keymap[i];
+ if (b != 0xff) {
+ /*
+ * One or more slots in this byte are free.
+ */
+ keyix = i*NBBY;
+ while (b & 1) {
+ again:
+ keyix++;
+ b >>= 1;
+ }
+ /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
+ if (isset(sc->sc_keymap, keyix+32) ||
+ isset(sc->sc_keymap, keyix+64) ||
+ isset(sc->sc_keymap, keyix+32+64)) {
+ /* full pair unavailable */
+ /* XXX statistic */
+ if (keyix == (i+1)*NBBY) {
+ /* no slots were appropriate, advance */
+ continue;
+ }
+ goto again;
+ }
+ setbit(sc->sc_keymap, keyix);
+ setbit(sc->sc_keymap, keyix+64);
+ setbit(sc->sc_keymap, keyix+32);
+ setbit(sc->sc_keymap, keyix+32+64);
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE,
+ ("%s: key pair %u,%u %u,%u\n",
+ __func__, keyix, keyix+64,
+ keyix+32, keyix+32+64));
+ *txkeyix = keyix;
+ *rxkeyix = keyix+32;
+ return 1;
+ }
+ }
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE, ("%s: out of pair space\n", __func__));
+ return 0;
+#undef N
+}
+
+/*
+ * Allocate a single key cache slot.
+ */
+static int
+key_alloc_single(struct ath_softc *sc,
+ ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ u_int i, keyix;
+
+ /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
+ for (i = 0; i < N(sc->sc_keymap); i++) {
+ u_int8_t b = sc->sc_keymap[i];
+ if (b != 0xff) {
+ /*
+ * One or more slots are free.
+ */
+ keyix = i*NBBY;
+ while (b & 1)
+ keyix++, b >>= 1;
+ setbit(sc->sc_keymap, keyix);
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE, ("%s: key %u\n",
+ __func__, keyix));
+ *txkeyix = *rxkeyix = keyix;
+ return 1;
+ }
+ }
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE, ("%s: out of space\n", __func__));
+ return 0;
+#undef N
+}
+
+/*
+ * Allocate one or more key cache slots for a uniacst key. The
+ * key itself is needed only to identify the cipher. For hardware
+ * TKIP with split cipher+MIC keys we allocate two key cache slot
+ * pairs so that we can setup separate TX and RX MIC keys. Note
+ * that the MIC key for a TKIP key at slot i is assumed by the
+ * hardware to be at slot i+64. This limits TKIP keys to the first
+ * 64 entries.
+ */
+static int
+ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
+ ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+
+ /*
+ * Group key allocation must be handled specially for
+ * parts that do not support multicast key cache search
+ * functionality. For those parts the key id must match
+ * the h/w key index so lookups find the right key. On
+ * parts w/ the key search facility we install the sender's
+ * mac address (with the high bit set) and let the hardware
+ * find the key w/o using the key id. This is preferred as
+ * it permits us to support multiple users for adhoc and/or
+ * multi-station operation.
+ */
+ if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) {
+ if (!(&ic->ic_nw_keys[0] <= k &&
+ k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
+ /* should not happen */
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE,
+ ("%s: bogus group key\n", __func__));
+ return 0;
+ }
+ /*
+ * XXX we pre-allocate the global keys so
+ * have no way to check if they've already been allocated.
+ */
+ *keyix = *rxkeyix = k - ic->ic_nw_keys;
+ return 1;
+ }
+
+ /*
+ * We allocate two pair for TKIP when using the h/w to do
+ * the MIC. For everything else, including software crypto,
+ * we allocate a single entry. Note that s/w crypto requires
+ * a pass-through slot on the 5211 and 5212. The 5210 does
+ * not support pass-through cache entries and we map all
+ * those requests to slot 0.
+ */
+ if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
+ return key_alloc_single(sc, keyix, rxkeyix);
+ } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) {
+ return key_alloc_2pair(sc, keyix, rxkeyix);
+ } else {
+ return key_alloc_single(sc, keyix, rxkeyix);
+ }
+}
+
+/*
+ * Delete an entry in the key cache allocated by ath_key_alloc.
+ */
+static int
+ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ const struct ieee80211_cipher *cip = k->wk_cipher;
+ u_int keyix = k->wk_keyix;
+
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE, ("%s: delete key %u\n", __func__, keyix));
+
+ ath_hal_keyreset(ah, keyix);
+ /*
+ * Handle split tx/rx keying required for TKIP with h/w MIC.
+ */
+ if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic)
+ ath_hal_keyreset(ah, keyix+32); /* RX key */
+ if (keyix >= IEEE80211_WEP_NKID) {
+ /*
+ * Don't touch keymap entries for global keys so
+ * they are never considered for dynamic allocation.
+ */
+ clrbit(sc->sc_keymap, keyix);
+ if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
+ sc->sc_splitmic) {
+ clrbit(sc->sc_keymap, keyix+64); /* TX key MIC */
+ clrbit(sc->sc_keymap, keyix+32); /* RX key */
+ clrbit(sc->sc_keymap, keyix+32+64); /* RX key MIC */
+ }
+ }
+ return 1;
+}
+
+/*
+ * Set the key cache contents for the specified key. Key cache
+ * slot(s) must already have been allocated by ath_key_alloc.
+ */
+static int
+ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
+ const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+
+ return ath_keyset(sc, k, mac, ic->ic_bss);
+}
+
+#define IF_LOCK(x)
+#define IF_UNLOCK(x)
+/*
+ * Block/unblock tx+rx processing while a key change is done.
+ * We assume the caller serializes key management operations
+ * so we only need to worry about synchronization with other
+ * uses that originate in the driver.
+ */
+static void
+ath_key_update_begin(struct ieee80211com *ic __unused)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE, ("%s:\n", __func__));
+#if 0
+ tasklet_disable(&sc->sc_rxtq);
+ IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */
+#endif
+}
+
+static void
+ath_key_update_end(struct ieee80211com *ic __unused)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE, ("%s:\n", __func__));
+#if 0
+ IF_UNLOCK(&ifp->if_snd);
+ tasklet_enable(&sc->sc_rxtq);
+#endif
+}
+
+/*
+ * Calculate the receive filter according to the
+ * operating mode and state:
+ *
+ * o always accept unicast, broadcast, and multicast traffic
+ * o maintain current state of phy error reception (the hal
+ * may enable phy error frames for noise immunity work)
+ * o probe request frames are accepted only when operating in
+ * hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ * - when operating in adhoc mode so the 802.11 layer creates
+ * node table entries for peers,
+ * - when operating in station mode for collecting rssi data when
+ * the station is otherwise quiet, or
+ * - when scanning
+ */
+static u_int32_t
+ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ifnet *ifp = sc->sc_ifp;
+ u_int32_t rfilt;
+
+ rfilt = (ath_hal_getrxfilter(ah) & HAL_RX_FILTER_PHYERR)
+ | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
+ if (ic->ic_opmode != IEEE80211_M_STA)
+ rfilt |= HAL_RX_FILTER_PROBEREQ;
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
+ (ifp->if_flags & IFF_PROMISC))
+ rfilt |= HAL_RX_FILTER_PROM;
+ if (ic->ic_opmode == IEEE80211_M_STA ||
+ ic->ic_opmode == IEEE80211_M_IBSS ||
+ state == IEEE80211_S_SCAN)
+ rfilt |= HAL_RX_FILTER_BEACON;
+ return rfilt;
+}
+
+static void
+ath_mode_init(struct ath_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ifnet *ifp = sc->sc_ifp;
+ u_int32_t rfilt, mfilt[2], val;
+ u_int8_t pos;
+ struct ifmultiaddr *ifma;
+
+ /* configure rx filter */
+ rfilt = ath_calcrxfilter(sc, ic->ic_state);
+ ath_hal_setrxfilter(ah, rfilt);
+
+ /* configure operational mode */
+ ath_hal_setopmode(ah);
+
+ /*
+ * Handle any link-level address change. Note that we only
+ * need to force ic_myaddr; any other addresses are handled
+ * as a byproduct of the ifnet code marking the interface
+ * down then up.
+ *
+ * XXX should get from lladdr instead of arpcom but that's more work
+ */
+#ifndef IFP2AC
+#define IFP2AC(ifp) ((struct arpcom *)(ifp))
+#endif
+ IEEE80211_ADDR_COPY(ic->ic_myaddr, IFP2AC(ifp)->ac_enaddr);
+
+ ath_hal_setmac(ah, ic->ic_myaddr);
+
+ /* calculate and install multicast filter */
+ if ((ifp->if_flags & IFF_ALLMULTI) == 0) {
+ mfilt[0] = mfilt[1] = 0;
+ /* XXX ADDR_LOCK */
+ LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ caddr_t dl;
+
+ /* calculate XOR of eight 6bit values */
+ dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
+ val = LE_READ_4(dl + 0);
+ pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+ val = LE_READ_4(dl + 3);
+ pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+ pos &= 0x3f;
+ mfilt[pos / 32] |= (1 << (pos % 32));
+ }
+ /* IF_ADDR_UNLOCK(ifp); XXX */
+ } else {
+ mfilt[0] = mfilt[1] = ~0;
+ }
+ ath_hal_setmcastfilter(ah, mfilt[0], mfilt[1]);
+ DPRINTF(sc, ATH_DEBUG_MODE, ("%s: RX filter 0x%x, MC filter %08x:%08x\n",
+ __func__, rfilt, mfilt[0], mfilt[1]));
+}
+
+static void
+ath_mbuf_load_cb(void *arg, bus_dma_segment_t *seg, int nseg, bus_size_t mapsize, int error __unused)
+{
+ struct ath_buf *bf = arg;
+
+ KASSERT(nseg <= ATH_MAX_SCATTER,
+ ("ath_mbuf_load_cb: too many DMA segments %u", nseg));
+ bf->bf_mapsize = mapsize;
+ bf->bf_nseg = nseg;
+ bcopy(seg, bf->bf_segs, nseg * sizeof (seg[0]));
+}
+
+/*
+ * Set the slot time based on the current setting.
+ */
+static void
+ath_setslottime(struct ath_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+
+ if (ic->ic_flags & IEEE80211_F_SHSLOT)
+ ath_hal_setslottime(ah, HAL_SLOT_TIME_9);
+ else
+ ath_hal_setslottime(ah, HAL_SLOT_TIME_20);
+ sc->sc_updateslot = OK;
+}
+
+/*
+ * Callback from the 802.11 layer to update the
+ * slot time based on the current setting.
+ */
+static void
+ath_updateslot(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ /*
+ * When not coordinating the BSS, change the hardware
+ * immediately. For other operation we defer the change
+ * until beacon updates have propagated to the stations.
+ */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+ sc->sc_updateslot = UPDATE;
+ else
+ ath_setslottime(sc);
+}
+
+/*
+ * Setup a h/w transmit queue for beacons.
+ */
+static int
+ath_beaconq_setup(struct ath_hal *ah)
+{
+ HAL_TXQ_INFO qi;
+
+ memset(&qi, 0, sizeof(qi));
+ qi.tqi_aifs = HAL_TXQ_USEDEFAULT;
+ qi.tqi_cwmin = HAL_TXQ_USEDEFAULT;
+ qi.tqi_cwmax = HAL_TXQ_USEDEFAULT;
+ /* NB: for dynamic turbo, don't enable any other interrupts */
+ qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
+ return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi);
+}
+
+/*
+ * Setup the transmit queue parameters for the beacon queue.
+ */
+static int
+ath_beaconq_config(struct ath_softc *sc)
+{
+#define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1)
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_TXQ_INFO qi;
+
+ ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi);
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ /*
+ * Always burst out beacon and CAB traffic.
+ */
+ qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT;
+ qi.tqi_cwmin = ATH_BEACON_CWMIN_DEFAULT;
+ qi.tqi_cwmax = ATH_BEACON_CWMAX_DEFAULT;
+ } else {
+ struct wmeParams *wmep =
+ &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE];
+ /*
+ * Adhoc mode; important thing is to use 2x cwmin.
+ */
+ qi.tqi_aifs = wmep->wmep_aifsn;
+ qi.tqi_cwmin = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
+ qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
+ }
+
+ if (!ath_hal_settxqueueprops(ah, sc->sc_bhalq, &qi)) {
+ device_printf(sc->sc_dev, "unable to update parameters for "
+ "beacon hardware queue!\n");
+ return 0;
+ } else {
+ ath_hal_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */
+ return 1;
+ }
+#undef ATH_EXPONENT_TO_VALUE
+}
+
+/*
+ * Allocate and setup an initial beacon frame.
+ */
+static int
+ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_buf *bf;
+ struct mbuf *m;
+ int error;
+
+ bf = STAILQ_FIRST(&sc->sc_bbuf);
+ if (bf == NULL) {
+ DPRINTF(sc, ATH_DEBUG_BEACON, ("%s: no dma buffers\n", __func__));
+ sc->sc_stats.ast_be_nombuf++; /* XXX */
+ return ENOMEM; /* XXX */
+ }
+ /*
+ * NB: the beacon data buffer must be 32-bit aligned;
+ * we assume the mbuf routines will return us something
+ * with this alignment (perhaps should assert).
+ */
+ m = ieee80211_beacon_alloc(ic, ni, &sc->sc_boff);
+ if (m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_BEACON, ("%s: cannot get mbuf\n",
+ __func__));
+ sc->sc_stats.ast_be_nombuf++;
+ return ENOMEM;
+ }
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m,
+ ath_mbuf_load_cb, bf,
+ BUS_DMA_NOWAIT);
+ if (error == 0) {
+ bf->bf_m = m;
+ bf->bf_node = ieee80211_ref_node(ni);
+ } else {
+ m_freem(m);
+ }
+ return error;
+}
+
+/*
+ * Setup the beacon frame for transmit.
+ */
+static void
+ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
+{
+#define USE_SHPREAMBLE(_ic) \
+ (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\
+ == IEEE80211_F_SHPREAMBLE)
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ieee80211com *ic = ni->ni_ic;
+ struct mbuf *m = bf->bf_m;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_desc *ds;
+ int flags, antenna;
+ u_int8_t rate;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON, ("%s: m %p len %u\n",
+ __func__, m, m->m_len));
+
+ /* setup descriptors */
+ ds = bf->bf_desc;
+
+ flags = HAL_TXDESC_NOACK;
+ if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) {
+ ds->ds_link = bf->bf_daddr; /* self-linked */
+ flags |= HAL_TXDESC_VEOL;
+ /*
+ * Let hardware handle antenna switching.
+ */
+ antenna = sc->sc_txantenna;
+ } else {
+ ds->ds_link = 0;
+ /*
+ * Switch antenna every 4 beacons.
+ * XXX assumes two antenna
+ */
+ antenna = (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1);
+ }
+
+ KASSERT(bf->bf_nseg == 1,
+ ("multi-segment beacon frame; nseg %u", bf->bf_nseg));
+ ds->ds_data = bf->bf_segs[0].ds_addr;
+ /*
+ * Calculate rate code.
+ * XXX everything at min xmit rate
+ */
+ if (USE_SHPREAMBLE(ic))
+ rate = an ? an->an_tx_mgtratesp
+ : sc->sc_currates->info[0].shortPreamble;
+ else
+ rate = an ? an->an_tx_mgtrate
+ : sc->sc_currates->info[0].rateCode;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,("Beacon rate %d\n", rate));
+
+ if (ic->ic_rawbpf)
+ bpf_mtap(ic->ic_rawbpf, m);
+ if (sc->sc_drvbpf) {
+ sc->sc_tx_th.wt_flags = 0;
+ if (USE_SHPREAMBLE(ic))
+ sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+ sc->sc_tx_th.wt_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
+ sc->sc_tx_th.wt_txpower = sc->tx_power; /* XXX */
+ sc->sc_tx_th.wt_antenna = antenna;
+ bpf_ptap(sc->sc_drvbpf, m, &sc->sc_tx_th, sc->sc_tx_th_len);
+ }
+
+ ath_hal_setuptxdesc(ah, ds
+ , m->m_len + IEEE80211_CRC_LEN /* frame length */
+ , sizeof(struct ieee80211_frame)/* header length */
+ , HAL_PKT_TYPE_BEACON /* Atheros packet type */
+ , ni->ni_txpower /* txpower XXX */
+ , rate, 1 /* series 0 rate/tries */
+ , HAL_TXKEYIX_INVALID /* no encryption */
+ , antenna /* antenna mode */
+ , flags /* no ack, veol for beacons */
+ , 0 /* rts/cts rate */
+ , 0 /* rts/cts duration */
+ );
+ /* NB: beacon's BufLen must be a multiple of 4 bytes */
+ ath_hal_filltxdesc(ah, ds
+ , roundup(m->m_len, 4) /* buffer length */
+ , AH_TRUE /* first segment */
+ , AH_TRUE /* last segment */
+ , ds /* first descriptor */
+ );
+#undef USE_SHPREAMBLE
+}
+
+/*
+ * Transmit a beacon frame at SWBA. Dynamic updates to the
+ * frame contents are done as needed and the slot time is
+ * also adjusted based on current state.
+ */
+static void
+ath_beacon_proc(void *arg, int pending)
+{
+ struct ath_softc *sc = arg;
+ struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf);
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_hal *ah = sc->sc_ah;
+ struct mbuf *m;
+ int ncabq, error, otherant;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON_PROC, ("%s: pending %u\n",
+ __func__, pending));
+
+ if (ic->ic_opmode == IEEE80211_M_STA ||
+ ic->ic_opmode == IEEE80211_M_MONITOR ||
+ bf == NULL || bf->bf_m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_ANY, ("%s: ic_flags=%x bf=%p bf_m=%p\n",
+ __func__, ic->ic_flags, bf, bf ? bf->bf_m : NULL));
+ return;
+ }
+ /*
+ * Check if the previous beacon has gone out. If
+ * not don't don't try to post another, skip this
+ * period and wait for the next. Missed beacons
+ * indicate a problem and should not occur. If we
+ * miss too many consecutive beacons reset the device.
+ */
+ if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
+ sc->sc_bmisscount++;
+ DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
+ ("%s: missed %u consecutive beacons\n",
+ __func__, sc->sc_bmisscount));
+ if (sc->sc_bmisscount > 3) /* NB: 3 is a guess */
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_bstucktask);
+ return;
+ }
+ if (sc->sc_bmisscount != 0) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ ("%s: resume beacon xmit after %u misses\n",
+ __func__, sc->sc_bmisscount));
+ sc->sc_bmisscount = 0;
+ }
+
+ /*
+ * Update dynamic beacon contents. If this returns
+ * non-zero then we need to remap the memory because
+ * the beacon frame changed size (probably because
+ * of the TIM bitmap).
+ */
+ m = bf->bf_m;
+ ncabq = ath_hal_numtxpending(ah, sc->sc_cabq->axq_qnum);
+ if (ieee80211_beacon_update(ic, bf->bf_node, &sc->sc_boff, m, ncabq)) {
+ /* XXX too conservative? */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m,
+ ath_mbuf_load_cb, bf,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(ic->ic_ifp,
+ "%s: bus_dmamap_load_mbuf failed, error %u\n",
+ __func__, error);
+ return;
+ }
+ }
+
+ /*
+ * Handle slot time change when a non-ERP station joins/leaves
+ * an 11g network. The 802.11 layer notifies us via callback,
+ * we mark updateslot, then wait one beacon before effecting
+ * the change. This gives associated stations at least one
+ * beacon interval to note the state change.
+ */
+ /* XXX locking */
+ if (sc->sc_updateslot == UPDATE)
+ sc->sc_updateslot = COMMIT; /* commit next beacon */
+ else if (sc->sc_updateslot == COMMIT)
+ ath_setslottime(sc); /* commit change to h/w */
+
+ /*
+ * Check recent per-antenna transmit statistics and flip
+ * the default antenna if noticeably more frames went out
+ * on the non-default antenna.
+ * XXX assumes 2 anntenae
+ */
+ otherant = sc->sc_defant & 1 ? 2 : 1;
+ if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
+ ath_setdefantenna(sc, otherant);
+ sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
+
+ /*
+ * Construct tx descriptor.
+ */
+ ath_beacon_setup(sc, bf);
+
+ /*
+ * Stop any current dma and put the new frame on the queue.
+ * This should never fail since we check above that no frames
+ * are still pending on the queue.
+ */
+ if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: beacon queue %u did not stop?\n",
+ __func__, sc->sc_bhalq));
+ }
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Enable the CAB queue before the beacon queue to
+ * insure cab frames are triggered by this beacon.
+ */
+ if (sc->sc_boff.bo_tim[4] & 1) /* NB: only at DTIM */
+ ath_hal_txstart(ah, sc->sc_cabq->axq_qnum);
+ ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
+ ath_hal_txstart(ah, sc->sc_bhalq);
+ DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
+ ("%s: TXDP[%u] = %p (%p)\n", __func__,
+ sc->sc_bhalq, (caddr_t)bf->bf_daddr, bf->bf_desc));
+
+ sc->sc_stats.ast_be_xmit++;
+}
+
+/*
+ * Reset the hardware after detecting beacons have stopped.
+ */
+static void
+ath_bstuck_proc(void *arg, int pending __unused)
+{
+ struct ath_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n",
+ sc->sc_bmisscount);
+ ath_reset(ifp);
+}
+
+/*
+ * Reclaim beacon resources.
+ */
+static void
+ath_beacon_free(struct ath_softc *sc)
+{
+ struct ath_buf *bf;
+
+ STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) {
+ if (bf->bf_m != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_node != NULL) {
+ ieee80211_free_node(bf->bf_node);
+ bf->bf_node = NULL;
+ }
+ }
+}
+
+/*
+ * Configure the beacon and sleep timers.
+ *
+ * When operating as an AP this resets the TSF and sets
+ * up the hardware to notify us when we need to issue beacons.
+ *
+ * When operating in station mode this sets up the beacon
+ * timers according to the timestamp of the last received
+ * beacon and the current TSF, configures PCF and DTIM
+ * handling, programs the sleep registers so the hardware
+ * will wakeup in time to receive beacons, and configures
+ * the beacon miss handling so we'll receive a BMISS
+ * interrupt when we stop seeing beacons from the AP
+ * we've associated with.
+ */
+static void
+ath_beacon_config(struct ath_softc *sc)
+{
+#define TSF_TO_TU(_h,_l) (((_h) << 22) | ((_l) >> 10))
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni = ic->ic_bss;
+ u_int32_t nexttbtt, intval;
+
+ /* 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));
+ /* NB: the beacon interval is kept internally in TU's */
+ intval = ni->ni_intval & HAL_BEACON_PERIOD;
+ if (nexttbtt == 0) /* e.g. for ap mode */
+ nexttbtt = intval;
+ else if (intval) /* NB: can be 0 for monitor mode */
+ nexttbtt = roundup(nexttbtt, intval);
+ DPRINTF(sc, ATH_DEBUG_BEACON, ("%s: nexttbtt %u intval %u (%u)\n",
+ __func__, nexttbtt, intval, ni->ni_intval));
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ HAL_BEACON_STATE bs;
+ u_int64_t tsf;
+ u_int32_t tsftu;
+ int dtimperiod, dtimcount;
+ int cfpperiod, cfpcount;
+
+ /*
+ * Setup dtim and cfp parameters according to
+ * last beacon we received (which may be none).
+ */
+ dtimperiod = ni->ni_dtim_period;
+ if (dtimperiod <= 0) /* NB: 0 if not known */
+ dtimperiod = 1;
+ dtimcount = ni->ni_dtim_count;
+ if (dtimcount >= dtimperiod) /* NB: sanity check */
+ dtimcount = 0; /* XXX? */
+ cfpperiod = 1; /* NB: no PCF support yet */
+ cfpcount = 0;
+#define FUDGE 2
+ /*
+ * Pull nexttbtt forward to reflect the current
+ * TSF and calculate dtim+cfp state for the result.
+ */
+ tsf = ath_hal_gettsf64(ah);
+ tsftu = TSF_TO_TU((u_int32_t)(tsf>>32), (u_int32_t)tsf) + FUDGE;
+ do {
+ nexttbtt += intval;
+ if (--dtimcount < 0) {
+ dtimcount = dtimperiod - 1;
+ if (--cfpcount < 0)
+ cfpcount = cfpperiod - 1;
+ }
+ } while (nexttbtt < tsftu);
+#undef FUDGE
+ memset(&bs, 0, sizeof(bs));
+ bs.bs_intval = intval;
+ bs.bs_nexttbtt = nexttbtt;
+ bs.bs_dtimperiod = dtimperiod*intval;
+ bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
+ bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
+ bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
+ bs.bs_cfpmaxduration = 0;
+#if 0
+ /*
+ * The 802.11 layer records the offset to the DTIM
+ * bitmap while receiving beacons; use it here to
+ * enable h/w detection of our AID being marked in
+ * the bitmap vector (to indicate frames for us are
+ * pending at the AP).
+ * XXX do DTIM handling in s/w to WAR old h/w bugs
+ * XXX enable based on h/w rev for newer chips
+ */
+ bs.bs_timoffset = ni->ni_timoff;
+#endif
+ /*
+ * Calculate the number of consecutive beacons to miss
+ * before taking a BMISS interrupt. The configuration
+ * is specified in ms, so we need to convert that to
+ * TU's and then calculate based on the beacon interval.
+ * Note that we clamp the result to at most 10 beacons.
+ */
+ bs.bs_bmissthreshold = howmany(ic->ic_bmisstimeout, intval);
+ if (bs.bs_bmissthreshold > 10)
+ bs.bs_bmissthreshold = 10;
+ else if (bs.bs_bmissthreshold <= 0)
+ bs.bs_bmissthreshold = 1;
+
+ /*
+ * Calculate sleep duration. The configuration is
+ * given in ms. We insure a multiple of the beacon
+ * period is used. Also, if the sleep duration is
+ * greater than the DTIM period then it makes senses
+ * to make it a multiple of that.
+ *
+ * XXX fixed at 100ms
+ */
+ bs.bs_sleepduration =
+ roundup(IEEE80211_MS_TO_TU(100), bs.bs_intval);
+ if (bs.bs_sleepduration > bs.bs_dtimperiod)
+ bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ ( "%s: intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n"
+ , __func__
+ , bs.bs_intval
+ , bs.bs_nexttbtt
+ , bs.bs_dtimperiod
+ , bs.bs_nextdtim
+ , bs.bs_bmissthreshold
+ , bs.bs_sleepduration
+ , bs.bs_cfpperiod
+ , bs.bs_cfpmaxduration
+ , bs.bs_cfpnext
+ , bs.bs_timoffset )
+ );
+ ath_hal_intrset(ah, 0);
+ ath_hal_beacontimers(ah, &bs);
+ sc->sc_imask |= HAL_INT_BMISS;
+ ath_hal_intrset(ah, sc->sc_imask);
+ } else {
+ ath_hal_intrset(ah, 0);
+ if (nexttbtt == intval)
+ intval |= HAL_BEACON_RESET_TSF;
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ /*
+ * In IBSS mode enable the beacon timers but only
+ * enable SWBA interrupts if we need to manually
+ * prepare beacon frames. Otherwise we use a
+ * self-linked tx descriptor and let the hardware
+ * deal with things.
+ */
+ intval |= HAL_BEACON_ENA;
+ if (!sc->sc_hasveol)
+ sc->sc_imask |= HAL_INT_SWBA;
+ ath_beaconq_config(sc);
+ } else if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ /*
+ * In AP 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 */
+ ath_beaconq_config(sc);
+ }
+ ath_hal_beaconinit(ah, nexttbtt, intval);
+ sc->sc_bmisscount = 0;
+ ath_hal_intrset(ah, sc->sc_imask);
+ /*
+ * When using a self-linked beacon descriptor in
+ * ibss mode load it once here.
+ */
+ if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol)
+ ath_beacon_proc(sc, 0);
+ }
+#undef TSF_TO_TU
+}
+
+static void
+ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs __unused, int error __unused)
+{
+ bus_addr_t *paddr = (bus_addr_t*) arg;
+ *paddr = segs->ds_addr;
+}
+
+static int
+ath_descdma_setup(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head,
+ const char *name, int nbuf, int ndesc)
+{
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_desc *ds;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ DPRINTF(sc, ATH_DEBUG_RESET, ("%s: %s DMA: %u buffers %u desc/buf\n",
+ __func__, name, nbuf, ndesc));
+
+ dd->dd_name = name;
+ dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+
+ /*
+ * Setup DMA descriptor area.
+ */
+ error = bus_dma_tag_create(NULL, /* parent */
+ PAGE_SIZE, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ dd->dd_desc_len, /* maxsize */
+ 1, /* nsegments */
+ BUS_SPACE_MAXADDR, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ &dd->dd_dmat);
+ if (error != 0) {
+ if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name);
+ return error;
+ }
+
+ /* allocate descriptors */
+ error = bus_dmamap_create(dd->dd_dmat, BUS_DMA_WAITOK, &dd->dd_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for %s descriptors, "
+ "error %u\n", dd->dd_name, error);
+ goto fail0;
+ }
+
+ error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc,
+ BUS_DMA_WAITOK, &dd->dd_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to alloc memory for %u %s descriptors, "
+ "error %u\n", nbuf * ndesc, dd->dd_name, error);
+ goto fail1;
+ }
+
+ error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap,
+ dd->dd_desc, dd->dd_desc_len,
+ ath_load_cb, &dd->dd_desc_paddr,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(ifp, "unable to map %s descriptors, error %u\n",
+ dd->dd_name, error);
+ goto fail2;
+ }
+
+ ds = dd->dd_desc;
+ DPRINTF(sc, ATH_DEBUG_RESET, ("%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
+ __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len,
+ (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len));
+
+ /* allocate rx buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = malloc(bsize, M_DEVBUF, M_WAITOK | M_ZERO);
+ if (bf == NULL) {
+ if_printf(ifp, "malloc of %s buffers failed, size %u\n",
+ dd->dd_name, bsize);
+ goto fail3;
+ }
+ dd->dd_bufptr = bf;
+
+ STAILQ_INIT(head);
+ for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+ error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_WAITOK,
+ &bf->bf_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for %s "
+ "buffer %u, error %u\n", dd->dd_name, i, error);
+ ath_descdma_cleanup(sc, dd, head);
+ return error;
+ }
+ STAILQ_INSERT_TAIL(head, bf, bf_list);
+ }
+ return 0;
+fail3:
+ bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
+fail2:
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+fail1:
+ bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
+fail0:
+ bus_dma_tag_destroy(dd->dd_dmat);
+ memset(dd, 0, sizeof(*dd));
+ return error;
+#undef DS2PHYS
+}
+
+static void
+ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head)
+{
+ struct ath_buf *bf;
+ struct ieee80211_node *ni;
+
+ bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+ bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
+ bus_dma_tag_destroy(dd->dd_dmat);
+
+ STAILQ_FOREACH(bf, head, bf_list) {
+ if (bf->bf_m) {
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_dmamap != NULL) {
+ bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
+ bf->bf_dmamap = NULL;
+ }
+ bf->bf_node = NULL;
+ if (ni != NULL) {
+ /*
+ * Reclaim node reference.
+ */
+ ieee80211_free_node(ni);
+ }
+ }
+
+ STAILQ_INIT(head);
+ free(dd->dd_bufptr, M_DEVBUF);
+ memset(dd, 0, sizeof(*dd));
+}
+
+static int
+ath_desc_alloc(struct ath_softc *sc)
+{
+ int error;
+
+ error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+ "rx", ATH_RXBUF, 1);
+ if (error != 0)
+ return error;
+
+ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
+ "tx", ATH_TXBUF, ATH_TXDESC);
+ if (error != 0) {
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ return error;
+ }
+
+ error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
+ "beacon", 1, 1);
+ if (error != 0) {
+ ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ return error;
+ }
+ return 0;
+}
+
+static void
+ath_desc_free(struct ath_softc *sc)
+{
+
+ if (sc->sc_bdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf);
+ if (sc->sc_txdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+ if (sc->sc_rxdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+}
+
+static struct ieee80211_node *
+ath_node_alloc(struct ieee80211_node_table *nt)
+{
+ struct ieee80211com *ic = nt->nt_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space;
+ struct ath_node *an;
+
+ an = malloc(space, M_80211_NODE, M_WAITOK|M_ZERO);
+ if (an == NULL) {
+ /* XXX stat+msg */
+ return NULL;
+ }
+ an->an_avgrssi = ATH_RSSI_DUMMY_MARKER;
+ an->an_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
+ an->an_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
+ an->an_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
+ ath_rate_node_init(sc, an);
+
+ DPRINTF(sc, ATH_DEBUG_NODE, ("%s: an %p\n", __func__, an));
+ return &an->an_node;
+}
+
+static void
+ath_node_free(struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+
+ ath_rate_node_cleanup(sc, ATH_NODE(ni));
+ (*sc->sc_node_free)( ni);
+}
+
+static u_int8_t
+ath_node_getrssi(const struct ieee80211_node *ni)
+{
+#define HAL_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+ u_int32_t avgrssi = ATH_NODE_CONST(ni)->an_avgrssi;
+ int32_t rssi;
+
+ /*
+ * When only one frame is received there will be no state in
+ * avgrssi so fallback on the value recorded by the 802.11 layer.
+ */
+ if (avgrssi != ATH_RSSI_DUMMY_MARKER)
+ rssi = HAL_EP_RND(avgrssi, HAL_RSSI_EP_MULTIPLIER);
+ else
+ rssi = ni->ni_rssi;
+ /* NB: theoretically we shouldn't need this, but be paranoid */
+ return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi;
+#undef HAL_EP_RND
+}
+
+static int
+ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int error;
+ struct mbuf *m;
+ struct ath_desc *ds;
+
+ m = bf->bf_m;
+ if (m == NULL) {
+ /*
+ * NB: by assigning a page to the rx dma buffer we
+ * implicitly satisfy the Atheros requirement that
+ * this buffer be cache-line-aligned and sized to be
+ * multiple of the cache line size. Not doing this
+ * causes weird stuff to happen (for the 5210 at least).
+ */
+ m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: no mbuf/cluster\n", __func__));
+ sc->sc_stats.ast_rx_nombuf++;
+ return ENOMEM;
+ }
+ bf->bf_m = m;
+ m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
+
+ error = bus_dmamap_load_mbuf(sc->sc_dmat,
+ bf->bf_dmamap, m,
+ ath_mbuf_load_cb, bf,
+ BUS_DMA_WAITOK);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: bus_dmamap_load_mbuf failed; error %d\n",
+ __func__, error));
+ sc->sc_stats.ast_rx_busdma++;
+ return error;
+ }
+ KASSERT(bf->bf_nseg == 1,
+ ("multi-segment packet; nseg %u", bf->bf_nseg));
+ }
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD);
+
+ /*
+ * Setup descriptors. For receive we always terminate
+ * the descriptor list with a self-linked entry so we'll
+ * not get overrun under high load (as can happen with a
+ * 5212 when ANI processing enables PHY error frames).
+ *
+ * To insure the last descriptor is self-linked we create
+ * each descriptor as self-linked and add it to the end. As
+ * each additional descriptor is added the previous self-linked
+ * entry is ``fixed'' naturally. This should be safe even
+ * if DMA is happening. When processing RX interrupts we
+ * never remove/process the last, self-linked, entry on the
+ * descriptor list. This insures the hardware always has
+ * someplace to write a new frame.
+ */
+ ds = bf->bf_desc;
+ ds->ds_link = bf->bf_daddr; /* link to self */
+ ds->ds_data = bf->bf_segs[0].ds_addr;
+ ath_hal_setuprxdesc(ah, ds
+ , m->m_len /* buffer size */
+ , 0
+ );
+
+ if (sc->sc_rxlink != NULL)
+ *sc->sc_rxlink = bf->bf_daddr;
+ sc->sc_rxlink = &ds->ds_link;
+ return 0;
+}
+
+/*
+ * Extend 15-bit time stamp from rx descriptor to
+ * a full 64-bit TSF using the current h/w TSF.
+ */
+static __inline u_int64_t
+ath_extend_tsf(struct ath_hal *ah, u_int32_t rstamp)
+{
+ u_int64_t tsf;
+
+ tsf = ath_hal_gettsf64(ah);
+ if ((tsf & 0x7fff) < rstamp)
+ tsf -= 0x8000;
+ return ((tsf &~ 0x7fff) | rstamp);
+}
+
+/*
+ * Intercept management frames to collect beacon rssi data
+ * and to do ibss merges.
+ */
+static void
+ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
+ struct ieee80211_node *ni,
+ int subtype, int rssi, u_int32_t rstamp)
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+
+ /*
+ * Call up first so subsequent work can use information
+ * potentially stored in the node (e.g. for ibss merge).
+ */
+ sc->sc_recv_mgmt(ic, m, ni, subtype, rssi, rstamp);
+ switch (subtype) {
+ case IEEE80211_FC0_SUBTYPE_BEACON:
+ /* update rssi statistics for use by the hal */
+ ATH_RSSI_LPF(ATH_NODE(ni)->an_halstats.ns_avgbrssi, rssi);
+ /* fall thru... */
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ if (ic->ic_opmode == IEEE80211_M_IBSS &&
+ ic->ic_state == IEEE80211_S_RUN) {
+ u_int64_t tsf = ath_extend_tsf(sc->sc_ah, rstamp);
+ /*
+ * Handle ibss merge as needed; check the tsf on the
+ * frame before attempting the merge. The 802.11 spec
+ * says the station should change it's bssid to match
+ * the oldest station with the same ssid, where oldest
+ * is determined by the tsf. Note that hardware
+ * reconfiguration happens through callback to
+ * ath_newstate as the state machine will go from
+ * RUN -> RUN when this happens.
+ */
+ if (le64toh(ni->ni_tstamp.tsf) >= tsf) {
+ DPRINTF(sc, ATH_DEBUG_STATE,
+ ("ibss merge, rstamp %u tsf %ju "
+ "tstamp %ju\n", rstamp, (uintmax_t)tsf,
+ (uintmax_t)ni->ni_tstamp.tsf));
+ (void) ieee80211_ibss_merge(ni);
+ }
+ }
+ break;
+ }
+}
+
+/*
+ * Set the default antenna.
+ */
+static void
+ath_setdefantenna(struct ath_softc *sc, u_int antenna)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ /* XXX block beacon interrupts */
+ ath_hal_setdefantenna(ah, antenna);
+ if (sc->sc_defant != antenna)
+ sc->sc_stats.ast_ant_defswitch++;
+ sc->sc_defant = antenna;
+ sc->sc_rxotherant = 0;
+}
+
+static void
+ath_rx_proc(void *arg, int npending)
+{
+#define PA2DESC(_sc, _pa) \
+ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+ struct ath_softc *sc = arg;
+ struct ath_buf *bf;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_desc *ds;
+ struct mbuf *m;
+ struct ieee80211_node *ni;
+ struct ath_node *an;
+ size_t len, type;
+ u_int phyerr;
+ HAL_STATUS status;
+
+ NET_LOCK_GIANT(); /* XXX */
+
+ DPRINTF(sc, ATH_DEBUG_RX_PROC, ("%s: pending %u\n", __func__, npending));
+ do {
+ bf = STAILQ_FIRST(&sc->sc_rxbuf);
+ if (bf == NULL) { /* NB: shouldn't happen */
+ if_printf(ifp, "ath_rx_proc: no buffer!\n");
+ break;
+ }
+ ds = bf->bf_desc;
+ if (ds->ds_link == bf->bf_daddr) {
+ /* NB: never process the self-linked entry at the end */
+ break;
+ }
+ m = bf->bf_m;
+ if (m == NULL) { /* NB: shouldn't happen */
+ if_printf(ifp, "ath_rx_proc: no mbuf!\n");
+ continue;
+ }
+ /* XXX sync descriptor memory */
+ /*
+ * Must provide the virtual address of the current
+ * descriptor, the physical address, and the virtual
+ * address of the next descriptor in the h/w chain.
+ * This allows the HAL to look ahead to see if the
+ * hardware is done with a descriptor by checking the
+ * done bit in the following descriptor and the address
+ * of the current descriptor the DMA engine is working
+ * on. All this is necessary because of our use of
+ * a self-linked list to avoid rx overruns.
+ */
+ status = ath_hal_rxprocdesc(ah, ds,
+ bf->bf_daddr, PA2DESC(sc, ds->ds_link));
+#ifdef AR_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
+ ath_printrxbuf(bf, status == HAL_OK);
+#endif
+ if (status == HAL_EINPROGRESS)
+ break;
+ STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
+ if (ds->ds_rxstat.rs_more) {
+ /*
+ * Frame spans multiple descriptors; this
+ * cannot happen yet as we don't support
+ * jumbograms. If not in monitor mode,
+ * discard the frame.
+ */
+ if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+ sc->sc_stats.ast_rx_toobig++;
+ goto rx_next;
+ }
+ /* fall thru for monitor mode handling... */
+ } else if (ds->ds_rxstat.rs_status != 0) {
+ if (ds->ds_rxstat.rs_status & HAL_RXERR_CRC)
+ sc->sc_stats.ast_rx_crcerr++;
+ if (ds->ds_rxstat.rs_status & HAL_RXERR_FIFO)
+ sc->sc_stats.ast_rx_fifoerr++;
+ if (ds->ds_rxstat.rs_status & HAL_RXERR_PHY) {
+ sc->sc_stats.ast_rx_phyerr++;
+ phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
+ sc->sc_stats.ast_rx_phy[phyerr]++;
+ goto rx_next;
+ }
+ if (ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT) {
+ /*
+ * Decrypt error. If the error occurred
+ * because there was no hardware key, then
+ * let the frame through so the upper layers
+ * can process it. This is necessary for 5210
+ * parts which have no way to setup a ``clear''
+ * key cache entry.
+ *
+ * XXX do key cache faulting
+ */
+ if (ds->ds_rxstat.rs_keyix == HAL_RXKEYIX_INVALID)
+ goto rx_accept;
+ sc->sc_stats.ast_rx_badcrypt++;
+ }
+ if (ds->ds_rxstat.rs_status & HAL_RXERR_MIC) {
+ sc->sc_stats.ast_rx_badmic++;
+ /*
+ * Do minimal work required to hand off
+ * the 802.11 header for notifcation.
+ */
+ /* XXX frag's and qos frames */
+ len = ds->ds_rxstat.rs_datalen;
+ if (len >= sizeof (struct ieee80211_frame)) {
+ bus_dmamap_sync(sc->sc_dmat,
+ bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ ieee80211_notify_michael_failure(ic,
+ mtod(m, struct ieee80211_frame *),
+ sc->sc_splitmic ?
+ ds->ds_rxstat.rs_keyix-32 :
+ ds->ds_rxstat.rs_keyix
+ );
+ }
+ }
+ ifp->if_ierrors++;
+ /*
+ * Reject error frames, we normally don't want
+ * to see them in monitor mode (in monitor mode
+ * allow through packets that have crypto problems).
+ */
+ if ((ds->ds_rxstat.rs_status &~
+ (HAL_RXERR_DECRYPT|HAL_RXERR_MIC)) ||
+ sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR)
+ goto rx_next;
+ }
+rx_accept:
+ /*
+ * Sync and unmap the frame. At this point we're
+ * committed to passing the mbuf somewhere so clear
+ * bf_m; this means a new sk_buff must be allocated
+ * when the rx descriptor is setup again to receive
+ * another frame.
+ */
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ bf->bf_m = NULL;
+
+ m->m_pkthdr.rcvif = ifp;
+ len = ds->ds_rxstat.rs_datalen;
+ m->m_pkthdr.len = m->m_len = len;
+
+ sc->sc_stats.ast_ant_rx[ds->ds_rxstat.rs_antenna]++;
+
+ if (sc->sc_drvbpf) {
+ u_int8_t rix;
+
+ /*
+ * Discard anything shorter than an ack or cts.
+ */
+ if (len < IEEE80211_ACK_LEN) {
+ DPRINTF(sc, ATH_DEBUG_RECV,
+ ( "%s: runt packet %d\n",
+ __func__, len ));
+ sc->sc_stats.ast_rx_tooshort++;
+ m_freem(m);
+ goto rx_next;
+ }
+ rix = ds->ds_rxstat.rs_rate;
+ sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags;
+ sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate;
+ sc->sc_rx_th.wr_antsignal = ds->ds_rxstat.rs_rssi;
+ sc->sc_rx_th.wr_antenna = ds->ds_rxstat.rs_antenna;
+ /* XXX TSF */
+
+#ifdef ATH_RAWBPF
+ bpf_ptap(sc->sc_drvbpf, m, &sc->sc_rx_th, sc->sc_rx_th_len);
+#endif
+ }
+
+ /*
+ * From this point on we assume the frame is at least
+ * as large as ieee80211_frame_min; verify that.
+ */
+ if (len < IEEE80211_MIN_LEN) {
+ DPRINTF(sc, ATH_DEBUG_RECV, ("%s: short packet %d\n",
+ __func__, len));
+ sc->sc_stats.ast_rx_tooshort++;
+ m_freem(m);
+ goto rx_next;
+ }
+
+ if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) {
+ ieee80211_dump_pkt(mtod(m, caddr_t), len,
+ sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate,
+ ds->ds_rxstat.rs_rssi);
+ }
+
+ m_adj(m, -IEEE80211_CRC_LEN);
+
+ /*
+ * Locate the node for sender, track state, and then
+ * pass the (referenced) node up to the 802.11 layer
+ * for its use.
+ */
+ ni = ieee80211_find_rxnode_withkey(ic,
+ mtod(m, const struct ieee80211_frame_min *),
+ ds->ds_rxstat.rs_keyix == HAL_RXKEYIX_INVALID ?
+ IEEE80211_KEYIX_NONE : ds->ds_rxstat.rs_keyix);
+ /*
+ * Track rx rssi and do any rx antenna management.
+ */
+ an = ATH_NODE(ni);
+ ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
+ /*
+ * Send frame up for processing.
+ */
+ type = ieee80211_input(ic, m, ni,
+ ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
+ ieee80211_free_node(ni);
+ if (sc->sc_diversity) {
+ /*
+ * When using fast diversity, change the default rx
+ * antenna if diversity chooses the other antenna 3
+ * times in a row.
+ */
+ if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
+ if (++sc->sc_rxotherant >= 3)
+ ath_setdefantenna(sc,
+ ds->ds_rxstat.rs_antenna);
+ } else
+ sc->sc_rxotherant = 0;
+ }
+ if (sc->sc_softled) {
+ /*
+ * Blink for any data frame. Otherwise do a
+ * heartbeat-style blink when idle. The latter
+ * is mainly for station mode where we depend on
+ * periodic beacon frames to trigger the poll event.
+ */
+ if (type == IEEE80211_FC0_TYPE_DATA) {
+ sc->sc_rxrate = ds->ds_rxstat.rs_rate;
+ ath_led_event(sc, ATH_LED_RX);
+ } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle)
+ ath_led_event(sc, ATH_LED_POLL);
+ }
+rx_next:
+ STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+ } while (ath_rxbuf_init(sc, bf) == 0);
+
+ /* rx signal state monitoring */
+ ath_hal_rxmonitor(ah, &ATH_NODE(ic->ic_bss)->an_halstats);
+
+ NET_UNLOCK_GIANT(); /* XXX */
+#undef PA2DESC
+}
+
+/*
+ * Setup a h/w transmit queue.
+ */
+static struct ath_txq *
+ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_TXQ_INFO qi;
+ int qnum;
+
+ memset(&qi, 0, sizeof(qi));
+ qi.tqi_subtype = subtype;
+ qi.tqi_aifs = HAL_TXQ_USEDEFAULT;
+ qi.tqi_cwmin = HAL_TXQ_USEDEFAULT;
+ qi.tqi_cwmax = HAL_TXQ_USEDEFAULT;
+ /*
+ * Enable interrupts only for EOL and DESC conditions.
+ * We mark tx descriptors to receive a DESC interrupt
+ * when a tx queue gets deep; otherwise waiting for the
+ * EOL to reap descriptors. Note that this is done to
+ * reduce interrupt load and this only defers reaping
+ * descriptors, never transmitting frames. Aside from
+ * reducing interrupts this also permits more concurrency.
+ * The only potential downside is if the tx queue backs
+ * up in which case the top half of the kernel may backup
+ * due to a lack of tx descriptors.
+ */
+ qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE;
+ qnum = ath_hal_setuptxqueue(ah, qtype, &qi);
+ if (qnum == -1) {
+ /*
+ * NB: don't print a message, this happens
+ * normally on parts with too few tx queues
+ */
+ return NULL;
+ }
+ if (qnum >= N(sc->sc_txq)) {
+ device_printf(sc->sc_dev,
+ "hal qnum %u out of range, max %zu!\n",
+ qnum, N(sc->sc_txq));
+ ath_hal_releasetxqueue(ah, qnum);
+ return NULL;
+ }
+ if (!ATH_TXQ_SETUP(sc, qnum)) {
+ struct ath_txq *txq = &sc->sc_txq[qnum];
+
+ txq->axq_qnum = qnum;
+ txq->axq_depth = 0;
+ txq->axq_intrcnt = 0;
+ txq->axq_link = NULL;
+ STAILQ_INIT(&txq->axq_q);
+ ATH_TXQ_LOCK_INIT(sc, txq);
+ sc->sc_txqsetup |= 1<<qnum;
+ }
+ return &sc->sc_txq[qnum];
+#undef N
+}
+
+/*
+ * Setup a hardware data transmit queue for the specified
+ * access control. The hal may not support all requested
+ * queues in which case it will return a reference to a
+ * previously setup queue. We record the mapping from ac's
+ * to h/w queues for use by ath_tx_start and also track
+ * the set of h/w queues being used to optimize work in the
+ * transmit interrupt handler and related routines.
+ */
+static int
+ath_tx_setup(struct ath_softc *sc, int ac, int haltype)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ struct ath_txq *txq;
+
+ if (ac >= N(sc->sc_ac2q)) {
+ device_printf(sc->sc_dev, "AC %u out of range, max %zu!\n",
+ ac, N(sc->sc_ac2q));
+ return 0;
+ }
+ txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype);
+ if (txq != NULL) {
+ sc->sc_ac2q[ac] = txq;
+ return 1;
+ } else
+ return 0;
+#undef N
+}
+
+/*
+ * Update WME parameters for a transmit queue.
+ */
+static int
+ath_txq_update(struct ath_softc *sc, int ac)
+{
+#define ATH_EXPONENT_TO_VALUE(v) ((1<<v)-1)
+#define ATH_TXOP_TO_US(v) (v<<5)
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_txq *txq = sc->sc_ac2q[ac];
+ struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac];
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_TXQ_INFO qi;
+
+ ath_hal_gettxqueueprops(ah, txq->axq_qnum, &qi);
+ qi.tqi_aifs = wmep->wmep_aifsn;
+ qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
+ qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
+ qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit);
+
+ if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) {
+ device_printf(sc->sc_dev, "unable to update hardware queue "
+ "parameters for %s traffic!\n",
+ ieee80211_wme_acnames[ac]);
+ return 0;
+ } else {
+ ath_hal_resettxqueue(ah, txq->axq_qnum); /* push to h/w */
+ return 1;
+ }
+#undef ATH_TXOP_TO_US
+#undef ATH_EXPONENT_TO_VALUE
+}
+
+/*
+ * Callback from the 802.11 layer to update WME parameters.
+ */
+static int
+ath_wme_update(struct ieee80211com *ic)
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+
+ return !ath_txq_update(sc, WME_AC_BE) ||
+ !ath_txq_update(sc, WME_AC_BK) ||
+ !ath_txq_update(sc, WME_AC_VI) ||
+ !ath_txq_update(sc, WME_AC_VO) ? EIO : 0;
+}
+
+/*
+ * Reclaim resources for a setup queue.
+ */
+static void
+ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
+{
+
+ ath_hal_releasetxqueue(sc->sc_ah, txq->axq_qnum);
+ ATH_TXQ_LOCK_DESTROY(txq);
+ sc->sc_txqsetup &= ~(1<<txq->axq_qnum);
+}
+
+/*
+ * Reclaim all tx queue resources.
+ */
+static void
+ath_tx_cleanup(struct ath_softc *sc)
+{
+ int i;
+
+ ATH_TXBUF_LOCK_DESTROY(sc);
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->sc_txq[i]);
+}
+
+/*
+ * Defragment an mbuf chain, returning at most maxfrags separate
+ * mbufs+clusters. If this is not possible NULL is returned and
+ * the original mbuf chain is left in it's present (potentially
+ * modified) state. We use two techniques: collapsing consecutive
+ * mbufs and replacing consecutive mbufs by a cluster.
+ */
+static struct mbuf *
+ath_defrag(struct mbuf *m0, int how, int maxfrags)
+{
+ struct mbuf *m, *n, *n2, **prev;
+ u_int curfrags;
+
+ /*
+ * Calculate the current number of frags.
+ */
+ curfrags = 0;
+ for (m = m0; m != NULL; m = m->m_next)
+ curfrags++;
+ /*
+ * First, try to collapse mbufs. Note that we always collapse
+ * towards the front so we don't need to deal with moving the
+ * pkthdr. This may be suboptimal if the first mbuf has much
+ * less data than the following.
+ */
+ m = m0;
+again:
+ for (;;) {
+ n = m->m_next;
+ if (n == NULL)
+ break;
+ if (/* (m->m_flags & M_RDONLY) == 0 && */ /* XXX */
+ n->m_len < M_TRAILINGSPACE(m)) {
+ bcopy(mtod(n, void *), mtod(m, char *) + m->m_len,
+ n->m_len);
+ m->m_len += n->m_len;
+ m->m_next = n->m_next;
+ m_free(n);
+ if (--curfrags <= maxfrags)
+ return m0;
+ } else
+ m = n;
+ }
+ KASSERT(maxfrags > 1,
+ ("maxfrags %u, but normal collapse failed", maxfrags));
+ /*
+ * Collapse consecutive mbufs to a cluster.
+ */
+ prev = &m0->m_next; /* NB: not the first mbuf */
+ while ((n = *prev) != NULL) {
+ if ((n2 = n->m_next) != NULL &&
+ n->m_len + n2->m_len < MCLBYTES) {
+ m = m_getcl(how, MT_DATA, 0);
+ if (m == NULL)
+ goto bad;
+ bcopy(mtod(n, void *), mtod(m, void *), n->m_len);
+ bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len,
+ n2->m_len);
+ m->m_len = n->m_len + n2->m_len;
+ m->m_next = n2->m_next;
+ *prev = m;
+ m_free(n);
+ m_free(n2);
+ if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */
+ return m0;
+ /*
+ * Still not there, try the normal collapse
+ * again before we allocate another cluster.
+ */
+ goto again;
+ }
+ prev = &n->m_next;
+ }
+ /*
+ * No place where we can collapse to a cluster; punt.
+ * This can occur if, for example, you request 2 frags
+ * but the packet requires that both be clusters (we
+ * never reallocate the first mbuf to avoid moving the
+ * packet header).
+ */
+bad:
+ return NULL;
+}
+
+static int
+ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
+ struct mbuf *m0)
+{
+#define CTS_DURATION \
+ ath_hal_computetxtime(ah, rt, IEEE80211_ACK_LEN, cix, AH_TRUE)
+#define updateCTSForBursting(_ah, _ds, _txq) \
+ ath_hal_updateCTSForBursting(_ah, _ds, \
+ _txq->axq_linkbuf != NULL ? _txq->axq_linkbuf->bf_desc : NULL, \
+ _txq->axq_lastdsWithCTS, _txq->axq_gatingds, \
+ txopLimit, CTS_DURATION)
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ifnet *ifp = sc->sc_ifp;
+ const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams;
+ int i, error, iswep, ismcast, keyix, hdrlen, pktlen, try0;
+ u_int8_t rix, txrate, ctsrate;
+ u_int8_t cix = 0xff; /* NB: silence compiler */
+ struct ath_desc *ds, *ds0;
+ struct ath_txq *txq;
+ struct ieee80211_frame *wh;
+ u_int subtype, flags, ctsduration;
+ HAL_PKT_TYPE atype;
+ const HAL_RATE_TABLE *rt;
+ HAL_BOOL shortPreamble;
+ struct ath_node *an;
+ struct mbuf *m;
+ u_int pri;
+ ATH_LOCK_INFO;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
+ ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+ hdrlen = ieee80211_anyhdrsize(wh);
+ /*
+ * Packet length must not include any
+ * pad bytes; deduct them here.
+ */
+ pktlen = m0->m_pkthdr.len - (hdrlen & 3);
+
+ if (iswep) {
+ const struct ieee80211_cipher *cip;
+ struct ieee80211_key *k;
+
+ /*
+ * Construct the 802.11 header+trailer for an encrypted
+ * frame. The only reason this can fail is because of an
+ * unknown or unsupported cipher/key type.
+ */
+ k = ieee80211_crypto_encap(ic, ni, m0);
+ if (k == NULL) {
+ /*
+ * This can happen when the key is yanked after the
+ * frame was queued. Just discard the frame; the
+ * 802.11 layer counts failures and provides
+ * debugging/diagnostics.
+ */
+ m_freem(m0);
+ return EIO;
+ }
+ /*
+ * Adjust the packet + header lengths for the crypto
+ * additions and calculate the h/w key index. When
+ * a s/w mic is done the frame will have had any mic
+ * added to it prior to entry so skb->len above will
+ * account for it. Otherwise we need to add it to the
+ * packet length.
+ */
+ cip = k->wk_cipher;
+ hdrlen += cip->ic_header;
+ pktlen += cip->ic_header + cip->ic_trailer;
+ if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0)
+ pktlen += cip->ic_miclen;
+ keyix = k->wk_keyix;
+
+ /* packet header may have moved, reset our local pointer */
+ wh = mtod(m0, struct ieee80211_frame *);
+ } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
+ /*
+ * Use station key cache slot, if assigned.
+ */
+ keyix = ni->ni_ucastkey.wk_keyix;
+ if (keyix == IEEE80211_KEYIX_NONE)
+ keyix = HAL_TXKEYIX_INVALID;
+ } else
+ keyix = HAL_TXKEYIX_INVALID;
+
+ pktlen += IEEE80211_CRC_LEN;
+
+ /*
+ * Load the DMA map so any coalescing is done. This
+ * also calculates the number of descriptors we need.
+ */
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m0,
+ ath_mbuf_load_cb, bf,
+ BUS_DMA_WAITOK);
+ if (error == EFBIG) {
+ /* XXX packet requires too many descriptors */
+ bf->bf_nseg = ATH_TXDESC+1;
+ } else if (error != 0) {
+ sc->sc_stats.ast_tx_busdma++;
+ m_freem(m0);
+ return error;
+ }
+ /*
+ * Discard null packets and check for packets that
+ * require too many TX descriptors. We try to convert
+ * the latter to a cluster.
+ */
+ if (bf->bf_nseg > ATH_TXDESC) { /* too many desc's, linearize */
+ sc->sc_stats.ast_tx_linear++;
+ m = ath_defrag(m0, MB_DONTWAIT, ATH_TXDESC);
+ if (m == NULL) {
+ m_freem(m0);
+ sc->sc_stats.ast_tx_nombuf++;
+ return ENOMEM;
+ }
+ m0 = m;
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m0,
+ ath_mbuf_load_cb, bf,
+ BUS_DMA_WAITOK);
+ if (error != 0) {
+ sc->sc_stats.ast_tx_busdma++;
+ m_freem(m0);
+ return error;
+ }
+ KASSERT(bf->bf_nseg <= ATH_TXDESC,
+ ("too many segments after defrag; nseg %u", bf->bf_nseg));
+ } else if (bf->bf_nseg == 0) { /* null packet, discard */
+ sc->sc_stats.ast_tx_nodata++;
+ m_freem(m0);
+ return EIO;
+ }
+ DPRINTF(sc, ATH_DEBUG_XMIT, ("%s: m %p len %u\n", __func__, m0, pktlen));
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+ bf->bf_m = m0;
+ bf->bf_node = ni; /* NB: held reference */
+
+ /* setup descriptors */
+ ds = bf->bf_desc;
+ rt = sc->sc_currates;
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+
+ /*
+ * NB: the 802.11 layer marks whether or not we should
+ * use short preamble based on the current mode and
+ * negotiated parameters.
+ */
+ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+ (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
+ shortPreamble = AH_TRUE;
+ sc->sc_stats.ast_tx_shortpre++;
+ } else {
+ shortPreamble = AH_FALSE;
+ }
+
+ an = ATH_NODE(ni);
+ flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */
+ /*
+ * Calculate Atheros packet type from IEEE80211 packet header,
+ * setup for rate calculations, and select h/w transmit queue.
+ */
+ switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
+ case IEEE80211_FC0_TYPE_MGT:
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+ if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
+ atype = HAL_PKT_TYPE_BEACON;
+ else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
+ atype = HAL_PKT_TYPE_PROBE_RESP;
+ else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM)
+ atype = HAL_PKT_TYPE_ATIM;
+ else
+ atype = HAL_PKT_TYPE_NORMAL; /* XXX */
+ rix = 0; /* XXX lowest rate */
+ try0 = ATH_TXMAXTRY;
+ if (shortPreamble)
+ txrate = an->an_tx_mgtratesp;
+ else
+ txrate = an->an_tx_mgtrate;
+ /* NB: force all management frames to highest queue */
+ if (ni->ni_flags & IEEE80211_NODE_QOS) {
+ /* NB: force all management frames to highest queue */
+ pri = WME_AC_VO;
+ } else
+ pri = WME_AC_BE;
+ flags |= HAL_TXDESC_INTREQ; /* force interrupt */
+ break;
+ case IEEE80211_FC0_TYPE_CTL:
+ atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */
+ rix = 0; /* XXX lowest rate */
+ try0 = ATH_TXMAXTRY;
+ if (shortPreamble)
+ txrate = an->an_tx_mgtratesp;
+ else
+ txrate = an->an_tx_mgtrate;
+ /* NB: force all ctl frames to highest queue */
+ if (ni->ni_flags & IEEE80211_NODE_QOS) {
+ /* NB: force all ctl frames to highest queue */
+ pri = WME_AC_VO;
+ } else
+ pri = WME_AC_BE;
+ flags |= HAL_TXDESC_INTREQ; /* force interrupt */
+ break;
+ case IEEE80211_FC0_TYPE_DATA:
+ atype = HAL_PKT_TYPE_NORMAL; /* default */
+ /*
+ * Data frames; consult the rate control module.
+ */
+ ath_rate_findrate(sc, an, shortPreamble, pktlen,
+ &rix, &try0, &txrate);
+ sc->sc_txrate = txrate; /* for LED blinking */
+ /*
+ * Default all non-QoS traffic to the background queue.
+ */
+ if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
+ pri = M_WME_GETAC(m0);
+ if (cap->cap_wmeParams[pri].wmep_noackPolicy) {
+ flags |= HAL_TXDESC_NOACK;
+ sc->sc_stats.ast_tx_noack++;
+ }
+ } else
+ pri = WME_AC_BE;
+ break;
+ default:
+ if_printf(ifp, "bogus frame type 0x%x (%s)\n",
+ wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
+ /* XXX statistic */
+ m_freem(m0);
+ return EIO;
+ }
+ txq = sc->sc_ac2q[pri];
+
+ /*
+ * When servicing one or more stations in power-save mode
+ * multicast frames must be buffered until after the beacon.
+ * We use the CAB queue for that.
+ */
+ if (ismcast && ic->ic_ps_sta) {
+ txq = sc->sc_cabq;
+ /* XXX? more bit in 802.11 frame header */
+ }
+
+ /*
+ * Calculate miscellaneous flags.
+ */
+ if (ismcast) {
+ flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */
+ sc->sc_stats.ast_tx_noack++;
+ } else if (pktlen > ic->ic_rtsthreshold) {
+ flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */
+ cix = rt->info[rix].controlRate;
+ sc->sc_stats.ast_tx_rts++;
+ }
+
+ /*
+ * If 802.11g protection is enabled, determine whether
+ * to use RTS/CTS or just CTS. Note that this is only
+ * done for OFDM unicast frames.
+ */
+ if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+ rt->info[rix].phy == IEEE80211_T_OFDM &&
+ (flags & HAL_TXDESC_NOACK) == 0) {
+ /* XXX fragments must use CCK rates w/ protection */
+ if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+ flags |= HAL_TXDESC_RTSENA;
+ else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+ flags |= HAL_TXDESC_CTSENA;
+ cix = rt->info[sc->sc_protrix].controlRate;
+ sc->sc_stats.ast_tx_protect++;
+ }
+
+ /*
+ * Calculate duration. This logically belongs in the 802.11
+ * layer but it lacks sufficient information to calculate it.
+ */
+ if ((flags & HAL_TXDESC_NOACK) == 0 &&
+ (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
+ u_int16_t dur;
+ /*
+ * XXX not right with fragmentation.
+ */
+ if (shortPreamble)
+ dur = rt->info[rix].spAckDuration;
+ else
+ dur = rt->info[rix].lpAckDuration;
+ *(u_int16_t *)wh->i_dur = htole16(dur);
+ }
+
+ /*
+ * Calculate RTS/CTS rate and duration if needed.
+ */
+ ctsduration = 0;
+ if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
+ /*
+ * CTS transmit rate is derived from the transmit rate
+ * by looking in the h/w rate table. We must also factor
+ * in whether or not a short preamble is to be used.
+ */
+ /* NB: cix is set above where RTS/CTS is enabled */
+ KASSERT(cix != 0xff, ("cix not setup"));
+ ctsrate = rt->info[cix].rateCode;
+ /*
+ * Compute the transmit duration based on the frame
+ * size and the size of an ACK frame. We call into the
+ * HAL to do the computation since it depends on the
+ * characteristics of the actual PHY being used.
+ *
+ * NB: CTS is assumed the same size as an ACK so we can
+ * use the precalculated ACK durations.
+ */
+ if (shortPreamble) {
+ ctsrate |= rt->info[cix].shortPreamble;
+ if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */
+ ctsduration += rt->info[cix].spAckDuration;
+ ctsduration += ath_hal_computetxtime(ah,
+ rt, pktlen, rix, AH_TRUE);
+ if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */
+ ctsduration += rt->info[rix].spAckDuration;
+ } else {
+ if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */
+ ctsduration += rt->info[cix].lpAckDuration;
+ ctsduration += ath_hal_computetxtime(ah,
+ rt, pktlen, rix, AH_FALSE);
+ if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */
+ ctsduration += rt->info[rix].lpAckDuration;
+ }
+ /*
+ * Must disable multi-rate retry when using RTS/CTS.
+ */
+ try0 = ATH_TXMAXTRY;
+ } else
+ ctsrate = 0;
+
+ if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
+ ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len,
+ sc->sc_hwmap[txrate].ieeerate, -1);
+
+ if (ic->ic_rawbpf)
+ bpf_mtap(ic->ic_rawbpf, m0);
+ if (sc->sc_drvbpf) {
+ sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].txflags;
+ if (iswep)
+ sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+ sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate;
+ sc->sc_tx_th.wt_txpower = ni->ni_txpower;
+ sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
+
+ bpf_ptap(sc->sc_drvbpf, m0, &sc->sc_tx_th, sc->sc_tx_th_len);
+ }
+
+ /*
+ * Determine if a tx interrupt should be generated for
+ * this descriptor. We take a tx interrupt to reap
+ * descriptors when the h/w hits an EOL condition or
+ * when the descriptor is specifically marked to generate
+ * an interrupt. We periodically mark descriptors in this
+ * way to insure timely replenishing of the supply needed
+ * for sending frames. Defering interrupts reduces system
+ * load and potentially allows more concurrent work to be
+ * done but if done to aggressively can cause senders to
+ * backup.
+ *
+ * NB: use >= to deal with sc_txintrperiod changing
+ * dynamically through sysctl.
+ */
+ if (flags & HAL_TXDESC_INTREQ) {
+ txq->axq_intrcnt = 0;
+ } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) {
+ flags |= HAL_TXDESC_INTREQ;
+ txq->axq_intrcnt = 0;
+ }
+
+ /*
+ * Formulate first tx descriptor with tx controls.
+ */
+ /* XXX check return value? */
+ ath_hal_setuptxdesc(ah, ds
+ , pktlen /* packet length */
+ , hdrlen /* header length */
+ , atype /* Atheros packet type */
+ , ni->ni_txpower /* txpower */
+ , txrate, try0 /* series 0 rate/tries */
+ , keyix /* key cache index */
+ , sc->sc_txantenna /* antenna mode */
+ , flags /* flags */
+ , ctsrate /* rts/cts rate */
+ , ctsduration /* rts/cts duration */
+ );
+ bf->bf_flags = flags;
+ /*
+ * Setup the multi-rate retry state only when we're
+ * going to use it. This assumes ath_hal_setuptxdesc
+ * initializes the descriptors (so we don't have to)
+ * when the hardware supports multi-rate retry and
+ * we don't use it.
+ */
+ if (try0 != ATH_TXMAXTRY)
+ ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix);
+
+ /*
+ * Fillin the remainder of the descriptor info.
+ */
+ ds0 = ds;
+ for (i = 0; i < bf->bf_nseg; i++, ds++) {
+ ds->ds_data = bf->bf_segs[i].ds_addr;
+ if (i == bf->bf_nseg - 1)
+ ds->ds_link = 0;
+ else
+ ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
+ ath_hal_filltxdesc(ah, ds
+ , bf->bf_segs[i].ds_len /* segment length */
+ , i == 0 /* first segment */
+ , i == bf->bf_nseg - 1 /* last segment */
+ , ds0 /* first descriptor */
+ );
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ ("%s: %d: %08x %08x %08x %08x %08x %08x\n",
+ __func__, i, ds->ds_link, ds->ds_data,
+ ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]));
+ }
+ /*
+ * Insert the frame on the outbound list and
+ * pass it on to the hardware.
+ */
+ ATH_TXQ_LOCK(txq);
+ if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) {
+ u_int32_t txopLimit = IEEE80211_TXOP_TO_US(
+ cap->cap_wmeParams[pri].wmep_txopLimit);
+ /*
+ * When bursting, potentially extend the CTS duration
+ * of a previously queued frame to cover this frame
+ * and not exceed the txopLimit. If that can be done
+ * then disable RTS/CTS on this frame since it's now
+ * covered (burst extension). Otherwise we must terminate
+ * the burst before this frame goes out so as not to
+ * violate the WME parameters. All this is complicated
+ * as we need to update the state of packets on the
+ * (live) hardware queue. The logic is buried in the hal
+ * because it's highly chip-specific.
+ */
+ if (txopLimit != 0) {
+ sc->sc_stats.ast_tx_ctsburst++;
+ if (updateCTSForBursting(ah, ds0, txq) == 0) {
+ /*
+ * This frame was not covered by RTS/CTS from
+ * the previous frame in the burst; update the
+ * descriptor pointers so this frame is now
+ * treated as the last frame for extending a
+ * burst.
+ */
+ txq->axq_lastdsWithCTS = ds0;
+ /* set gating Desc to final desc */
+ txq->axq_gatingds =
+ (struct ath_desc *)txq->axq_link;
+ } else
+ sc->sc_stats.ast_tx_ctsext++;
+ }
+ }
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+ if (txq->axq_link == NULL) {
+ ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ ("%s: TXDP[%u] = %p (%p) depth %d\n", __func__,
+ txq->axq_qnum, (caddr_t)bf->bf_daddr, bf->bf_desc,
+ txq->axq_depth));
+ } else {
+ *txq->axq_link = bf->bf_daddr;
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ ("%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
+ txq->axq_qnum, txq->axq_link,
+ (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth));
+ }
+ txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
+ /*
+ * The CAB queue is started from the SWBA handler since
+ * frames only go out on DTIM and to avoid possible races.
+ */
+ if (txq != sc->sc_cabq)
+ ath_hal_txstart(ah, txq->axq_qnum);
+ ATH_TXQ_UNLOCK(txq);
+
+ return 0;
+#undef updateCTSForBursting
+#undef CTS_DURATION
+}
+
+/*
+ * Process completed xmit descriptors from the specified queue.
+ */
+static void
+ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_buf *bf;
+ struct ath_desc *ds, *ds0;
+ struct ieee80211_node *ni;
+ struct ath_node *an;
+ int sr, lr, pri;
+ HAL_STATUS status;
+ ATH_LOCK_INFO;
+ ATH_TXBUF_LOCK_INFO;
+
+ DPRINTF(sc, ATH_DEBUG_TX_PROC, ("%s: tx queue %u head %p link %p\n",
+ __func__, txq->axq_qnum,
+ (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum),
+ txq->axq_link));
+ for (;;) {
+ ATH_TXQ_LOCK(txq);
+ txq->axq_intrcnt = 0; /* reset periodic desc intr count */
+ bf = STAILQ_FIRST(&txq->axq_q);
+ if (bf == NULL) {
+ txq->axq_link = NULL;
+ ATH_TXQ_UNLOCK(txq);
+ break;
+ }
+ ds0 = &bf->bf_desc[0];
+ ds = &bf->bf_desc[bf->bf_nseg - 1];
+ status = ath_hal_txprocdesc(ah, ds);
+#ifdef AR_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_XMIT_DESC)
+ ath_printtxbuf(bf, status == HAL_OK);
+#endif
+ if (status == HAL_EINPROGRESS) {
+ ATH_TXQ_UNLOCK(txq);
+ break;
+ }
+ if (ds0 == txq->axq_lastdsWithCTS)
+ txq->axq_lastdsWithCTS = NULL;
+ if (ds == txq->axq_gatingds)
+ txq->axq_gatingds = NULL;
+ ATH_TXQ_REMOVE_HEAD(txq, bf_list);
+ ATH_TXQ_UNLOCK(txq);
+
+ ni = bf->bf_node;
+ if (ni != NULL) {
+ an = ATH_NODE(ni);
+ if (ds->ds_txstat.ts_status == 0) {
+ u_int8_t txant = ds->ds_txstat.ts_antenna;
+ sc->sc_stats.ast_ant_tx[txant]++;
+ sc->sc_ant_tx[txant]++;
+ if (ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)
+ sc->sc_stats.ast_tx_altrate++;
+ sc->sc_stats.ast_tx_rssi =
+ ds->ds_txstat.ts_rssi;
+ ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi,
+ ds->ds_txstat.ts_rssi);
+ pri = M_WME_GETAC(bf->bf_m);
+ if (pri >= WME_AC_VO)
+ ic->ic_wme.wme_hipri_traffic++;
+ ni->ni_inact = ni->ni_inact_reload;
+ } else {
+ if (ds->ds_txstat.ts_status & HAL_TXERR_XRETRY)
+ sc->sc_stats.ast_tx_xretries++;
+ if (ds->ds_txstat.ts_status & HAL_TXERR_FIFO)
+ sc->sc_stats.ast_tx_fifoerr++;
+ if (ds->ds_txstat.ts_status & HAL_TXERR_FILT)
+ sc->sc_stats.ast_tx_filtered++;
+ }
+ sr = ds->ds_txstat.ts_shortretry;
+ lr = ds->ds_txstat.ts_longretry;
+ sc->sc_stats.ast_tx_shortretry += sr;
+ sc->sc_stats.ast_tx_longretry += lr;
+ /*
+ * Hand the descriptor to the rate control algorithm.
+ */
+ if ((ds->ds_txstat.ts_status & HAL_TXERR_FILT) == 0 &&
+ (bf->bf_flags & HAL_TXDESC_NOACK) == 0)
+ ath_rate_tx_complete(sc, an, ds, ds0);
+ /*
+ * Reclaim reference to node.
+ *
+ * NB: the node may be reclaimed here if, for example
+ * this is a DEAUTH message that was sent and the
+ * node was timed out due to inactivity.
+ */
+ ieee80211_free_node(ni);
+ }
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ }
+}
+
+/*
+ * Deferred processing of transmit interrupt; special-cased
+ * for a single hardware transmit queue (e.g. 5210 and 5211).
+ */
+static void
+ath_tx_proc_q0(void *arg, int npending __unused)
+{
+ struct ath_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ ath_tx_processq(sc, &sc->sc_txq[0]);
+ ath_tx_processq(sc, sc->sc_cabq);
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->sc_tx_timer = 0;
+
+ if (sc->sc_softled)
+ ath_led_event(sc, ATH_LED_TX);
+
+ ath_start(ifp);
+}
+
+/*
+ * Deferred processing of transmit interrupt; special-cased
+ * for four hardware queues, 0-3 (e.g. 5212 w/ WME support).
+ */
+static void
+ath_tx_proc_q0123(void *arg, int npending __unused)
+{
+ struct ath_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ /*
+ * Process each active queue.
+ */
+ ath_tx_processq(sc, &sc->sc_txq[0]);
+ ath_tx_processq(sc, &sc->sc_txq[1]);
+ ath_tx_processq(sc, &sc->sc_txq[3]);
+ ath_tx_processq(sc, sc->sc_cabq);
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->sc_tx_timer = 0;
+
+ if (sc->sc_softled)
+ ath_led_event(sc, ATH_LED_TX);
+
+ ath_start(ifp);
+}
+
+/*
+ * Deferred processing of transmit interrupt.
+ */
+static void
+ath_tx_proc(void *arg, int npending __unused)
+{
+ struct ath_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ int i;
+
+ /*
+ * Process each active queue.
+ */
+ /* XXX faster to read ISR_S0_S and ISR_S1_S to determine q's? */
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_processq(sc, &sc->sc_txq[i]);
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->sc_tx_timer = 0;
+
+ if (sc->sc_softled)
+ ath_led_event(sc, ATH_LED_TX);
+
+ ath_start(ifp);
+}
+
+static void
+ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211_node *ni;
+ struct ath_buf *bf;
+ ATH_LOCK_INFO;
+ ATH_TXBUF_LOCK_INFO;
+
+ /*
+ * NB: this assumes output has been stopped and
+ * we do not need to block ath_tx_tasklet
+ */
+ for (;;) {
+ ATH_TXQ_LOCK(txq);
+ bf = STAILQ_FIRST(&txq->axq_q);
+ if (bf == NULL) {
+ txq->axq_link = NULL;
+ ATH_TXQ_UNLOCK(txq);
+ break;
+ }
+#if old
+ TAILQ_REMOVE(&sc->sc_txq, bf, bf_list);
+#else
+ ATH_TXQ_REMOVE_HEAD(txq, bf_list);
+#endif
+ ATH_TXQ_UNLOCK(txq);
+#ifdef AR_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_RESET)
+ ath_printtxbuf(bf,
+ ath_hal_txprocdesc(ah, bf->bf_desc) == HAL_OK);
+#endif /* AR_DEBUG */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ ni = bf->bf_node;
+ bf->bf_node = NULL;
+ if (ni != NULL) {
+ /*
+ * Reclaim node reference.
+ */
+ ieee80211_free_node(ni);
+ }
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ }
+}
+
+static void
+ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ (void) ath_hal_stoptxdma(ah, txq->axq_qnum);
+ DPRINTF(sc, ATH_DEBUG_RESET, ("%s: tx queue [%u] %p, link %p\n",
+ __func__, txq->axq_qnum,
+ (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, txq->axq_qnum),
+ txq->axq_link));
+}
+
+/*
+ * Drain the transmit queues and reclaim resources.
+ */
+static void
+ath_draintxq(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ifnet *ifp = sc->sc_ifp;
+ int i;
+
+ /* XXX return value */
+ if (!sc->sc_invalid) {
+ /* don't touch the hardware if marked invalid */
+ (void) ath_hal_stoptxdma(ah, sc->sc_bhalq);
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ ("%s: beacon queue %p\n", __func__,
+ (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, sc->sc_bhalq)));
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_stopdma(sc, &sc->sc_txq[i]);
+ }
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_draintxq(sc, &sc->sc_txq[i]);
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->sc_tx_timer = 0;
+}
+
+/*
+ * Disable the receive h/w in preparation for a reset.
+ */
+static void
+ath_stoprecv(struct ath_softc *sc)
+{
+#define PA2DESC(_sc, _pa) \
+ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+ struct ath_hal *ah = sc->sc_ah;
+
+ ath_hal_stoppcurecv(ah); /* disable PCU */
+ ath_hal_setrxfilter(ah, 0); /* clear recv filter */
+ ath_hal_stopdmarecv(ah); /* disable DMA engine */
+ DELAY(3000); /* long enough for 1 frame */
+#ifdef AR_DEBUG
+ if (sc->sc_debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) {
+ struct ath_buf *bf;
+
+ printf("%s: rx queue %p, link %p\n", __func__,
+ (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink);
+ STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
+ struct ath_desc *ds = bf->bf_desc;
+ HAL_STATUS status = ath_hal_rxprocdesc(ah, ds,
+ bf->bf_daddr, PA2DESC(sc, ds->ds_link));
+ if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL))
+ ath_printrxbuf(bf, status == HAL_OK);
+ }
+ }
+#endif
+ sc->sc_rxlink = NULL; /* just in case */
+#undef PA2DESC
+}
+
+/*
+ * Enable the receive h/w following a reset.
+ */
+static int
+ath_startrecv(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+
+ sc->sc_rxlink = NULL;
+ STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
+ int error = ath_rxbuf_init(sc, bf);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DEBUG_RECV,
+ ("%s: ath_rxbuf_init failed %d\n",
+ __func__, error));
+ return error;
+ }
+ }
+
+ bf = STAILQ_FIRST(&sc->sc_rxbuf);
+ ath_hal_putrxbuf(ah, bf->bf_daddr);
+ ath_hal_rxena(ah); /* enable recv descriptors */
+ ath_mode_init(sc); /* set filters, etc. */
+ ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */
+ return 0;
+}
+
+/*
+ * Update internal state after a channel change.
+ */
+static void
+ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ enum ieee80211_phymode mode;
+ u_int16_t flags;
+
+ /*
+ * Change channels and update the h/w rate map
+ * if we're switching; e.g. 11a to 11b/g.
+ */
+ mode = ieee80211_chan2mode(ic, chan);
+ if (mode != sc->sc_curmode)
+ ath_setcurmode(sc, mode);
+ /*
+ * Update BPF state. NB: ethereal et. al. don't handle
+ * merged flags well so pick a unique mode for their use.
+ */
+ if (IEEE80211_IS_CHAN_A(chan))
+ flags = IEEE80211_CHAN_A;
+ /* XXX 11g schizophrenia */
+ else if (IEEE80211_IS_CHAN_G(chan) ||
+ IEEE80211_IS_CHAN_PUREG(chan))
+ flags = IEEE80211_CHAN_G;
+ else
+ flags = IEEE80211_CHAN_B;
+ if (IEEE80211_IS_CHAN_T(chan))
+ flags |= IEEE80211_CHAN_TURBO;
+ sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
+ htole16(chan->ic_freq);
+ sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
+ htole16(flags);
+}
+
+/*
+ * Set/change channels. If the channel is really being changed,
+ * it's done by resetting the chip. To accomplish this we must
+ * first cleanup any pending DMA, then restart stuff after a la
+ * ath_init.
+ */
+static int
+ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211com *ic = &sc->sc_ic;
+ HAL_CHANNEL hchan;
+
+ /*
+ * Convert to a HAL channel description with
+ * the flags constrained to reflect the current
+ * operating mode.
+ */
+ hchan.channel = chan->ic_freq;
+ hchan.channelFlags = ath_chan2flags(ic, chan);
+
+ DPRINTF(sc, ATH_DEBUG_RESET, ("%s: %u (%u MHz) -> %u (%u MHz)\n",
+ __func__,
+ ath_hal_mhz2ieee(sc->sc_curchan.channel,
+ sc->sc_curchan.channelFlags),
+ sc->sc_curchan.channel,
+ ath_hal_mhz2ieee(hchan.channel, hchan.channelFlags), hchan.channel));
+ if (hchan.channel != sc->sc_curchan.channel ||
+ hchan.channelFlags != sc->sc_curchan.channelFlags) {
+ HAL_STATUS status;
+
+ /*
+ * To switch channels clear any pending DMA operations;
+ * wait long enough for the RX fifo to drain, reset the
+ * hardware at the new frequency, and then re-enable
+ * the relevant bits of the h/w.
+ */
+ ath_hal_intrset(ah, 0); /* disable interrupts */
+ ath_draintxq(sc); /* clear pending tx frames */
+ ath_stoprecv(sc); /* turn off frame recv */
+ if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) {
+ if_printf(ic->ic_ifp, "ath_chan_set: unable to reset "
+ "channel %u (%u Mhz)\n",
+ ieee80211_chan2ieee(ic, chan), chan->ic_freq);
+ return EIO;
+ }
+ sc->sc_curchan = hchan;
+ ath_update_txpow(sc); /* update tx power state */
+ sc->sc_diversity = ath_hal_getdiversity(ah);
+
+ /*
+ * Re-enable rx framework.
+ */
+ if (ath_startrecv(sc) != 0) {
+ if_printf(ic->ic_ifp,
+ "ath_chan_set: unable to restart recv logic\n");
+ return EIO;
+ }
+
+ /*
+ * Change channels and update the h/w rate map
+ * if we're switching; e.g. 11a to 11b/g.
+ */
+ ic->ic_ibss_chan = chan;
+ ath_chan_change(sc, chan);
+
+ /*
+ * Re-enable interrupts.
+ */
+ ath_hal_intrset(ah, sc->sc_imask);
+ }
+ return 0;
+}
+
+static void
+ath_next_scan(void *arg)
+{
+ struct ath_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ if (ic->ic_state == IEEE80211_S_SCAN)
+ ieee80211_next_scan(ic);
+}
+
+/*
+ * Periodically recalibrate the PHY to account
+ * for temperature/environment changes.
+ */
+static void
+ath_calibrate(void *arg)
+{
+ struct ath_softc *sc = arg;
+ struct ath_hal *ah = sc->sc_ah;
+
+ sc->sc_stats.ast_per_cal++;
+
+ DPRINTF(sc, ATH_DEBUG_CALIBRATE, ( "%s: channel %u/%x\n",
+ __func__, sc->sc_curchan.channel, sc->sc_curchan.channelFlags ));
+
+ if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) {
+ /*
+ * Rfgain is out of bounds, reset the chip
+ * to load new gain values.
+ */
+ sc->sc_stats.ast_per_rfgain++;
+ ath_reset(sc->sc_ifp);
+ }
+ if (!ath_hal_calibrate(ah, &sc->sc_curchan)) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: calibration of channel %u failed\n",
+ __func__, sc->sc_curchan.channel));
+ sc->sc_stats.ast_per_calfail++;
+ }
+ callout_reset(&sc->sc_cal_ch, ath_calinterval * hz, ath_calibrate, sc);
+}
+
+static int
+ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211_node *ni;
+ int i, error;
+ const u_int8_t *bssid;
+ u_int32_t rfilt;
+ static const HAL_LED_STATE leds[] = {
+ HAL_LED_INIT, /* IEEE80211_S_INIT */
+ HAL_LED_SCAN, /* IEEE80211_S_SCAN */
+ HAL_LED_AUTH, /* IEEE80211_S_AUTH */
+ HAL_LED_ASSOC, /* IEEE80211_S_ASSOC */
+ HAL_LED_RUN, /* IEEE80211_S_RUN */
+ };
+
+ DPRINTF(sc, ATH_DEBUG_STATE, ("%s: %s -> %s\n", __func__,
+ ieee80211_state_name[ic->ic_state],
+ ieee80211_state_name[nstate]));
+
+ callout_stop(&sc->sc_scan_ch);
+ callout_stop(&sc->sc_cal_ch);
+ ath_hal_setledstate(ah, leds[nstate]); /* set LED */
+
+ if (nstate == IEEE80211_S_INIT) {
+ sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
+ /*
+ * NB: disable interrupts so we don't rx frames.
+ */
+ ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL);
+ /*
+ * Notify the rate control algorithm.
+ */
+ ath_rate_newstate(sc, nstate);
+ goto done;
+ }
+ ni = ic->ic_bss;
+ error = ath_chan_set(sc, ic->ic_curchan);
+ if (error != 0)
+ goto bad;
+ rfilt = ath_calcrxfilter(sc, nstate);
+ if (nstate == IEEE80211_S_SCAN)
+ bssid = ifp->if_broadcastaddr;
+ else
+ bssid = ni->ni_bssid;
+ ath_hal_setrxfilter(ah, rfilt);
+ DPRINTF(sc, ATH_DEBUG_STATE, ("%s: RX filter 0x%x bssid %6D\n",
+ __func__, rfilt, (bssid), ":"));
+
+ if (nstate == IEEE80211_S_RUN && ic->ic_opmode == IEEE80211_M_STA)
+ ath_hal_setassocid(ah, bssid, ni->ni_associd);
+ else
+ ath_hal_setassocid(ah, bssid, 0);
+ if (ic->ic_flags & IEEE80211_F_PRIVACY) {
+ for (i = 0; i < IEEE80211_WEP_NKID; i++)
+ if (ath_hal_keyisvalid(ah, i))
+ ath_hal_keysetmac(ah, i, bssid);
+ }
+
+ /*
+ * Notify the rate control algorithm so rates
+ * are setup should ath_beacon_alloc be called.
+ */
+ ath_rate_newstate(sc, nstate);
+
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ /* nothing to do */;
+ } else if (nstate == IEEE80211_S_RUN) {
+ DPRINTF(sc, ATH_DEBUG_STATE,
+ ("%s(RUN): ic_flags=0x%08x iv=%d bssid=%6D "
+ "capinfo=0x%04x chan=%d\n"
+ , __func__
+ , ic->ic_flags
+ , ni->ni_intval
+ , (ni->ni_bssid), ":"
+ , ni->ni_capinfo
+ , ieee80211_chan2ieee(ic, ic->ic_curchan)));
+
+ switch (ic->ic_opmode) {
+ case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_IBSS:
+ /*
+ * Allocate and setup the beacon frame.
+ *
+ * Stop any previous beacon DMA. This may be
+ * necessary, for example, when an ibss merge
+ * causes reconfiguration; there will be a state
+ * transition from RUN->RUN that means we may
+ * be called with beacon transmission active.
+ */
+ ath_hal_stoptxdma(ah, sc->sc_bhalq);
+ ath_beacon_free(sc);
+ error = ath_beacon_alloc(sc, ni);
+ if (error != 0)
+ goto bad;
+ break;
+ case IEEE80211_M_STA:
+ /*
+ * Allocate a key cache slot to the station.
+ */
+ if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0 &&
+ sc->sc_hasclrkey &&
+ ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE)
+ ath_setup_stationkey(ni);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Configure the beacon and sleep timers.
+ */
+ ath_beacon_config(sc);
+ } else {
+ ath_hal_intrset(ah,
+ sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS));
+ sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
+ }
+done:
+ /*
+ * Invoke the parent method to complete the work.
+ */
+ error = sc->sc_newstate(ic, nstate, arg);
+ /*
+ * Finally, start any timers.
+ */
+ if (nstate == IEEE80211_S_RUN) {
+ /* start periodic recalibration timer */
+ callout_reset(&sc->sc_cal_ch, ath_calinterval * hz,
+ ath_calibrate, sc);
+ } else if (nstate == IEEE80211_S_SCAN) {
+ /* start ap/neighbor scan timer */
+ callout_reset(&sc->sc_scan_ch, (ath_dwelltime * hz) / 1000,
+ ath_next_scan, sc);
+ }
+bad:
+ return error;
+}
+
+/*
+ * Allocate a key cache slot to the station so we can
+ * setup a mapping from key index to node. The key cache
+ * slot is needed for managing antenna state and for
+ * compression when stations do not use crypto. We do
+ * it uniliaterally here; if crypto is employed this slot
+ * will be reassigned.
+ */
+static void
+ath_setup_stationkey(struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ ieee80211_keyix keyix, rxkeyix;
+
+ if (!ath_key_alloc(ic, &ni->ni_ucastkey, &keyix, &rxkeyix)) {
+ /*
+ * Key cache is full; we'll fall back to doing
+ * the more expensive lookup in software. Note
+ * this also means no h/w compression.
+ */
+ /* XXX msg+statistic */
+ } else {
+ /* XXX locking? */
+ ni->ni_ucastkey.wk_keyix = keyix;
+ ni->ni_ucastkey.wk_rxkeyix = rxkeyix;
+ /* NB: this will create a pass-thru key entry */
+ ath_keyset(sc, &ni->ni_ucastkey, ni->ni_macaddr, ic->ic_bss);
+ }
+}
+
+/*
+ * Setup driver-specific state for a newly associated node.
+ * Note that we're called also on a re-associate, the isnew
+ * param tells us if this is the first time or not.
+ */
+static void
+ath_newassoc(struct ieee80211_node *ni, int isnew)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+
+ ath_rate_newassoc(sc, ATH_NODE(ni), isnew);
+ if (isnew &&
+ (ic->ic_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey) {
+ KASSERT(ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE,
+ ("new assoc with a unicast key already setup (keyix %u)",
+ ni->ni_ucastkey.wk_keyix));
+ ath_setup_stationkey(ni);
+ }
+}
+
+static int
+ath_getchannels(struct ath_softc *sc, u_int cc,
+ HAL_BOOL outdoor, HAL_BOOL xchanmode)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_CHANNEL *chans;
+ int i, ix, nchan;
+
+ chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL),
+ M_TEMP, M_WAITOK);
+ if (chans == NULL) {
+ if_printf(ifp, "unable to allocate channel table\n");
+ return ENOMEM;
+ }
+ if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
+ cc, HAL_MODE_ALL, outdoor, xchanmode)) {
+ u_int32_t rd;
+
+ ath_hal_getregdomain(ah, &rd);
+ if_printf(ifp, "unable to collect channel list from hal; "
+ "regdomain likely %u country code %u\n", rd, cc);
+ free(chans, M_TEMP);
+ return EINVAL;
+ }
+
+ /*
+ * Convert HAL channels to ieee80211 ones and insert
+ * them in the table according to their channel number.
+ */
+ for (i = 0; i < nchan; i++) {
+ HAL_CHANNEL *c = &chans[i];
+ ix = ath_hal_mhz2ieee(c->channel, c->channelFlags);
+ if (ix > IEEE80211_CHAN_MAX) {
+ if_printf(ifp, "bad hal channel %u (%u/%x) ignored\n",
+ ix, c->channel, c->channelFlags);
+ continue;
+ }
+ /* NB: flags are known to be compatible */
+ if (ic->ic_channels[ix].ic_freq == 0) {
+ ic->ic_channels[ix].ic_freq = c->channel;
+ ic->ic_channels[ix].ic_flags = c->channelFlags;
+ } else {
+ /* channels overlap; e.g. 11g and 11b */
+ ic->ic_channels[ix].ic_flags |= c->channelFlags;
+ }
+ }
+ free(chans, M_TEMP);
+ return 0;
+}
+
+static void
+ath_led_done(void *arg)
+{
+ struct ath_softc *sc = arg;
+
+ sc->sc_blinking = 0;
+}
+
+/*
+ * Turn the LED off: flip the pin and then set a timer so no
+ * update will happen for the specified duration.
+ */
+static void
+ath_led_off(void *arg)
+{
+ struct ath_softc *sc = arg;
+
+ ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
+ callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc);
+}
+
+/*
+ * Blink the LED according to the specified on/off times.
+ */
+static void
+ath_led_blink(struct ath_softc *sc, int on, int off)
+{
+ DPRINTF(sc, ATH_DEBUG_LED, ("%s: on %u off %u\n", __func__, on, off));
+ ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon);
+ sc->sc_blinking = 1;
+ sc->sc_ledoff = off;
+ callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc);
+}
+
+static void
+ath_led_event(struct ath_softc *sc, int event)
+{
+
+ sc->sc_ledevent = ticks; /* time of last event */
+ if (sc->sc_blinking) /* don't interrupt active blink */
+ return;
+ switch (event) {
+ case ATH_LED_POLL:
+ ath_led_blink(sc, sc->sc_hwmap[0].ledon,
+ sc->sc_hwmap[0].ledoff);
+ break;
+ case ATH_LED_TX:
+ ath_led_blink(sc, sc->sc_hwmap[sc->sc_txrate].ledon,
+ sc->sc_hwmap[sc->sc_txrate].ledoff);
+ break;
+ case ATH_LED_RX:
+ ath_led_blink(sc, sc->sc_hwmap[sc->sc_rxrate].ledon,
+ sc->sc_hwmap[sc->sc_rxrate].ledoff);
+ break;
+ }
+}
+
+static void
+ath_update_txpow(struct ath_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int32_t txpow;
+
+ if (sc->sc_curtxpow != ic->ic_txpowlimit) {
+ ath_hal_settxpowlimit(ah, ic->ic_txpowlimit);
+ /* read back in case value is clamped */
+ ath_hal_gettxpowlimit(ah, &txpow);
+ ic->ic_txpowlimit = sc->sc_curtxpow = txpow;
+ }
+ /*
+ * Fetch max tx power level for status requests.
+ */
+ ath_hal_getmaxtxpow(sc->sc_ah, &txpow);
+ ic->ic_bss->ni_txpower = txpow;
+}
+
+static int
+ath_rate_setup(struct ath_softc *sc, u_int mode)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211com *ic = &sc->sc_ic;
+ const HAL_RATE_TABLE *rt;
+ struct ieee80211_rateset *rs;
+ int i, maxrates;
+
+ switch (mode) {
+ case IEEE80211_MODE_11A:
+ sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11A);
+ break;
+ case IEEE80211_MODE_11B:
+ sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11B);
+ break;
+ case IEEE80211_MODE_11G:
+ sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11G);
+ break;
+ case IEEE80211_MODE_TURBO_A:
+ sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_TURBO);
+ break;
+ case IEEE80211_MODE_TURBO_G:
+ sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_108G);
+ break;
+ default:
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: invalid mode %u\n", __func__, mode));
+ return 0;
+ }
+ rt = sc->sc_rates[mode];
+ if (rt == NULL)
+ return 0;
+ if (rt->rateCount > IEEE80211_RATE_MAXSIZE) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ ("%s: rate table too small (%u > %u)\n",
+ __func__, rt->rateCount, IEEE80211_RATE_MAXSIZE));
+ maxrates = IEEE80211_RATE_MAXSIZE;
+ } else
+ maxrates = rt->rateCount;
+ rs = &ic->ic_sup_rates[mode];
+ for (i = 0; i < maxrates; i++)
+ rs->rs_rates[i] = rt->info[i].dot11Rate;
+ rs->rs_nrates = maxrates;
+ return 1;
+}
+
+static void
+ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ /* NB: on/off times from the Atheros NDIS driver, w/ permission */
+ static const struct {
+ u_int rate; /* tx/rx 802.11 rate */
+ u_int16_t timeOn; /* LED on time (ms) */
+ u_int16_t timeOff; /* LED off time (ms) */
+ } blinkrates[] = {
+ { 108, 40, 10 },
+ { 96, 44, 11 },
+ { 72, 50, 13 },
+ { 48, 57, 14 },
+ { 36, 67, 16 },
+ { 24, 80, 20 },
+ { 22, 100, 25 },
+ { 18, 133, 34 },
+ { 12, 160, 40 },
+ { 10, 200, 50 },
+ { 6, 240, 58 },
+ { 4, 267, 66 },
+ { 2, 400, 100 },
+ { 0, 500, 130 },
+ };
+ const HAL_RATE_TABLE *rt;
+ int i, j;
+
+ memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
+ rt = sc->sc_rates[mode];
+ KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode));
+ for (i = 0; i < rt->rateCount; i++)
+ sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i;
+ memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
+ for (i = 0; i < 32; i++) {
+ u_int8_t ix = rt->rateCodeToIndex[i];
+ if (ix == 0xff) {
+ sc->sc_hwmap[i].ledon = (500 * hz) / 1000;
+ sc->sc_hwmap[i].ledoff = (130 * hz) / 1000;
+ continue;
+ }
+ sc->sc_hwmap[i].ieeerate =
+ rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
+ sc->sc_hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
+ if (rt->info[ix].shortPreamble ||
+ rt->info[ix].phy == IEEE80211_T_OFDM)
+ sc->sc_hwmap[i].txflags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+ /* NB: receive frames include FCS */
+ sc->sc_hwmap[i].rxflags = sc->sc_hwmap[i].txflags |
+ IEEE80211_RADIOTAP_F_FCS;
+ /* setup blink rate table to avoid per-packet lookup */
+ for (j = 0; j < N(blinkrates)-1; j++)
+ if (blinkrates[j].rate == sc->sc_hwmap[i].ieeerate)
+ break;
+ /* NB: this uses the last entry if the rate isn't found */
+ /* XXX beware of overlow */
+ sc->sc_hwmap[i].ledon = (blinkrates[j].timeOn * hz) / 1000;
+ sc->sc_hwmap[i].ledoff = (blinkrates[j].timeOff * hz) / 1000;
+ }
+ sc->sc_currates = rt;
+ sc->sc_curmode = mode;
+ /*
+ * All protection frames are transmited at 2Mb/s for
+ * 11g, otherwise at 1Mb/s.
+ * XXX select protection rate index from rate table.
+ */
+ sc->sc_protrix = (mode == IEEE80211_MODE_11G ? 1 : 0);
+ /* NB: caller is responsible for reseting rate control state */
+#undef N
+}
+
+#ifdef AR_DEBUG
+static void
+ath_printrxbuf(struct ath_buf *bf, int done)
+{
+ struct ath_desc *ds;
+ int i;
+
+ for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
+ printf("R%d (%p %p) %08x %08x %08x %08x %08x %08x %c\n",
+ i, ds, (struct ath_desc *)bf->bf_daddr + i,
+ ds->ds_link, ds->ds_data,
+ ds->ds_ctl0, ds->ds_ctl1,
+ ds->ds_hw[0], ds->ds_hw[1],
+ !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!');
+ }
+}
+
+static void
+ath_printtxbuf(struct ath_buf *bf, int done)
+{
+ struct ath_desc *ds;
+ int i;
+
+ for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
+ printf("T%d (%p %p) %08x %08x %08x %08x %08x %08x %08x %08x %c\n",
+ i, ds, (struct ath_desc *)bf->bf_daddr + i,
+ ds->ds_link, ds->ds_data,
+ ds->ds_ctl0, ds->ds_ctl1,
+ ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3],
+ !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!');
+ }
+}
+#endif /* AR_DEBUG */
+
+static void
+ath_watchdog(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ ifp->if_timer = 0;
+ if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid)
+ return;
+ if (sc->sc_tx_timer) {
+ if (--sc->sc_tx_timer == 0) {
+ if_printf(ifp, "device timeout\n");
+ ath_reset(ifp);
+ ifp->if_oerrors++;
+ sc->sc_stats.ast_watchdog++;
+ } else
+ ifp->if_timer = 1;
+ }
+ ieee80211_watchdog(ic);
+}
+
+/*
+ * Diagnostic interface to the HAL. This is used by various
+ * tools to do things like retrieve register contents for
+ * debugging. The mechanism is intentionally opaque so that
+ * it can change frequently w/o concern for compatiblity.
+ */
+static int
+ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u_int id = ad->ad_id & ATH_DIAG_ID;
+ void *indata = NULL;
+ void *outdata = NULL;
+ u_int32_t insize = ad->ad_in_size;
+ u_int32_t outsize = ad->ad_out_size;
+ int error = 0;
+
+ if (ad->ad_id & ATH_DIAG_IN) {
+ /*
+ * Copy in data.
+ */
+ indata = malloc(insize, M_TEMP, M_WAITOK);
+ if (indata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ error = copyin(ad->ad_in_data, indata, insize);
+ if (error)
+ goto bad;
+ }
+ if (ad->ad_id & ATH_DIAG_DYN) {
+ /*
+ * Allocate a buffer for the results (otherwise the HAL
+ * returns a pointer to a buffer where we can read the
+ * results). Note that we depend on the HAL leaving this
+ * pointer for us to use below in reclaiming the buffer;
+ * may want to be more defensive.
+ */
+ outdata = malloc(outsize, M_TEMP, M_WAITOK);
+ if (outdata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ }
+ if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) {
+ if (outsize < ad->ad_out_size)
+ ad->ad_out_size = outsize;
+ if (outdata != NULL)
+ error = copyout(outdata, ad->ad_out_data,
+ ad->ad_out_size);
+ } else {
+ error = EINVAL;
+ }
+bad:
+ if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
+ free(indata, M_TEMP);
+ if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
+ free(outdata, M_TEMP);
+ return error;
+}
+
+static int
+ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
+{
+#define IS_RUNNING(ifp) \
+ ((ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING))
+ struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error = 0;
+ ATH_LOCK_INFO;
+
+ ATH_LOCK(sc);
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ if (IS_RUNNING(ifp)) {
+ /*
+ * To avoid rescanning another access point,
+ * do not call ath_init() here. Instead,
+ * only reflect promisc mode settings.
+ */
+ ath_mode_init(sc);
+ } else if (ifp->if_flags & IFF_UP) {
+ /*
+ * Beware of being called during attach/detach
+ * to reset promiscuous mode. In that case we
+ * will still be marked UP but not RUNNING.
+ * However trying to re-init the interface
+ * is the wrong thing to do as we've already
+ * torn down much of our state. There's
+ * probably a better way to deal with this.
+ */
+ if (!sc->sc_invalid && ic->ic_bss != NULL)
+ ath_init(sc); /* XXX lose error */
+ } else
+ ath_stop_locked(ifp);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /*
+ * The upper layer has already installed/removed
+ * the multicast address(es), just recalculate the
+ * multicast filter for the card.
+ */
+ if (ifp->if_flags & IFF_RUNNING)
+ ath_mode_init(sc);
+ break;
+ case SIOCGATHSTATS:
+ /* NB: embed these numbers to get a consistent view */
+ sc->sc_stats.ast_tx_packets = ifp->if_opackets;
+ sc->sc_stats.ast_rx_packets = ifp->if_ipackets;
+ sc->sc_stats.ast_rx_rssi = ieee80211_getrssi(ic);
+ ATH_UNLOCK(sc);
+ /*
+ * NB: Drop the softc lock in case of a page fault;
+ * we'll accept any potential inconsisentcy in the
+ * statistics. The alternative is to copy the data
+ * to a local structure.
+ */
+ return copyout(&sc->sc_stats,
+ ifr->ifr_data, sizeof (sc->sc_stats));
+ case SIOCGATHDIAG:
+ error = ath_ioctl_diag(sc, (struct ath_diag *) ifr);
+ break;
+ default:
+ error = ieee80211_ioctl(ic, cmd, data, cr);
+ if (error == ENETRESET) {
+ if (IS_RUNNING(ifp) &&
+ ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
+ ath_init(sc); /* XXX lose error */
+ error = 0;
+ }
+ if (error == ERESTART)
+ error = IS_RUNNING(ifp) ? ath_reset(ifp) : 0;
+ break;
+ }
+ ATH_UNLOCK(sc);
+ return error;
+#undef IS_RUNNING
+}
+
+static int
+ath_sysctl_slottime(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ u_int slottime = ath_hal_getslottime(sc->sc_ah);
+ int error;
+ (void) arg2;
+
+ error = sysctl_handle_int(oidp, &slottime, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0;
+}
+
+static int
+ath_sysctl_acktimeout(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ u_int acktimeout = ath_hal_getacktimeout(sc->sc_ah);
+ int error;
+ (void) arg2;
+
+ error = sysctl_handle_int(oidp, &acktimeout, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return !ath_hal_setacktimeout(sc->sc_ah, acktimeout) ? EINVAL : 0;
+}
+
+static int
+ath_sysctl_ctstimeout(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ u_int ctstimeout = ath_hal_getctstimeout(sc->sc_ah);
+ int error;
+ (void) arg2;
+
+ error = sysctl_handle_int(oidp, &ctstimeout, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return !ath_hal_setctstimeout(sc->sc_ah, ctstimeout) ? EINVAL : 0;
+}
+
+static int
+ath_sysctl_softled(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ int softled = sc->sc_softled;
+ int error;
+ (void) arg2;
+
+ error = sysctl_handle_int(oidp, &softled, 0, req);
+ if (error || !req->newptr)
+ return error;
+ softled = (softled != 0);
+ if (softled != sc->sc_softled) {
+ if (softled) {
+ /* NB: handle any sc_ledpin change */
+ ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin);
+ ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin,
+ !sc->sc_ledon);
+ }
+ sc->sc_softled = softled;
+ }
+ return 0;
+}
+
+static int
+ath_sysctl_rxantenna(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ u_int defantenna = ath_hal_getdefantenna(sc->sc_ah);
+ int error;
+ (void) arg2;
+
+ error = sysctl_handle_int(oidp, &defantenna, 0, req);
+ if (!error && req->newptr)
+ ath_hal_setdefantenna(sc->sc_ah, defantenna);
+ return error;
+}
+
+static int
+ath_sysctl_diversity(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ u_int diversity = ath_hal_getdiversity(sc->sc_ah);
+ int error;
+ (void) arg2;
+
+ error = sysctl_handle_int(oidp, &diversity, 0, req);
+ if (error || !req->newptr)
+ return error;
+ if (!ath_hal_setdiversity(sc->sc_ah, diversity))
+ return EINVAL;
+ sc->sc_diversity = diversity;
+ return 0;
+}
+
+static int
+ath_sysctl_diag(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ u_int32_t diag;
+ int error;
+ (void) arg2;
+
+ if (!ath_hal_getdiag(sc->sc_ah, &diag))
+ return EINVAL;
+ error = sysctl_handle_int(oidp, &diag, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return !ath_hal_setdiag(sc->sc_ah, diag) ? EINVAL : 0;
+}
+
+static int
+ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ struct ifnet *ifp = sc->sc_ifp;
+ u_int32_t scale;
+ int error;
+ (void) arg2;
+
+ ath_hal_gettpscale(sc->sc_ah, &scale);
+ error = sysctl_handle_int(oidp, &scale, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL : ath_reset(ifp);
+}
+
+static int
+ath_sysctl_tpc(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ u_int tpc = ath_hal_gettpc(sc->sc_ah);
+ int error;
+ (void) arg2;
+
+ error = sysctl_handle_int(oidp, &tpc, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return !ath_hal_settpc(sc->sc_ah, tpc) ? EINVAL : 0;
+}
+
+static void
+ath_sysctlattach(struct ath_softc *sc)
+{
+ struct sysctl_ctx_list *ctx = &sc->sysctl_ctx;
+ struct sysctl_oid *tree = sc->sysctl_tree;
+ struct ath_hal *ah = sc->sc_ah;
+ crit_enter();
+
+ ath_hal_getcountrycode(sc->sc_ah, &sc->sc_countrycode);
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "countrycode", CTLFLAG_RD, &sc->sc_countrycode, 0,
+ "EEPROM country code");
+ ath_hal_getregdomain(sc->sc_ah, &sc->sc_regdomain);
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "regdomain", CTLFLAG_RD, &sc->sc_regdomain, 0,
+ "EEPROM regdomain code");
+ sc->sc_debug = ath_debug;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "debug", CTLFLAG_RW, &sc->sc_debug, 0,
+ "control debugging printfs");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "slottime", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_slottime, "I", "802.11 slot time (us)");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "acktimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_acktimeout, "I", "802.11 ACK timeout (us)");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ctstimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_ctstimeout, "I", "802.11 CTS timeout (us)");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "softled", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_softled, "I", "enable/disable software LED support");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ledpin", CTLFLAG_RW, &sc->sc_ledpin, 0,
+ "GPIO pin connected to LED");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ledon", CTLFLAG_RW, &sc->sc_ledon, 0,
+ "setting to turn LED on");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0,
+ "idle time for inactivity LED (ticks)");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "txantenna", CTLFLAG_RW, &sc->sc_txantenna, 0,
+ "tx antenna (0=auto)");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "rxantenna", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_rxantenna, "I", "default/rx antenna");
+ if (ath_hal_hasdiversity(ah))
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "diversity", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_diversity, "I", "antenna diversity");
+ sc->sc_txintrperiod = ATH_TXINTR_PERIOD;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "txintrperiod", CTLFLAG_RW, &sc->sc_txintrperiod, 0,
+ "tx descriptor batching");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "diag", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_diag, "I", "h/w diagnostic control");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "tpscale", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_tpscale, "I", "tx power scaling");
+ if (ath_hal_hastpc(ah))
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "tpc", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_tpc, "I", "enable/disable per-packet TPC");
+ crit_exit();
+}
+
+static void
+ath_bpfattach(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ bpfattach_dlt(ifp, DLT_IEEE802_11_RADIO,
+ sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
+ /*
+ * Initialize constant fields.
+ * XXX make header lengths a multiple of 32-bits so subsequent
+ * headers are properly aligned; this is a kludge to keep
+ * certain applications happy.
+ *
+ * NB: the channel is setup each time we transition to the
+ * RUN state to avoid filling it in for each frame.
+ */
+ sc->sc_tx_th_len = 64;
+ sc->sc_tx_th.wt_ihdr.it_len = htole16(sc->sc_tx_th_len);
+ sc->sc_tx_th.wt_ihdr.it_present = htole32(ATH_TX_RADIOTAP_PRESENT);
+
+ sc->sc_rx_th_len = 64;
+ sc->sc_rx_th.wr_ihdr.it_len = htole16(sc->sc_rx_th_len);
+ sc->sc_rx_th.wr_ihdr.it_present = htole32(ATH_RX_RADIOTAP_PRESENT);
+}
+
+/*
+ * Announce various information on device/driver attach.
+ */
+static void
+ath_announce(struct ath_softc *sc)
+{
+#define HAL_MODE_DUALBAND (HAL_MODE_11A|HAL_MODE_11B)
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int modes, cc;
+
+ if_printf(ifp, "mac %d.%d phy %d.%d",
+ ah->ah_macVersion, ah->ah_macRev,
+ ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf);
+ /*
+ * Print radio revision(s). We check the wireless modes
+ * to avoid falsely printing revs for inoperable parts.
+ * Dual-band radio revs are returned in the 5Ghz rev number.
+ */
+ ath_hal_getcountrycode(ah, &cc);
+ modes = ath_hal_getwirelessmodes(ah, cc);
+ if ((modes & HAL_MODE_DUALBAND) == HAL_MODE_DUALBAND) {
+ if (ah->ah_analog5GhzRev && ah->ah_analog2GhzRev)
+ printf(" 5ghz radio %d.%d 2ghz radio %d.%d",
+ ah->ah_analog5GhzRev >> 4,
+ ah->ah_analog5GhzRev & 0xf,
+ ah->ah_analog2GhzRev >> 4,
+ ah->ah_analog2GhzRev & 0xf);
+ else
+ printf(" radio %d.%d", ah->ah_analog5GhzRev >> 4,
+ ah->ah_analog5GhzRev & 0xf);
+ } else
+ printf(" radio %d.%d", ah->ah_analog5GhzRev >> 4,
+ ah->ah_analog5GhzRev & 0xf);
+ printf("\n");
+ if (bootverbose) {
+ int i;
+ for (i = 0; i <= WME_AC_VO; i++) {
+ struct ath_txq *txq = sc->sc_ac2q[i];
+ if_printf(ifp, "Use hw queue %u for %s traffic\n",
+ txq->axq_qnum, ieee80211_wme_acnames[i]);
+ }
+ if_printf(ifp, "Use hw queue %u for CAB traffic\n",
+ sc->sc_cabq->axq_qnum);
+ if_printf(ifp, "Use hw queue %u for beacons\n", sc->sc_bhalq);
+ }
+#undef HAL_MODE_DUALBAND
+}
diff -N -u -r src.preview/sys/dev/netif/ath/if_ath_pci.c src/sys/dev/netif/ath/if_ath_pci.c
--- src.preview/sys/dev/netif/ath/if_ath_pci.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/if_ath_pci.c 2005-09-26 10:53:20.000000000 -0400
@@ -0,0 +1,307 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+ * DragonFly Port - Copyright (c) 2005 Andrew Atrens
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * PCI/Cardbus front-end for the Atheros Wireless LAN controller driver.
+ */
+
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+#include <net/if_arp.h>
+
+#include <netproto/802_11/ieee80211.h>
+#include <netproto/802_11/ieee80211_dragonfly.h>
+#include <netproto/802_11/ieee80211_crypto.h>
+#include <netproto/802_11/ieee80211_node.h>
+#include <netproto/802_11/ieee80211_proto.h>
+#include <netproto/802_11/ieee80211_var.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include "if_athvar.h"
+#include "../../../contrib/dev/ath/ah.h"
+
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+
+/*
+ * PCI glue.
+ */
+
+struct ath_pci_softc {
+ struct ath_softc sc_sc;
+ struct resource *sc_sr; /* memory resource */
+ struct resource *sc_irq; /* irq resource */
+ void *sc_ih; /* interrupt handler */
+};
+
+#define BS_BAR 0x10
+#define PCIR_RETRY_TIMEOUT 0x41
+
+static int
+ath_pci_probe(device_t dev)
+{
+ const char* devname;
+
+ devname = ath_hal_probe(pci_get_vendor(dev), pci_get_device(dev));
+ if (devname) {
+ device_set_desc(dev, devname);
+ return 0;
+ }
+ return ENXIO;
+}
+
+static u_int32_t
+ath_pci_setup(device_t dev)
+{
+ u_int32_t cmd;
+
+ /*
+ * Enable memory mapping and bus mastering.
+ */
+ cmd = pci_read_config(dev, PCIR_COMMAND, 4);
+ cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN;
+ pci_write_config(dev, PCIR_COMMAND, cmd, 4);
+ cmd = pci_read_config(dev, PCIR_COMMAND, 4);
+ if ((cmd & PCIM_CMD_MEMEN) == 0) {
+ device_printf(dev, "failed to enable memory mapping\n");
+ return 0;
+ }
+ if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) {
+ device_printf(dev, "failed to enable bus mastering\n");
+ return 0;
+ }
+
+ /*
+ * Disable retry timeout to keep PCI Tx retries from
+ * interfering with C3 CPU state.
+ */
+ pci_write_config(dev, PCIR_RETRY_TIMEOUT, 0, 1);
+
+ return 1;
+}
+
+static int
+ath_pci_attach(device_t dev)
+{
+ struct ath_pci_softc *psc = device_get_softc(dev);
+ struct ath_softc *sc = &psc->sc_sc;
+ int error = ENXIO;
+ int rid;
+
+ sc->sc_dev = dev;
+
+ if (!ath_pci_setup(dev))
+
+ /*
+ * Setup memory-mapping of PCI registers.
+ */
+ rid = BS_BAR;
+ psc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (psc->sc_sr == NULL) {
+ device_printf(dev, "cannot map register space\n");
+ goto bad;
+ }
+ sc->sc_st = rman_get_bustag(psc->sc_sr);
+ sc->sc_sh = rman_get_bushandle(psc->sc_sr);
+ /*
+ * Mark device invalid so any interrupts (shared or otherwise)
+ * that arrive before the HAL is setup are discarded.
+ */
+ sc->sc_invalid = 1;
+
+ /*
+ * Arrange interrupt line.
+ */
+ rid = 0;
+ psc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE|RF_ACTIVE);
+ if (psc->sc_irq == NULL) {
+ device_printf(dev, "could not map interrupt\n");
+ goto bad1;
+ }
+ if (bus_setup_intr(dev, psc->sc_irq,
+ INTR_TYPE_NET | INTR_MPSAFE,
+ ath_intr, sc, &psc->sc_ih, NULL)) {
+ device_printf(dev, "could not establish interrupt\n");
+ goto bad2;
+ }
+
+ /*
+ * Setup DMA descriptor area.
+ */
+ if (bus_dma_tag_create(NULL, /* parent */
+ 1, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ 0x3ffff, /* maxsize XXX */
+ ATH_MAX_SCATTER, /* nsegments */
+ BUS_SPACE_MAXADDR, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ &sc->sc_dmat)) {
+ device_printf(dev, "cannot allocate DMA tag\n");
+ goto bad3;
+ }
+
+ ATH_LOCK_INIT(sc);
+
+ error = ath_attach(pci_get_device(dev), sc);
+ if (error == 0)
+ return error;
+
+ ATH_LOCK_DESTROY(sc);
+ bus_dma_tag_destroy(sc->sc_dmat);
+bad3:
+ bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih);
+bad2:
+ bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq);
+bad1:
+ bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr);
+bad:
+ return (error);
+}
+
+static int
+ath_pci_detach(device_t dev)
+{
+ struct ath_pci_softc *psc = device_get_softc(dev);
+ struct ath_softc *sc = &psc->sc_sc;
+
+ /* check if device was removed */
+ sc->sc_invalid = !bus_child_present(dev);
+
+ ath_detach(sc);
+
+ bus_generic_detach(dev);
+ bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq);
+
+ bus_dma_tag_destroy(sc->sc_dmat);
+ bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr);
+
+ ATH_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static int
+ath_pci_shutdown(device_t dev)
+{
+ struct ath_pci_softc *psc = device_get_softc(dev);
+
+ ath_shutdown(&psc->sc_sc);
+ return (0);
+}
+
+static int
+ath_pci_suspend(device_t dev)
+{
+ struct ath_pci_softc *psc = device_get_softc(dev);
+
+ ath_suspend(&psc->sc_sc);
+
+ return (0);
+}
+
+static int
+ath_pci_resume(device_t dev)
+{
+ struct ath_pci_softc *psc = device_get_softc(dev);
+
+ if (!ath_pci_setup(dev))
+ return ENXIO;
+
+ ath_resume(&psc->sc_sc);
+
+ return (0);
+}
+
+static device_method_t ath_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ath_pci_probe),
+ DEVMETHOD(device_attach, ath_pci_attach),
+ DEVMETHOD(device_detach, ath_pci_detach),
+ DEVMETHOD(device_shutdown, ath_pci_shutdown),
+ DEVMETHOD(device_suspend, ath_pci_suspend),
+ DEVMETHOD(device_resume, ath_pci_resume),
+
+ { 0,0 }
+};
+static driver_t ath_pci_driver = {
+ "ath",
+ ath_pci_methods,
+ sizeof (struct ath_pci_softc),
+ 0,
+ 0,
+ 0
+};
+static devclass_t ath_devclass;
+DRIVER_MODULE(if_ath, pci, ath_pci_driver, ath_devclass, 0, 0);
+DRIVER_MODULE(if_ath, cardbus, ath_pci_driver, ath_devclass, 0, 0);
+MODULE_VERSION(if_ath, 1);
+MODULE_DEPEND(if_ath, ath_hal, 1, 1, 1); /* Atheros HAL */
+MODULE_DEPEND(if_ath, wlan, 1, 1, 1); /* 802.11 media layer */
+MODULE_DEPEND(if_ath, ath_rate, 1, 1, 1); /* rate control algorithm */
diff -N -u -r src.preview/sys/dev/netif/ath/if_athioctl.h src/sys/dev/netif/ath/if_athioctl.h
--- src.preview/sys/dev/netif/ath/if_athioctl.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/if_athioctl.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD: src/sys/dev/ath/if_athioctl.h,v 1.7 2004/04/02 23:57:10 sam Exp $
+ */
+
+/*
+ * Ioctl-related defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_ATHIOCTL_H
+#define _DEV_ATH_ATHIOCTL_H
+
+struct ath_stats {
+ u_int32_t ast_watchdog; /* device reset by watchdog */
+ u_int32_t ast_hardware; /* fatal hardware error interrupts */
+ u_int32_t ast_bmiss; /* beacon miss interrupts */
+ u_int32_t ast_bstuck; /* beacon stuck interrupts */
+ u_int32_t ast_rxorn; /* rx overrun interrupts */
+ u_int32_t ast_rxeol; /* rx eol interrupts */
+ u_int32_t ast_txurn; /* tx underrun interrupts */
+ u_int32_t ast_mib; /* mib interrupts */
+ u_int32_t ast_intrcoal; /* interrupts coalesced */
+ u_int32_t ast_tx_packets; /* packet sent on the interface */
+ u_int32_t ast_tx_mgmt; /* management frames transmitted */
+ u_int32_t ast_tx_discard; /* frames discarded prior to assoc */
+ u_int32_t ast_tx_qstop; /* output stopped 'cuz no buffer */
+ u_int32_t ast_tx_encap; /* tx encapsulation failed */
+ u_int32_t ast_tx_nonode; /* tx failed 'cuz no node */
+ u_int32_t ast_tx_nombuf; /* tx failed 'cuz no mbuf */
+ u_int32_t ast_tx_nomcl; /* tx failed 'cuz no cluster */
+ u_int32_t ast_tx_linear; /* tx linearized to cluster */
+ u_int32_t ast_tx_nodata; /* tx discarded empty frame */
+ u_int32_t ast_tx_busdma; /* tx failed for dma resrcs */
+ u_int32_t ast_tx_xretries;/* tx failed 'cuz too many retries */
+ u_int32_t ast_tx_fifoerr; /* tx failed 'cuz FIFO underrun */
+ u_int32_t ast_tx_filtered;/* tx failed 'cuz xmit filtered */
+ u_int32_t ast_tx_shortretry;/* tx on-chip retries (short) */
+ u_int32_t ast_tx_longretry;/* tx on-chip retries (long) */
+ u_int32_t ast_tx_badrate; /* tx failed 'cuz bogus xmit rate */
+ u_int32_t ast_tx_noack; /* tx frames with no ack marked */
+ u_int32_t ast_tx_rts; /* tx frames with rts enabled */
+ u_int32_t ast_tx_cts; /* tx frames with cts enabled */
+ u_int32_t ast_tx_shortpre;/* tx frames with short preamble */
+ u_int32_t ast_tx_altrate; /* tx frames with alternate rate */
+ u_int32_t ast_tx_protect; /* tx frames with protection */
+ u_int32_t ast_tx_ctsburst;/* tx frames with cts and bursting */
+ u_int32_t ast_tx_ctsext; /* tx frames with cts extension */
+ u_int32_t ast_rx_nombuf; /* rx setup failed 'cuz no mbuf */
+ u_int32_t ast_rx_busdma; /* rx setup failed for dma resrcs */
+ u_int32_t ast_rx_orn; /* rx failed 'cuz of desc overrun */
+ u_int32_t ast_rx_crcerr; /* rx failed 'cuz of bad CRC */
+ u_int32_t ast_rx_fifoerr; /* rx failed 'cuz of FIFO overrun */
+ u_int32_t ast_rx_badcrypt;/* rx failed 'cuz decryption */
+ u_int32_t ast_rx_badmic; /* rx failed 'cuz MIC failure */
+ u_int32_t ast_rx_phyerr; /* rx failed 'cuz of PHY err */
+ u_int32_t ast_rx_phy[32]; /* rx PHY error per-code counts */
+ u_int32_t ast_rx_tooshort;/* rx discarded 'cuz frame too short */
+ u_int32_t ast_rx_toobig; /* rx discarded 'cuz frame too large */
+ u_int32_t ast_rx_packets; /* packet recv on the interface */
+ u_int32_t ast_rx_mgt; /* management frames received */
+ u_int32_t ast_rx_ctl; /* rx discarded 'cuz ctl frame */
+ int8_t ast_tx_rssi; /* tx rssi of last ack */
+ int8_t ast_rx_rssi; /* rx rssi from histogram */
+ u_int32_t ast_be_xmit; /* beacons transmitted */
+ u_int32_t ast_be_nombuf; /* beacon setup failed 'cuz no mbuf */
+ u_int32_t ast_per_cal; /* periodic calibration calls */
+ u_int32_t ast_per_calfail;/* periodic calibration failed */
+ u_int32_t ast_per_rfgain; /* periodic calibration rfgain reset */
+ u_int32_t ast_rate_calls; /* rate control checks */
+ u_int32_t ast_rate_raise; /* rate control raised xmit rate */
+ u_int32_t ast_rate_drop; /* rate control dropped xmit rate */
+ u_int32_t ast_ant_defswitch;/* rx/default antenna switches */
+ u_int32_t ast_ant_txswitch;/* tx antenna switches */
+ u_int32_t ast_ant_rx[8]; /* rx frames with antenna */
+ u_int32_t ast_ant_tx[8]; /* tx frames with antenna */
+};
+
+#define SIOCGATHSTATS _IOWR('i', 137, struct ifreq)
+
+struct ath_diag {
+ char ad_name[IFNAMSIZ]; /* if name, e.g. "ath0" */
+ u_int16_t ad_id;
+#define ATH_DIAG_DYN 0x8000 /* allocate buffer in caller */
+#define ATH_DIAG_IN 0x4000 /* copy in parameters */
+#define ATH_DIAG_OUT 0x0000 /* copy out results (always) */
+#define ATH_DIAG_ID 0x0fff
+ u_int16_t ad_in_size;
+ caddr_t ad_in_data;
+ caddr_t ad_out_data;
+ u_int ad_out_size;
+
+};
+#define SIOCGATHDIAG _IOWR('i', 138, struct ath_diag)
+
+/*
+ * Radio capture format.
+ */
+#define ATH_RX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \
+ 0)
+
+struct ath_rx_radiotap_header {
+ struct ieee80211_radiotap_header wr_ihdr;
+ u_int8_t wr_flags; /* XXX for padding */
+ u_int8_t wr_rate;
+ u_int16_t wr_chan_freq;
+ u_int16_t wr_chan_flags;
+ u_int8_t wr_antenna;
+ u_int8_t wr_antsignal;
+};
+
+#define ATH_TX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ 0)
+
+struct ath_tx_radiotap_header {
+ struct ieee80211_radiotap_header wt_ihdr;
+ u_int8_t wt_flags; /* XXX for padding */
+ u_int8_t wt_rate;
+ u_int16_t wt_chan_freq;
+ u_int16_t wt_chan_flags;
+ u_int8_t wt_txpower;
+ u_int8_t wt_antenna;
+};
+
+#endif /* _DEV_ATH_ATHIOCTL_H */
diff -N -u -r src.preview/sys/dev/netif/ath/if_athrate.h src/sys/dev/netif/ath/if_athrate.h
--- src.preview/sys/dev/netif/ath/if_athrate.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/if_athrate.h 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2004-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004 Video54 Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/dev/ath/if_athrate.h,v 1.2 2004/12/31 22:41:45 sam Exp $
+ */
+#ifndef _ATH_RATECTRL_H_
+#define _ATH_RATECTRL_H_
+
+/*
+ * Interface definitions for transmit rate control modules for the
+ * Atheros driver.
+ *
+ * A rate control module is responsible for choosing the transmit rate
+ * for each data frame. Management+control frames are always sent at
+ * a fixed rate.
+ *
+ * Only one module may be present at a time; the driver references
+ * rate control interfaces by symbol name. If multiple modules are
+ * to be supported we'll need to switch to a registration-based scheme
+ * as is currently done, for example, for authentication modules.
+ *
+ * An instance of the rate control module is attached to each device
+ * at attach time and detached when the device is destroyed. The module
+ * may associate data with each device and each node (station). Both
+ * sets of storage are opaque except for the size of the per-node storage
+ * which must be provided when the module is attached.
+ *
+ * The rate control module is notified for each state transition and
+ * station association/reassociation. Otherwise it is queried for a
+ * rate for each outgoing frame and provided status from each transmitted
+ * frame. Any ancillary processing is the responsibility of the module
+ * (e.g. if periodic processing is required then the module should setup
+ * it's own timer).
+ *
+ * In addition to the transmit rate for each frame the module must also
+ * indicate the number of attempts to make at the specified rate. If this
+ * number is != ATH_TXMAXTRY then an additional callback is made to setup
+ * additional transmit state. The rate control code is assumed to write
+ * this additional data directly to the transmit descriptor.
+ */
+struct ath_softc;
+struct ath_node;
+struct ath_desc;
+
+struct ath_ratectrl {
+ size_t arc_space; /* space required for per-node state */
+};
+/*
+ * Attach/detach a rate control module.
+ */
+struct ath_ratectrl *ath_rate_attach(struct ath_softc *);
+void ath_rate_detach(struct ath_ratectrl *);
+
+/*
+ * State storage handling.
+ */
+/*
+ * Initialize per-node state already allocated for the specified
+ * node; this space can be assumed initialized to zero.
+ */
+void ath_rate_node_init(struct ath_softc *, struct ath_node *);
+/*
+ * Cleanup any per-node state prior to the node being reclaimed.
+ */
+void ath_rate_node_cleanup(struct ath_softc *, struct ath_node *);
+/*
+ * Update rate control state on station associate/reassociate
+ * (when operating as an ap or for nodes discovered when operating
+ * in ibss mode).
+ */
+void ath_rate_newassoc(struct ath_softc *, struct ath_node *,
+ int isNewAssociation);
+/*
+ * Update/reset rate control state for 802.11 state transitions.
+ * Important mostly as the analog to ath_rate_newassoc when operating
+ * in station mode.
+ */
+void ath_rate_newstate(struct ath_softc *, enum ieee80211_state);
+
+/*
+ * Transmit handling.
+ */
+/*
+ * Return the transmit info for a data packet. If multi-rate state
+ * is to be setup then try0 should contain a value other than ATH_TXMATRY
+ * and ath_rate_setupxtxdesc will be called after deciding if the frame
+ * can be transmitted with multi-rate retry.
+ */
+void ath_rate_findrate(struct ath_softc *, struct ath_node *,
+ int shortPreamble, size_t frameLen,
+ u_int8_t *rix, int *try0, u_int8_t *txrate);
+/*
+ * Setup any extended (multi-rate) descriptor state for a data packet.
+ * The rate index returned by ath_rate_findrate is passed back in.
+ */
+void ath_rate_setupxtxdesc(struct ath_softc *, struct ath_node *,
+ struct ath_desc *, int shortPreamble, u_int8_t rix);
+/*
+ * Update rate control state for a packet associated with the
+ * supplied transmit descriptor. The routine is invoked both
+ * for packets that were successfully sent and for those that
+ * failed (consult the descriptor for details).
+ */
+void
+ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
+ const struct ath_desc *ds, const struct ath_desc *ds0);
+
+#endif /* _ATH_RATECTRL_H_ */
diff -N -u -r src.preview/sys/dev/netif/ath/if_athvar.h src/sys/dev/netif/ath/if_athvar.h
--- src.preview/sys/dev/netif/ath/if_athvar.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/dev/netif/ath/if_athvar.h 2005-09-23 11:57:00.000000000 -0400
@@ -0,0 +1,535 @@
+/*-
+ * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
+ * DragonFly Port - Copyright (c) 2005 Andrew Atrens
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_ATHVAR_H
+#define _DEV_ATH_ATHVAR_H
+
+#include <sys/taskqueue.h>
+#include <sys/sysctl.h>
+
+#include "../../../contrib/dev/ath/ah.h"
+#include <netproto/802_11/ieee80211_radiotap.h>
+#include "if_athioctl.h"
+#include "if_athrate.h"
+
+#define ATH_TIMEOUT 1000
+
+#define ATH_RXBUF 40 /* number of RX buffers */
+#define ATH_TXBUF 100 /* number of TX buffers */
+#define ATH_TXDESC 10 /* number of descriptors per buffer */
+#define ATH_TXMAXTRY 11 /* max number of transmit attempts */
+#define ATH_TXINTR_PERIOD 5 /* max number of batched tx descriptors */
+
+#define ATH_BEACON_AIFS_DEFAULT 0 /* default aifs for ap beacon q */
+#define ATH_BEACON_CWMIN_DEFAULT 0 /* default cwmin for ap beacon q */
+#define ATH_BEACON_CWMAX_DEFAULT 0 /* default cwmax for ap beacon q */
+
+/*
+ * The key cache is used for h/w cipher state and also for
+ * tracking station state such as the current tx antenna.
+ * We also setup a mapping table between key cache slot indices
+ * and station state to short-circuit node lookups on rx.
+ * Different parts have different size key caches. We handle
+ * up to ATH_KEYMAX entries (could dynamically allocate state).
+ */
+#define ATH_KEYMAX 128 /* max key cache size we handle */
+#define ATH_KEYBYTES (ATH_KEYMAX/NBBY) /* storage space in bytes */
+
+/* driver-specific node state */
+struct ath_node {
+ struct ieee80211_node an_node; /* base class */
+ u_int8_t an_tx_mgtrate; /* h/w rate for management/ctl frames */
+ u_int8_t an_tx_mgtratesp;/* short preamble h/w rate for " " */
+ u_int32_t an_avgrssi; /* average rssi over all rx frames */
+ HAL_NODE_STATS an_halstats; /* rssi statistics used by hal */
+ /* variable-length rate control state follows */
+};
+#define ATH_NODE(ni) ((struct ath_node *)(ni))
+#define ATH_NODE_CONST(ni) ((const struct ath_node *)(ni))
+
+#define ATH_RSSI_LPF_LEN 10
+#define ATH_RSSI_DUMMY_MARKER 0x127
+#define ATH_EP_MUL(x, mul) ((x) * (mul))
+#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), HAL_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= -20) \
+ x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+} while (0)
+
+struct ath_buf {
+ STAILQ_ENTRY(ath_buf) bf_list;
+ int bf_nseg;
+ int bf_flags; /* tx descriptor flags */
+ struct ath_desc *bf_desc; /* virtual addr of desc */
+ bus_addr_t bf_daddr; /* physical addr of desc */
+ bus_dmamap_t bf_dmamap; /* DMA map for mbuf chain */
+ struct mbuf *bf_m; /* mbuf for buf */
+ struct ieee80211_node *bf_node; /* pointer to the node */
+ bus_size_t bf_mapsize;
+#define ATH_MAX_SCATTER ATH_TXDESC /* max(tx,rx,beacon) desc's */
+ bus_dma_segment_t bf_segs[ATH_MAX_SCATTER];
+};
+typedef STAILQ_HEAD(, ath_buf) ath_bufhead;
+
+/*
+ * DMA state for tx/rx descriptors.
+ */
+struct ath_descdma {
+ const char* dd_name;
+ struct ath_desc *dd_desc; /* descriptors */
+ bus_addr_t dd_desc_paddr; /* physical addr of dd_desc */
+ bus_addr_t dd_desc_len; /* size of dd_desc */
+ bus_dma_segment_t dd_dseg;
+ bus_dma_tag_t dd_dmat; /* bus DMA tag */
+ bus_dmamap_t dd_dmamap; /* DMA map for descriptors */
+ struct ath_buf *dd_bufptr; /* associated buffers */
+};
+
+/*
+ * Data transmit queue state. One of these exists for each
+ * hardware transmit queue. Packets sent to us from above
+ * are assigned to queues based on their priority. Not all
+ * devices support a complete set of hardware transmit queues.
+ * For those devices the array sc_ac2q will map multiple
+ * priorities to fewer hardware queues (typically all to one
+ * hardware queue).
+ */
+struct ath_txq {
+ u_int axq_qnum; /* hardware q number */
+ u_int axq_depth; /* queue depth (stat only) */
+ u_int axq_intrcnt; /* interrupt count */
+ u_int32_t *axq_link; /* link ptr in last TX desc */
+ STAILQ_HEAD(, ath_buf) axq_q; /* transmit queue */
+ struct lwkt_token axq_lock; /* lock on q and link */
+ /*
+ * State for patching up CTS when bursting.
+ */
+ struct ath_buf *axq_linkbuf; /* va of last buffer */
+ struct ath_desc *axq_lastdsWithCTS;
+ /* first desc of last descriptor
+ * that contains CTS
+ */
+ struct ath_desc *axq_gatingds; /* final desc of the gating desc
+ * that determines whether
+ * lastdsWithCTS has been DMA'ed
+ * or not
+ */
+};
+
+#define ATH_TXQ_LOCK_INIT(_sc, _tq) lwkt_token_init(&(_tq)->axq_lock)
+
+#define ATH_TXQ_LOCK_DESTROY(_tq) lwkt_token_uninit(&(_tq)->axq_lock)
+#define ATH_TXQ_LOCK(_tq) lwkt_gettoken(&tokinfo, &(_tq)->axq_lock)
+#define ATH_TXQ_UNLOCK(_txq) lwkt_reltoken(&tokinfo)
+#define ATH_TXQ_LOCK_ASSERT(_sc) (void)_sc
+
+#define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
+ STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
+ (_tq)->axq_depth++; \
+} while (0)
+#define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \
+ STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \
+ (_tq)->axq_depth--; \
+} while (0)
+
+struct ath_softc {
+ struct arpcom sc_arp; /* interface common */
+ struct ifnet *sc_ifp;
+ struct ath_stats sc_stats; /* interface statistics */
+ struct ieee80211com sc_ic; /* IEEE 802.11 common */
+ int sc_regdomain;
+ int sc_countrycode;
+ int sc_debug;
+ void (*sc_recv_mgmt)(struct ieee80211com *,
+ struct mbuf *,
+ struct ieee80211_node *,
+ int, int, u_int32_t);
+ int (*sc_newstate)(struct ieee80211com *,
+ enum ieee80211_state, int);
+ void (*sc_node_free)(struct ieee80211_node *);
+ device_t sc_dev;
+ bus_space_tag_t sc_st; /* bus space tag */
+ bus_space_handle_t sc_sh; /* bus space handle */
+ bus_dma_tag_t sc_dmat; /* bus DMA tag */
+ struct lwkt_token sc_mtx; /* master lock (recursive) */
+ struct ath_hal *sc_ah; /* Atheros HAL */
+ struct ath_ratectrl *sc_rc; /* tx rate control support */
+ void (*sc_setdefantenna)(struct ath_softc *, u_int);
+ unsigned int sc_invalid : 1, /* disable hardware accesses */
+ sc_mrretry : 1, /* multi-rate retry support */
+ sc_softled : 1, /* enable LED gpio status */
+ sc_splitmic: 1, /* split TKIP MIC keys */
+ sc_needmib : 1, /* enable MIB stats intr */
+ sc_diversity : 1,/* enable rx diversity */
+ sc_hasveol : 1, /* tx VEOL support */
+ sc_ledstate: 1, /* LED on/off state */
+ sc_blinking: 1, /* LED blink operation active */
+ sc_mcastkey: 1, /* mcast key cache search */
+ sc_hasclrkey:1; /* CLR key supported */
+ /* rate tables */
+ const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX];
+ const HAL_RATE_TABLE *sc_currates; /* current rate table */
+ enum ieee80211_phymode sc_curmode; /* current phy mode */
+ u_int16_t sc_curtxpow; /* current tx power limit */
+ HAL_CHANNEL sc_curchan; /* current h/w channel */
+ u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */
+ struct {
+ u_int8_t ieeerate; /* IEEE rate */
+ u_int8_t rxflags; /* radiotap rx flags */
+ u_int8_t txflags; /* radiotap tx flags */
+ u_int16_t ledon; /* softled on time */
+ u_int16_t ledoff; /* softled off time */
+ } sc_hwmap[32]; /* h/w rate ix mappings */
+ u_int8_t sc_protrix; /* protection rate index */
+ u_int sc_txantenna; /* tx antenna (fixed or auto) */
+ HAL_INT sc_imask; /* interrupt mask copy */
+ u_int sc_keymax; /* size of key cache */
+ u_int8_t sc_keymap[ATH_KEYBYTES];/* key use bit map */
+
+ u_int sc_ledpin; /* GPIO pin for driving LED */
+ u_int sc_ledon; /* pin setting for LED on */
+ u_int sc_ledidle; /* idle polling interval */
+ int sc_ledevent; /* time of last LED event */
+ u_int8_t sc_rxrate; /* current rx rate for LED */
+ u_int8_t sc_txrate; /* current tx rate for LED */
+ u_int16_t sc_ledoff; /* off time for current blink */
+ struct callout sc_ledtimer; /* led off timer */
+
+ struct bpf_if *sc_drvbpf;
+ union {
+ struct ath_tx_radiotap_header th;
+ u_int8_t pad[64];
+ } u_tx_rt;
+ int sc_tx_th_len;
+ union {
+ struct ath_rx_radiotap_header th;
+ u_int8_t pad[64];
+ } u_rx_rt;
+ int sc_rx_th_len;
+
+ struct task sc_fataltask; /* fatal int processing */
+
+ struct ath_descdma sc_rxdma; /* RX descriptos */
+ ath_bufhead sc_rxbuf; /* receive buffer */
+ u_int32_t *sc_rxlink; /* link ptr in last RX desc */
+ struct task sc_rxtask; /* rx int processing */
+ struct task sc_rxorntask; /* rxorn int processing */
+ u_int8_t sc_defant; /* current default antenna */
+ u_int8_t sc_rxotherant; /* rx's on non-default antenna*/
+
+ struct ath_descdma sc_txdma; /* TX descriptors */
+ ath_bufhead sc_txbuf; /* transmit buffer */
+ struct lwkt_token sc_txbuflock; /* txbuf lock */
+ int sc_tx_timer; /* transmit timeout */
+ u_int sc_txqsetup; /* h/w queues setup */
+ u_int sc_txintrperiod;/* tx interrupt batching */
+ struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
+ struct ath_txq *sc_ac2q[5]; /* WME AC -> h/w q map */
+ struct task sc_txtask; /* tx int processing */
+
+ struct ath_descdma sc_bdma; /* beacon descriptors */
+ ath_bufhead sc_bbuf; /* beacon buffers */
+ u_int sc_bhalq; /* HAL q for outgoing beacons */
+ u_int sc_bmisscount; /* missed beacon transmits */
+ u_int32_t sc_ant_tx[8]; /* recent tx frames/antenna */
+ struct ath_txq *sc_cabq; /* tx q for cab frames */
+ struct ieee80211_beacon_offsets sc_boff;/* dynamic update state */
+ struct task sc_bmisstask; /* bmiss int processing */
+ struct task sc_bstucktask; /* stuck beacon processing */
+ enum {
+ OK, /* no change needed */
+ UPDATE, /* update pending */
+ COMMIT /* beacon sent, commit change */
+ } sc_updateslot; /* slot time update fsm */
+
+ struct callout sc_cal_ch; /* callout handle for cals */
+ struct callout sc_scan_ch; /* callout handle for scan */
+
+ struct sysctl_ctx_list sysctl_ctx;
+ struct sysctl_oid *sysctl_tree;
+ u_int32_t tx_power;
+ u_int32_t last_rx_rssi;
+
+};
+#define sc_if sc_arp.ac_if
+#define sc_tx_th u_tx_rt.th
+#define sc_rx_th u_rx_rt.th
+
+#define ATH_LOCK_INFO struct lwkt_tokref tokinfo;
+#define ATH_LOCK_INIT(_sc) lwkt_token_init(&(_sc)->sc_mtx)
+#define ATH_LOCK_DESTROY(_sc) lwkt_token_uninit(&(_sc)->sc_mtx)
+#define ATH_LOCK(_sc) lwkt_gettoken(&tokinfo, &(_sc)->sc_mtx)
+#define ATH_UNLOCK(_sc) lwkt_reltoken(&tokinfo)
+#define ATH_LOCK_ASSERT(_sc) (void)_sc
+
+#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<<i))
+
+
+#define ATH_TXBUF_LOCK_INFO struct lwkt_tokref txbuf_tokinfo;
+#define ATH_TXBUF_LOCK_INIT(_sc) lwkt_token_init(&(_sc)->sc_txbuflock)
+#define ATH_TXBUF_LOCK_DESTROY(_sc) lwkt_token_uninit(&(_sc)->sc_txbuflock)
+#define ATH_TXBUF_LOCK(_sc) lwkt_gettoken(&txbuf_tokinfo, &(_sc)->sc_txbuflock)
+#define ATH_TXBUF_UNLOCK(_sc) lwkt_reltoken(&txbuf_tokinfo)
+#define ATH_TXBUF_LOCK_ASSERT(_sc) (void)_sc
+
+
+#define NET_LOCK_GIANT() (void)0
+#define NET_UNLOCK_GIANT() (void)0
+
+int ath_attach(u_int16_t, struct ath_softc *);
+int ath_detach(struct ath_softc *);
+void ath_resume(struct ath_softc *);
+void ath_suspend(struct ath_softc *);
+void ath_shutdown(struct ath_softc *);
+void ath_intr(void *);
+
+/*
+ * HAL definitions to comply with local coding convention.
+ */
+#define ath_hal_detach(_ah) \
+ ((*(_ah)->ah_detach)((_ah)))
+#define ath_hal_reset(_ah, _opmode, _chan, _outdoor, _pstatus) \
+ ((*(_ah)->ah_reset)((_ah), (_opmode), (_chan), (_outdoor), (_pstatus)))
+#define ath_hal_getratetable(_ah, _mode) \
+ ((*(_ah)->ah_getRateTable)((_ah), (_mode)))
+#define ath_hal_getmac(_ah, _mac) \
+ ((*(_ah)->ah_getMacAddress)((_ah), (_mac)))
+#define ath_hal_setmac(_ah, _mac) \
+ ((*(_ah)->ah_setMacAddress)((_ah), (_mac)))
+#define ath_hal_intrset(_ah, _mask) \
+ ((*(_ah)->ah_setInterrupts)((_ah), (_mask)))
+#define ath_hal_intrget(_ah) \
+ ((*(_ah)->ah_getInterrupts)((_ah)))
+#define ath_hal_intrpend(_ah) \
+ ((*(_ah)->ah_isInterruptPending)((_ah)))
+#define ath_hal_getisr(_ah, _pmask) \
+ ((*(_ah)->ah_getPendingInterrupts)((_ah), (_pmask)))
+#define ath_hal_updatetxtriglevel(_ah, _inc) \
+ ((*(_ah)->ah_updateTxTrigLevel)((_ah), (_inc)))
+#define ath_hal_setpower(_ah, _mode, _sleepduration) \
+ ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_TRUE, (_sleepduration)))
+#define ath_hal_keycachesize(_ah) \
+ ((*(_ah)->ah_getKeyCacheSize)((_ah)))
+#define ath_hal_keyreset(_ah, _ix) \
+ ((*(_ah)->ah_resetKeyCacheEntry)((_ah), (_ix)))
+#define ath_hal_keyset(_ah, _ix, _pk, _mac) \
+ ((*(_ah)->ah_setKeyCacheEntry)((_ah), (_ix), (_pk), (_mac), AH_FALSE))
+#define ath_hal_keyisvalid(_ah, _ix) \
+ (((*(_ah)->ah_isKeyCacheEntryValid)((_ah), (_ix))))
+#define ath_hal_keysetmac(_ah, _ix, _mac) \
+ ((*(_ah)->ah_setKeyCacheEntryMac)((_ah), (_ix), (_mac)))
+#define ath_hal_getrxfilter(_ah) \
+ ((*(_ah)->ah_getRxFilter)((_ah)))
+#define ath_hal_setrxfilter(_ah, _filter) \
+ ((*(_ah)->ah_setRxFilter)((_ah), (_filter)))
+#define ath_hal_setmcastfilter(_ah, _mfilt0, _mfilt1) \
+ ((*(_ah)->ah_setMulticastFilter)((_ah), (_mfilt0), (_mfilt1)))
+#define ath_hal_waitforbeacon(_ah, _bf) \
+ ((*(_ah)->ah_waitForBeaconDone)((_ah), (_bf)->bf_daddr))
+#define ath_hal_putrxbuf(_ah, _bufaddr) \
+ ((*(_ah)->ah_setRxDP)((_ah), (_bufaddr)))
+#define ath_hal_gettsf32(_ah) \
+ ((*(_ah)->ah_getTsf32)((_ah)))
+#define ath_hal_gettsf64(_ah) \
+ ((*(_ah)->ah_getTsf64)((_ah)))
+#define ath_hal_resettsf(_ah) \
+ ((*(_ah)->ah_resetTsf)((_ah)))
+#define ath_hal_rxena(_ah) \
+ ((*(_ah)->ah_enableReceive)((_ah)))
+#define ath_hal_puttxbuf(_ah, _q, _bufaddr) \
+ ((*(_ah)->ah_setTxDP)((_ah), (_q), (_bufaddr)))
+#define ath_hal_gettxbuf(_ah, _q) \
+ ((*(_ah)->ah_getTxDP)((_ah), (_q)))
+#define ath_hal_numtxpending(_ah, _q) \
+ ((*(_ah)->ah_numTxPending)((_ah), (_q)))
+#define ath_hal_getrxbuf(_ah) \
+ ((*(_ah)->ah_getRxDP)((_ah)))
+#define ath_hal_txstart(_ah, _q) \
+ ((*(_ah)->ah_startTxDma)((_ah), (_q)))
+#define ath_hal_setchannel(_ah, _chan) \
+ ((*(_ah)->ah_setChannel)((_ah), (_chan)))
+#define ath_hal_calibrate(_ah, _chan) \
+ ((*(_ah)->ah_perCalibration)((_ah), (_chan)))
+#define ath_hal_setledstate(_ah, _state) \
+ ((*(_ah)->ah_setLedState)((_ah), (_state)))
+#define ath_hal_beaconinit(_ah, _nextb, _bperiod) \
+ ((*(_ah)->ah_beaconInit)((_ah), (_nextb), (_bperiod)))
+#define ath_hal_beaconreset(_ah) \
+ ((*(_ah)->ah_resetStationBeaconTimers)((_ah)))
+#define ath_hal_beacontimers(_ah, _bs) \
+ ((*(_ah)->ah_setStationBeaconTimers)((_ah), (_bs)))
+#define ath_hal_setassocid(_ah, _bss, _associd) \
+ ((*(_ah)->ah_writeAssocid)((_ah), (_bss), (_associd)))
+#define ath_hal_phydisable(_ah) \
+ ((*(_ah)->ah_phyDisable)((_ah)))
+#define ath_hal_setopmode(_ah) \
+ ((*(_ah)->ah_setPCUConfig)((_ah)))
+#define ath_hal_stoptxdma(_ah, _qnum) \
+ ((*(_ah)->ah_stopTxDma)((_ah), (_qnum)))
+#define ath_hal_stoppcurecv(_ah) \
+ ((*(_ah)->ah_stopPcuReceive)((_ah)))
+#define ath_hal_startpcurecv(_ah) \
+ ((*(_ah)->ah_startPcuReceive)((_ah)))
+#define ath_hal_stopdmarecv(_ah) \
+ ((*(_ah)->ah_stopDmaReceive)((_ah)))
+#define ath_hal_getdiagstate(_ah, _id, _indata, _insize, _outdata, _outsize) \
+ ((*(_ah)->ah_getDiagState)((_ah), (_id), \
+ (_indata), (_insize), (_outdata), (_outsize)))
+#define ath_hal_setuptxqueue(_ah, _type, _irq) \
+ ((*(_ah)->ah_setupTxQueue)((_ah), (_type), (_irq)))
+#define ath_hal_resettxqueue(_ah, _q) \
+ ((*(_ah)->ah_resetTxQueue)((_ah), (_q)))
+#define ath_hal_releasetxqueue(_ah, _q) \
+ ((*(_ah)->ah_releaseTxQueue)((_ah), (_q)))
+#define ath_hal_gettxqueueprops(_ah, _q, _qi) \
+ ((*(_ah)->ah_getTxQueueProps)((_ah), (_q), (_qi)))
+#define ath_hal_settxqueueprops(_ah, _q, _qi) \
+ ((*(_ah)->ah_setTxQueueProps)((_ah), (_q), (_qi)))
+#define ath_hal_getrfgain(_ah) \
+ ((*(_ah)->ah_getRfGain)((_ah)))
+#define ath_hal_getdefantenna(_ah) \
+ ((*(_ah)->ah_getDefAntenna)((_ah)))
+#define ath_hal_setdefantenna(_ah, _ant) \
+ ((*(_ah)->ah_setDefAntenna)((_ah), (_ant)))
+#define ath_hal_rxmonitor(_ah, _arg) \
+ ((*(_ah)->ah_rxMonitor)((_ah), (_arg)))
+#define ath_hal_mibevent(_ah, _stats) \
+ ((*(_ah)->ah_procMibEvent)((_ah), (_stats)))
+#define ath_hal_setslottime(_ah, _us) \
+ ((*(_ah)->ah_setSlotTime)((_ah), (_us)))
+#define ath_hal_getslottime(_ah) \
+ ((*(_ah)->ah_getSlotTime)((_ah)))
+#define ath_hal_setacktimeout(_ah, _us) \
+ ((*(_ah)->ah_setAckTimeout)((_ah), (_us)))
+#define ath_hal_getacktimeout(_ah) \
+ ((*(_ah)->ah_getAckTimeout)((_ah)))
+#define ath_hal_setctstimeout(_ah, _us) \
+ ((*(_ah)->ah_setCTSTimeout)((_ah), (_us)))
+#define ath_hal_getctstimeout(_ah) \
+ ((*(_ah)->ah_getCTSTimeout)((_ah)))
+#define ath_hal_getcapability(_ah, _cap, _param, _result) \
+ ((*(_ah)->ah_getCapability)((_ah), (_cap), (_param), (_result)))
+#define ath_hal_setcapability(_ah, _cap, _param, _v, _status) \
+ ((*(_ah)->ah_setCapability)((_ah), (_cap), (_param), (_v), (_status)))
+#define ath_hal_ciphersupported(_ah, _cipher) \
+ (ath_hal_getcapability(_ah, HAL_CAP_CIPHER, _cipher, NULL) == HAL_OK)
+#define ath_hal_getregdomain(_ah, _prd) \
+ ath_hal_getcapability(_ah, HAL_CAP_REG_DMN, 0, (_prd))
+#define ath_hal_getcountrycode(_ah, _pcc) \
+ (*(_pcc) = (_ah)->ah_countryCode)
+#define ath_hal_tkipsplit(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TKIP_SPLIT, 0, NULL) == HAL_OK)
+#define ath_hal_hwphycounters(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_PHYCOUNTERS, 0, NULL) == HAL_OK)
+#define ath_hal_hasdiversity(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_DIVERSITY, 0, NULL) == HAL_OK)
+#define ath_hal_getdiversity(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_DIVERSITY, 1, NULL) == HAL_OK)
+#define ath_hal_setdiversity(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_DIVERSITY, 1, _v, NULL)
+#define ath_hal_getdiag(_ah, _pv) \
+ (ath_hal_getcapability(_ah, HAL_CAP_DIAG, 0, _pv) == HAL_OK)
+#define ath_hal_setdiag(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_DIAG, 0, _v, NULL)
+#define ath_hal_getnumtxqueues(_ah, _pv) \
+ (ath_hal_getcapability(_ah, HAL_CAP_NUM_TXQUEUES, 0, _pv) == HAL_OK)
+#define ath_hal_hasveol(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_VEOL, 0, NULL) == HAL_OK)
+#define ath_hal_hastxpowlimit(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 0, NULL) == HAL_OK)
+#define ath_hal_settxpowlimit(_ah, _pow) \
+ ((*(_ah)->ah_setTxPowerLimit)((_ah), (_pow)))
+#define ath_hal_gettxpowlimit(_ah, _ppow) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 1, _ppow) == HAL_OK)
+#define ath_hal_getmaxtxpow(_ah, _ppow) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 2, _ppow) == HAL_OK)
+#define ath_hal_gettpscale(_ah, _scale) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 3, _scale) == HAL_OK)
+#define ath_hal_settpscale(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_TXPOW, 3, _v, NULL)
+#define ath_hal_hastpc(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TPC, 0, NULL) == HAL_OK)
+#define ath_hal_gettpc(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TPC, 1, NULL) == HAL_OK)
+#define ath_hal_settpc(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_TPC, 1, _v, NULL)
+#define ath_hal_hasbursting(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_BURST, 0, NULL) == HAL_OK)
+#ifdef notyet
+#define ath_hal_hasmcastkeysearch(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_MCAST_KEYSRCH, 0, NULL) == HAL_OK)
+#define ath_hal_getmcastkeysearch(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_MCAST_KEYSRCH, 1, NULL) == HAL_OK)
+#else
+#define ath_hal_getmcastkeysearch(_ah) 0
+#endif
+
+#define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \
+ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))
+#define ath_hal_rxprocdesc(_ah, _ds, _dspa, _dsnext) \
+ ((*(_ah)->ah_procRxDesc)((_ah), (_ds), (_dspa), (_dsnext)))
+#define ath_hal_setuptxdesc(_ah, _ds, _plen, _hlen, _atype, _txpow, \
+ _txr0, _txtr0, _keyix, _ant, _flags, \
+ _rtsrate, _rtsdura) \
+ ((*(_ah)->ah_setupTxDesc)((_ah), (_ds), (_plen), (_hlen), (_atype), \
+ (_txpow), (_txr0), (_txtr0), (_keyix), (_ant), \
+ (_flags), (_rtsrate), (_rtsdura)))
+#define ath_hal_setupxtxdesc(_ah, _ds, \
+ _txr1, _txtr1, _txr2, _txtr2, _txr3, _txtr3) \
+ ((*(_ah)->ah_setupXTxDesc)((_ah), (_ds), \
+ (_txr1), (_txtr1), (_txr2), (_txtr2), (_txr3), (_txtr3)))
+#define ath_hal_filltxdesc(_ah, _ds, _l, _first, _last, _ds0) \
+ ((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_l), (_first), (_last), (_ds0)))
+#define ath_hal_txprocdesc(_ah, _ds) \
+ ((*(_ah)->ah_procTxDesc)((_ah), (_ds)))
+#define ath_hal_updateCTSForBursting(_ah, _ds, _prevds, _prevdsWithCTS, \
+ _gatingds, _txOpLimit, _ctsDuration) \
+ ((*(_ah)->ah_updateCTSForBursting)((_ah), (_ds), (_prevds), \
+ (_prevdsWithCTS), (_gatingds), (_txOpLimit), (_ctsDuration)))
+
+#define ath_hal_gpioCfgOutput(_ah, _gpio) \
+ ((*(_ah)->ah_gpioCfgOutput)((_ah), (_gpio)))
+#define ath_hal_gpioset(_ah, _gpio, _b) \
+ ((*(_ah)->ah_gpioSet)((_ah), (_gpio), (_b)))
+
+#endif /* _DEV_ATH_ATHVAR_H */
diff -N -u -r src.preview/sys/dev/netif/ndis/if_ndis.c src/sys/dev/netif/ndis/if_ndis.c
--- src.preview/sys/dev/netif/ndis/if_ndis.c 2005-08-10 23:22:57.000000000 -0400
+++ src/sys/dev/netif/ndis/if_ndis.c 2005-09-23 11:24:22.000000000 -0400
@@ -659,8 +659,8 @@
if (r == 0)
ic->ic_caps |= IEEE80211_C_PMGT;
bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr));
- ieee80211_ifattach(ifp);
- ieee80211_media_init(ifp, ieee80211_media_change,
+ ieee80211_ifattach(ic);
+ ieee80211_media_init(ic, ieee80211_media_change,
ndis_media_status);
ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
@@ -701,11 +701,11 @@
ndis_detach(dev)
device_t dev;
{
- struct ndis_softc *sc;
- struct ifnet *ifp;
+ struct ndis_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ieee80211com *ic = &sc->sc_ic;
NDIS_LOCK_INFO;
- sc = device_get_softc(dev);
NDIS_LOCK(sc);
ifp = &sc->arpcom.ac_if;
ifp->if_flags &= ~IFF_UP;
@@ -714,7 +714,7 @@
NDIS_UNLOCK(sc);
ndis_stop(sc);
if (sc->ndis_80211)
- ieee80211_ifdetach(ifp);
+ ieee80211_ifdetach(ic);
else
ether_ifdetach(ifp);
} else
@@ -1655,7 +1655,7 @@
case IEEE80211_MODE_11G:
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
break;
- case IEEE80211_MODE_TURBO:
+ case IEEE80211_MODE_TURBO_A:
imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
| IFM_IEEE80211_TURBO;
break;
diff -N -u -r src.preview/sys/dev/netif/ndis/if_ndisvar.h src/sys/dev/netif/ndis/if_ndisvar.h
--- src.preview/sys/dev/netif/ndis/if_ndisvar.h 2004-09-14 19:57:00.000000000 -0400
+++ src/sys/dev/netif/ndis/if_ndisvar.h 2005-09-23 11:24:22.000000000 -0400
@@ -68,10 +68,9 @@
#define NDIS_INC(x) \
(x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts
-#define arpcom ic.ic_ac
-
struct ndis_softc {
struct ieee80211com ic; /* interface info */
+ struct arpcom arpcom; /* interface info */
#ifdef notdef
struct ieee80211com arpcom; /* interface info */
#endif
diff -N -u -r src.preview/sys/dev/netif/wi/Makefile src/sys/dev/netif/wi/Makefile
--- src.preview/sys/dev/netif/wi/Makefile 2004-09-06 09:52:24.000000000 -0400
+++ src/sys/dev/netif/wi/Makefile 2005-09-23 11:24:22.000000000 -0400
@@ -5,6 +5,7 @@
SRCS= if_wi.c if_wi_pccard.c if_wi_pci.c \
opt_wi.h \
card_if.h device_if.h bus_if.h pci_if.h
+CFLAGS+= -g
opt_wi.h:
echo '#define WI_SYMBOL_FIRMWARE 1' > ${.OBJDIR}/opt_wi.h
diff -N -u -r src.preview/sys/dev/netif/wi/if_wi.c src/sys/dev/netif/wi/if_wi.c
--- src.preview/sys/dev/netif/wi/if_wi.c 2005-07-03 12:47:20.000000000 -0400
+++ src/sys/dev/netif/wi/if_wi.c 2005-09-23 11:36:54.000000000 -0400
@@ -98,7 +98,6 @@
#include <netproto/802_11/ieee80211_var.h>
#include <netproto/802_11/ieee80211_ioctl.h>
#include <netproto/802_11/ieee80211_radiotap.h>
-#include <netproto/802_11/if_wavelan_ieee.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -108,6 +107,7 @@
#include <net/bpf.h>
+#include <netproto/802_11/if_wavelan_ieee.h>
#include <dev/netif/wi/if_wireg.h>
#include <dev/netif/wi/if_wivar.h>
@@ -236,7 +236,7 @@
{
struct wi_softc *sc = device_get_softc(dev);
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_if;
int i, nrates, buflen;
u_int16_t val;
u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE];
@@ -249,6 +249,7 @@
ifp->if_softc = sc;
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ sc->sc_firmware_type = WI_NOTYPE;
sc->wi_cmd_count = 500;
/* Reset the NIC. */
error = wi_reset(sc);
@@ -292,10 +293,14 @@
#endif
ifp->if_capenable = ifp->if_capabilities;
+ ic->ic_ifp = ifp;
ic->ic_phytype = IEEE80211_T_DS;
ic->ic_opmode = IEEE80211_M_STA;
- ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_AHDEMO;
ic->ic_state = IEEE80211_S_INIT;
+ ic->ic_caps = IEEE80211_C_PMGT
+ | IEEE80211_C_WEP /* everyone supports WEP */
+ ;
+ ic->ic_max_aid = WI_MAX_AID;
/*
* Query the card for available channels and setup the
@@ -308,11 +313,11 @@
val <<= 1; /* shift for base 1 indices */
for (i = 1; i < 16; i++) {
- if (isset((u_int8_t*)&val, i)) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
- }
+ if (!isset((u_int8_t*)&val, i))
+ continue;
+ ic->ic_channels[i].ic_freq =
+ ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
+ ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
}
/*
@@ -454,15 +459,14 @@
/*
* Call MI attach routine.
*/
- ieee80211_ifattach(ifp);
+ ieee80211_ifattach(ic);
/* override state transition method */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = wi_newstate;
- ieee80211_media_init(ifp, wi_media_change, wi_media_status);
+ ieee80211_media_init(ic, wi_media_change, wi_media_status);
bpfattach_dlt(ifp, DLT_IEEE802_11_RADIO,
- sizeof(struct ieee80211_frame) + sizeof(sc->sc_tx_th),
- &sc->sc_drvbpf);
+ sizeof(struct ieee80211_frame) + 64, &sc->sc_drvbpf);
/*
* Initialize constant fields.
* XXX make header lengths a multiple of 32-bits so subsequent
@@ -510,6 +514,8 @@
wi_stop(ifp, 0);
+ bpfdetach(ifp);
+
ieee80211_ifdetach(ifp);
wi_free(dev);
WI_UNLOCK(sc);
@@ -573,13 +579,15 @@
u_int16_t status;
WI_LOCK_DECL();
+ WI_LOCK(sc);
+
if (sc->wi_gone || !sc->sc_enabled || (ifp->if_flags & IFF_UP) == 0) {
CSR_WRITE_2(sc, WI_INT_EN, 0);
CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
+ WI_UNLOCK(sc);
return;
}
- WI_LOCK(sc);
/* Disable interrupts. */
CSR_WRITE_2(sc, WI_INT_EN, 0);
@@ -752,9 +760,10 @@
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
+ ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_MONITOR ||
ic->ic_opmode == IEEE80211_M_HOSTAP)
- ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ ieee80211_create_ibss(ic, ic->ic_ibss_chan);
/* Enable interrupts if not polling */
#ifdef DEVICE_POLLING
@@ -839,6 +848,7 @@
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct ieee80211_frame *wh;
+ struct ether_header *eh;
struct mbuf *m0;
struct wi_frame frmhdr;
int cur, fid, off, error;
@@ -884,14 +894,28 @@
} else {
if (ic->ic_state != IEEE80211_S_RUN)
break;
- m0 = ifq_poll(&ifp->if_snd);
+ IF_POLL(&ifp->if_snd, m0);
if (m0 == NULL)
break;
if (sc->sc_txd[cur].d_len != 0) {
+ IF_PREPEND(&ifp->if_snd, m0);
ifp->if_flags |= IFF_OACTIVE;
break;
}
- m0 = ifq_dequeue(&ifp->if_snd);
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0->m_len < sizeof(struct ether_header) &&
+ (m0 = m_pullup(m0, sizeof(struct ether_header))) == NULL) {
+ ifp->if_oerrors++;
+ continue;
+ }
+ eh = mtod(m0, struct ether_header *);
+ ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+ if (ni == NULL) {
+ m_freem(m0);
+ continue;
+ }
+
+
ifp->if_opackets++;
m_copydata(m0, 0, ETHER_HDR_LEN,
(caddr_t)&frmhdr.wi_ehdr);
@@ -899,6 +923,7 @@
m0 = ieee80211_encap(ifp, m0, &ni);
if (m0 == NULL) {
+ ieee80211_free_node(ni);
ifp->if_oerrors++;
continue;
}
@@ -914,10 +939,13 @@
frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX);
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
- if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) {
- ifp->if_oerrors++;
- if (ni && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ struct ieee80211_key *k;
+
+ k = ieee80211_crypto_encap(ic, ni, m0);
+ if (k == NULL) {
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ m_freem(m0);
continue;
}
frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
@@ -941,8 +969,8 @@
error = wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0
|| wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0;
m_freem(m0);
- if (ni && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ if (ni != NULL)
+ ieee80211_free_node(ni);
if (error) {
ifp->if_oerrors++;
continue;
@@ -999,6 +1027,9 @@
/* Calibrate timer. */
wi_write_val(sc, WI_RID_TICK_TIME, 8);
+ if (bootverbose)
+ ieee80211_announce(ic);
+
return (0);
#undef WI_INIT_TRIES
}
@@ -1045,7 +1076,7 @@
}
/* TODO: rate control */
- ieee80211_watchdog(ifp);
+ ieee80211_watchdog(&sc->sc_ic);
}
static int
@@ -1141,7 +1172,7 @@
ireq->i_len);
break;
default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
+ error = ieee80211_ioctl(ic, cmd, data, cr);
break;
}
break;
@@ -1171,7 +1202,7 @@
sc->sc_nodelen = ireq->i_len;
break;
default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
+ error = ieee80211_ioctl(ic, cmd, data, cr);
break;
}
break;
@@ -1180,7 +1211,7 @@
wi_init(sc);
break;
default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
+ error = ieee80211_ioctl(ic, cmd, data, cr);
break;
}
if (error == ENETRESET) {
@@ -1229,23 +1260,22 @@
(sc->sc_flags & WI_FLAGS_OUTRANGE) == 0)
imr->ifm_status |= IFM_ACTIVE;
len = sizeof(val);
- if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) != 0)
- rate = 0;
- else {
+ if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) == 0 &&
+ len == sizeof(val)) {
+ val = le16toh(val);
rate = val * 2;
if (sc->sc_firmware_type == WI_LUCENT) {
- if (rate == 4 * 2)
+ if (rate == 10)
rate = 11; /* 5.5Mbps */
- else if (rate == 5 * 2)
- rate = 22; /* 11Mbps */
} else {
if (rate == 4*2)
rate = 11; /* 5.5Mbps */
else if (rate == 8*2)
rate = 22; /* 11Mbps */
}
- }
+ } else
+ rate = 0;
imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
@@ -1270,7 +1300,7 @@
{
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = ic->ic_bss;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_if;
if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid))
return;
@@ -1283,17 +1313,25 @@
* change-of-BSSID indications.
*/
if ((ifp->if_flags & IFF_PROMISC) != 0 &&
- sc->sc_false_syns >= WI_MAX_FALSE_SYNS)
+ !ppsratecheck(&sc->sc_last_syn, &sc->sc_false_syns,
+ WI_MAX_FALSE_SYNS))
return;
- ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ sc->sc_false_syns = MAX(0, sc->sc_false_syns - 1);
+ /*
+ * XXX hack; we should create a new node with the new bssid
+ * and replace the existing ic_bss with it but since we don't
+ * process management frames to collect state we cheat by
+ * reusing the existing node as we know wi_newstate will be
+ * called and it will overwrite the node state.
+ */
+ ieee80211_sta_join(ic, ieee80211_ref_node(ni));
}
static void
wi_rx_monitor(struct wi_softc *sc, int fid)
{
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_if;
struct wi_frame *rx_frame;
struct mbuf *m;
int datlen, hdrlen;
@@ -1376,7 +1414,7 @@
wi_rx_intr(struct wi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_if;
struct wi_frame frmhdr;
struct mbuf *m;
struct ieee80211_frame *wh;
@@ -1458,6 +1496,17 @@
CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
+ wh = mtod(m, struct ieee80211_frame *);
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ /*
+ * WEP is decrypted by hardware and the IV
+ * is stripped. Clear WEP bit so we don't
+ * try to process it in ieee80211_input.
+ * XXX fix for TKIP, et. al.
+ */
+ wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ }
+
if (sc->sc_drvbpf) {
/* XXX replace divide by table */
sc->sc_rx_th.wr_rate = frmhdr.wi_rx_rate / 5;
@@ -1469,14 +1518,6 @@
bpf_ptap(sc->sc_drvbpf, m, &sc->sc_rx_th, sc->sc_rx_th_len);
}
- wh = mtod(m, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- /*
- * WEP is decrypted by hardware. Clear WEP bit
- * header for ieee80211_input().
- */
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
- }
/* synchronize driver's BSSID with firmware's BSSID */
dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
@@ -1486,36 +1527,25 @@
/*
* Locate the node for sender, track state, and
* then pass this node (referenced) up to the 802.11
- * layer for its use. We are required to pass
- * something so we fallback to ic_bss when this frame
- * is from an unknown sender.
+ * layer for its use.
*/
- if (ic->ic_opmode != IEEE80211_M_STA) {
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL)
- ni = ieee80211_ref_node(ic->ic_bss);
- } else
- ni = ieee80211_ref_node(ic->ic_bss);
+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *) wh);
/*
* Send frame up for processing.
*/
- ieee80211_input(ifp, m, ni, rssi, rstamp);
+ ieee80211_input(ic, m, ni, rssi, rstamp);
/*
* The frame may have caused the node to be marked for
* reclamation (e.g. in response to a DEAUTH message)
* so use free_node here instead of unref_node.
*/
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ ieee80211_free_node(ni);
}
static void
wi_tx_ex_intr(struct wi_softc *sc)
{
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_if;
struct wi_frame frmhdr;
int fid;
@@ -1559,8 +1589,7 @@
static void
wi_tx_intr(struct wi_softc *sc)
{
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_if;
int fid, cur;
if (sc->wi_gone)
@@ -1596,7 +1625,7 @@
wi_info_intr(struct wi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_if;
int i, fid, len, off;
u_int16_t ltbuf[2];
u_int16_t stat;
@@ -1676,7 +1705,7 @@
static int
wi_write_multi(struct wi_softc *sc)
{
- struct ifnet *ifp = &sc->sc_ic.ic_if;
+ struct ifnet *ifp = &sc->sc_if;
int n;
struct ifmultiaddr *ifma;
struct wi_mcast mlist;
@@ -1827,7 +1856,7 @@
case WI_RID_TX_CRYPT_KEY:
case WI_RID_DEFLT_CRYPT_KEYS:
case WI_RID_TX_RATE:
- return ieee80211_cfgget(ifp, cmd, data, cr);
+ return ieee80211_cfgget(ic, cmd, data, cr);
case WI_RID_MICROWAVE_OVEN:
if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) {
@@ -1881,7 +1910,7 @@
case WI_RID_READ_APS:
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
- return ieee80211_cfgget(ifp, cmd, data, cr);
+ return ieee80211_cfgget(ic, cmd, data, cr);
if (sc->sc_scan_timer > 0) {
error = EINPROGRESS;
break;
@@ -1918,11 +1947,11 @@
break;
case WI_RID_READ_CACHE:
- return ieee80211_cfgget(ifp, cmd, data, cr);
+ return ieee80211_cfgget(ic, cmd, data, cr);
case WI_RID_SCAN_RES: /* compatibility interface */
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
- return ieee80211_cfgget(ifp, cmd, data, cr);
+ return ieee80211_cfgget(ic, cmd, data, cr);
if (sc->sc_scan_timer > 0) {
error = EINPROGRESS;
break;
@@ -2004,7 +2033,7 @@
sc->sc_nodelen);
break;
default:
- return ieee80211_cfgget(ifp, cmd, data, cr);
+ return ieee80211_cfgget(ic, cmd, data, cr);
}
break;
}
@@ -2024,6 +2053,7 @@
struct mbuf *m;
int i, len, error, mif, val;
struct ieee80211_rateset *rs;
+ WI_LOCK_DECL();
error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
if (error)
@@ -2039,20 +2069,23 @@
error = ENOSPC;
break;
}
- if (sc->sc_enabled) {
+ WI_LOCK(sc);
+ if (sc->sc_enabled)
error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
len);
- if (error)
- break;
+ if (error == 0) {
+ sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2;
+ memcpy(sc->sc_nodename, &wreq.wi_val[1],
+ sc->sc_nodelen);
}
- sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2;
- memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen);
+ WI_UNLOCK(sc);
break;
case WI_RID_MICROWAVE_OVEN:
case WI_RID_ROAMING_MODE:
case WI_RID_SYSTEM_SCALE:
case WI_RID_FRAG_THRESH:
+ /* XXX unlocked reads */
if (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
(sc->sc_flags & WI_FLAGS_HAS_MOR) == 0)
break;
@@ -2069,11 +2102,14 @@
case WI_RID_RTS_THRESH:
case WI_RID_CNFAUTHMODE:
case WI_RID_MAX_DATALEN:
+ WI_LOCK(sc);
if (sc->sc_enabled) {
error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
sizeof(u_int16_t));
- if (error)
+ if (error != 0) {
+ WI_UNLOCK(sc);
break;
+ }
}
switch (wreq.wi_type) {
case WI_RID_FRAG_THRESH:
@@ -2098,9 +2134,11 @@
sc->sc_max_datalen = le16toh(wreq.wi_val[0]);
break;
}
+ WI_UNLOCK(sc);
break;
case WI_RID_TX_RATE:
+ WI_LOCK(sc);
switch (le16toh(wreq.wi_val[0])) {
case 3:
ic->ic_fixed_rate = -1;
@@ -2112,46 +2150,56 @@
/ 2 == le16toh(wreq.wi_val[0]))
break;
}
- if (i == rs->rs_nrates)
+ if (i == rs->rs_nrates) {
+ WI_UNLOCK(sc);
return EINVAL;
+ }
ic->ic_fixed_rate = i;
}
if (sc->sc_enabled)
error = wi_write_txrate(sc);
+ WI_UNLOCK(sc);
break;
case WI_RID_SCAN_APS:
+ WI_LOCK(sc);
if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP)
error = wi_scan_ap(sc, 0x3fff, 0x000f);
+ WI_UNLOCK(sc);
break;
case WI_RID_SCAN_REQ: /* compatibility interface */
+ WI_LOCK(sc);
if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP)
error = wi_scan_ap(sc, wreq.wi_val[0], wreq.wi_val[1]);
+ WI_UNLOCK(sc);
break;
case WI_RID_MGMT_XMIT:
- if (!sc->sc_enabled) {
+ WI_LOCK(sc);
+ if (!sc->sc_enabled)
error = ENETDOWN;
- break;
- }
- if (ic->ic_mgtq.ifq_len > 5) {
+ else if (ic->ic_mgtq.ifq_len > 5)
error = EAGAIN;
- break;
- }
- /* XXX wi_len looks in u_int8_t, not in u_int16_t */
- m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0, ifp, NULL);
- if (m == NULL) {
- error = ENOMEM;
- break;
+ else {
+ /* NB: m_devget uses M_DONTWAIT so can hold the lock */
+ /* XXX wi_len looks in u_int8_t, not in u_int16_t */
+ m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0,
+ ifp, NULL);
+ if (m != NULL) {
+ IF_ENQUEUE(&ic->ic_mgtq, m);
+ } else
+ error = ENOMEM;
}
- IF_ENQUEUE(&ic->ic_mgtq, m);
+ WI_UNLOCK(sc);
break;
case WI_RID_MIF:
mif = wreq.wi_val[0];
val = wreq.wi_val[1];
+ WI_LOCK(sc);
error = wi_cmd(sc, WI_CMD_WRITEMIF, mif, val, 0);
+ WI_UNLOCK(sc);
break;
case WI_RID_PROCFRAME: /* ignore for compatibility */
@@ -2163,20 +2211,30 @@
error = ENOSPC;
break;
}
+ WI_LOCK(sc);
memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
- error = ENETRESET;
+ if (sc->sc_enabled)
+ wi_init(sc); /* XXX no error return */
+ WI_UNLOCK(sc);
break;
default:
- if (sc->sc_enabled) {
+ WI_LOCK(sc);
+ if (sc->sc_enabled)
error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
len);
- if (error)
- break;
+ if (error == 0) {
+ /* XXX ieee80211_cfgset does a copyin */
+ error = ieee80211_cfgset(ic, cmd, data);
+ if (error == ENETRESET) {
+ if (sc->sc_enabled)
+ wi_init(sc);
+ error = 0;
+ }
}
- error = ieee80211_cfgset(ifp, cmd, data);
+ WI_UNLOCK(sc);
break;
}
return error;
@@ -2248,16 +2306,18 @@
switch (sc->sc_firmware_type) {
case WI_LUCENT:
- val = (ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0;
+ val = (ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0;
error = wi_write_val(sc, WI_RID_ENCRYPTION, val);
if (error)
break;
- error = wi_write_val(sc, WI_RID_TX_CRYPT_KEY, ic->ic_wep_txkey);
+ if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
+ break;
+ error = wi_write_val(sc, WI_RID_TX_CRYPT_KEY, ic->ic_def_txkey);
if (error)
break;
memset(wkey, 0, sizeof(wkey));
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- keylen = ic->ic_nw_keys[i].wk_len;
+ keylen = ic->ic_nw_keys[i].wk_keylen;
wkey[i].wi_keylen = htole16(keylen);
memcpy(wkey[i].wi_keydat, ic->ic_nw_keys[i].wk_key,
keylen);
@@ -2268,7 +2328,7 @@
case WI_INTERSIL:
case WI_SYMBOL:
- if (ic->ic_flags & IEEE80211_F_WEPON) {
+ if (ic->ic_flags & IEEE80211_F_PRIVACY) {
/*
* ONLY HWB3163 EVAL-CARD Firmware version
* less than 0.8 variant2
@@ -2300,17 +2360,24 @@
error = wi_write_val(sc, WI_RID_P2_ENCRYPTION, val);
if (error)
break;
+ if ((val & PRIVACY_INVOKED) == 0)
+ break;
error = wi_write_val(sc, WI_RID_P2_TX_CRYPT_KEY,
- ic->ic_wep_txkey);
+ ic->ic_def_txkey);
if (error)
break;
+ if (val & HOST_DECRYPT)
+ break;
/*
* It seems that the firmware accept 104bit key only if
* all the keys have 104bit length. We get the length of
* the transmit key and use it for all other keys.
* Perhaps we should use software WEP for such situation.
*/
- keylen = ic->ic_nw_keys[ic->ic_wep_txkey].wk_len;
+ if (ic->ic_def_txkey != IEEE80211_KEYIX_NONE)
+ keylen = ic->ic_nw_keys[ic->ic_def_txkey].wk_keylen;
+ else /* XXX should not hapen */
+ keylen = IEEE80211_WEP_KEYLEN;
if (keylen > IEEE80211_WEP_KEYLEN)
keylen = 13; /* 104bit keys */
else
@@ -2537,12 +2604,13 @@
for (i = 0; i < WI_TIMEOUT; i++) {
if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
break;
- if (i == WI_TIMEOUT) {
- if_printf(&sc->sc_ic.ic_if, "timeout in alloc\n");
- return ETIMEDOUT;
- }
DELAY(1);
}
+ if (i == WI_TIMEOUT) {
+ device_printf(sc->sc_dev, "timeout in alloc\n");
+ return ETIMEDOUT;
+ }
+
*idp = CSR_READ_2(sc, WI_ALLOC_FID);
CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
return 0;
@@ -2601,7 +2669,7 @@
static int
wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = ic->ic_ifp;
struct wi_softc *sc = ifp->if_softc;
struct ieee80211_node *ni = ic->ic_bss;
int buflen;
@@ -2613,40 +2681,53 @@
ieee80211_state_name[ic->ic_state],
ieee80211_state_name[nstate]));
+ /*
+ * Internal to the driver the INIT and RUN states are used
+ * so bypass the net80211 state machine for other states.
+ * Beware however that this requires use to net80211 state
+ * management that otherwise would be handled for us.
+ */
switch (nstate) {
case IEEE80211_S_INIT:
- ic->ic_flags &= ~IEEE80211_F_SIBSS;
sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
return (*sc->sc_newstate)(ic, nstate, arg);
+ case IEEE80211_S_SCAN:
+ case IEEE80211_S_AUTH:
+ case IEEE80211_S_ASSOC:
+ ic->ic_state = nstate; /* NB: skip normal ieee80211 handling */
+ break;
+
case IEEE80211_S_RUN:
+ ni = ic->ic_bss;
sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
buflen = IEEE80211_ADDR_LEN;
+ IEEE80211_ADDR_COPY(old_bssid, ni->ni_bssid);
wi_read_rid(sc, WI_RID_CURRENT_BSSID, ni->ni_bssid, &buflen);
IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
buflen = sizeof(val);
wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen);
/* XXX validate channel */
ni->ni_chan = &ic->ic_channels[le16toh(val)];
+ ic->ic_ibss_chan = ni->ni_chan;
sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
htole16(ni->ni_chan->ic_freq);
sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
htole16(ni->ni_chan->ic_flags);
- if (IEEE80211_ADDR_EQ(old_bssid, ni->ni_bssid))
- sc->sc_false_syns++;
- else
- sc->sc_false_syns = 0;
-
- if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
- ni->ni_esslen = ic->ic_des_esslen;
- memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
- ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];
- ni->ni_intval = ic->ic_lintval;
- ni->ni_capinfo = IEEE80211_CAPINFO_ESS;
- if (ic->ic_flags & IEEE80211_F_WEPON)
- ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
- } else {
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
+ /*
+ * XXX hack; unceremoniously clear
+ * IEEE80211_F_DROPUNENC when operating with
+ * wep enabled so we don't drop unencoded frames
+ * at the 802.11 layer. This is necessary because
+ * we must strip the WEP bit from the 802.11 header
+ * before passing frames to ieee80211_input because
+ * the card has already stripped the WEP crypto
+ * header from the packet.
+ */
+ if (ic->ic_flags & IEEE80211_F_PRIVACY)
+ ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
/* XXX check return value */
buflen = sizeof(ssid);
wi_read_rid(sc, WI_RID_CURRENT_SSID, &ssid, &buflen);
@@ -2655,15 +2736,8 @@
ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/
memcpy(ni->ni_essid, ssid.wi_ssid, ni->ni_esslen);
}
- break;
-
- case IEEE80211_S_SCAN:
- case IEEE80211_S_AUTH:
- case IEEE80211_S_ASSOC:
- break;
+ return (*sc->sc_newstate)(ic, nstate, arg);
}
-
- ic->ic_state = nstate; /* NB: skip normal ieee80211 handling */
return 0;
}
@@ -2680,8 +2754,8 @@
(void)wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
break;
case WI_INTERSIL:
- val[0] = chanmask; /* channel */
- val[1] = txrate; /* tx rate */
+ val[0] = htole16(chanmask); /* channel */
+ val[1] = htole16(txrate); /* tx rate */
error = wi_write_rid(sc, WI_RID_SCAN_REQ, val, sizeof(val));
break;
case WI_SYMBOL:
@@ -2695,7 +2769,7 @@
}
if (error == 0) {
sc->sc_scan_timer = WI_SCAN_WAIT;
- sc->sc_ic.ic_if.if_timer = 1;
+ sc->sc_if.if_timer = 1;
DPRINTF((&sc->sc_ic.ic_if, "wi_scan_ap: start scanning, "
"chamask 0x%x txrate 0x%x\n", chanmask, txrate));
}
diff -N -u -r src.preview/sys/dev/netif/wi/if_wi_pccard.c src/sys/dev/netif/wi/if_wi_pccard.c
--- src.preview/sys/dev/netif/wi/if_wi_pccard.c 2005-06-30 13:11:28.000000000 -0400
+++ src/sys/dev/netif/wi/if_wi_pccard.c 2005-09-23 11:24:22.000000000 -0400
@@ -137,8 +137,11 @@
PCMCIA_CARD(GEMTEK, WLAN, 0),
PCMCIA_CARD(HWN, AIRWAY80211, 0),
PCMCIA_CARD(INTEL, PRO_WLAN_2011, 0),
- PCMCIA_CARD(INTERSIL, MA401RA, 0),
- PCMCIA_CARD(INTERSIL, DWL650, 0),
+#if 0
+ PCMCIA_CARD(INTERSIL, ISL37100P, 0),
+ PCMCIA_CARD(INTERSIL, ISL37110P, 0),
+ PCMCIA_CARD(INTERSIL, ISL37300P, 0),
+#endif
PCMCIA_CARD(INTERSIL2, PRISM2, 0),
PCMCIA_CARD(IODATA2, WCF12, 0),
PCMCIA_CARD(IODATA2, WNB11PCM, 0),
@@ -147,7 +150,9 @@
PCMCIA_CARD(MICROSOFT, MN_520, 0),
PCMCIA_CARD(NOKIA, C020_WLAN, 0),
PCMCIA_CARD(NOKIA, C110_WLAN, 0),
- PCMCIA_CARD(PLANEX_2, GWNS11H, 0),
+#if 0
+ PCMCIA_CARD(PLANEX, GWNS11H, 0),
+#endif
PCMCIA_CARD(PROXIM, HARMONY, 0),
PCMCIA_CARD(PROXIM, RANGELANDS_8430, 0),
PCMCIA_CARD(SAMSUNG, SWL_2000N, 0),
@@ -164,7 +169,7 @@
device_t dev;
{
const struct pccard_product *pp;
- u_int32_t fcn;
+ u_int32_t fcn = PCCARD_FUNCTION_UNSPEC;
/* Make sure we're a network driver */
fcn = pccard_get_function(dev);
@@ -195,12 +200,12 @@
if (error)
return (error);
- wi_free(dev);
-
/* Make sure interrupts are disabled. */
CSR_WRITE_2(sc, WI_INT_EN, 0);
CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
+ wi_free(dev);
+
return (0);
}
@@ -233,6 +238,7 @@
spectrum24t_primsym, sizeof(spectrum24t_primsym),
spectrum24t_secsym, sizeof(spectrum24t_secsym))) {
device_printf(dev, "couldn't load firmware\n");
+ return (ENXIO);
}
#else
device_printf(dev,
diff -N -u -r src.preview/sys/dev/netif/wi/if_wi_pci.c src/sys/dev/netif/wi/if_wi_pci.c
--- src.preview/sys/dev/netif/wi/if_wi_pci.c 2005-06-30 13:11:28.000000000 -0400
+++ src/sys/dev/netif/wi/if_wi_pci.c 2005-09-23 11:24:22.000000000 -0400
@@ -238,10 +238,9 @@
static int
wi_pci_suspend(device_t dev)
{
- struct wi_softc *sc;
- struct ifnet *ifp;
- sc = device_get_softc(dev);
- ifp = &sc->sc_if;
+ struct wi_softc *sc = device_get_softc(dev);
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = ic->ic_ifp;
wi_stop(ifp, 1);
@@ -251,10 +250,9 @@
static int
wi_pci_resume(device_t dev)
{
- struct wi_softc *sc;
- struct ifnet *ifp;
- sc = device_get_softc(dev);
- ifp = &sc->sc_if;
+ struct wi_softc *sc = device_get_softc(dev);
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = ic->ic_ifp;
if (sc->wi_bus_type != WI_BUS_PCI_NATIVE)
return (0);
diff -N -u -r src.preview/sys/dev/netif/wi/if_wivar.h src/sys/dev/netif/wi/if_wivar.h
--- src.preview/sys/dev/netif/wi/if_wivar.h 2005-06-30 11:57:27.000000000 -0400
+++ src/sys/dev/netif/wi/if_wivar.h 2005-09-23 11:24:22.000000000 -0400
@@ -60,7 +60,10 @@
#define WI_RID_ROAMING_MODE 0xFC2D
#define WI_RID_CUR_TX_RATE 0xFD44 /* current TX rate */
+#define WI_MAX_AID 256 /* max stations for ap operation */
+
struct wi_softc {
+ struct arpcom sc_arp;
struct ieee80211com sc_ic;
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
@@ -156,6 +159,7 @@
u_int16_t wi_confbits_param0;
} wi_debug;
+ struct timeval sc_last_syn;
int sc_false_syns;
u_int16_t sc_txbuf[IEEE80211_MAX_LEN/2];
@@ -171,7 +175,7 @@
} u_rx_rt;
int sc_rx_th_len;
};
-#define sc_if sc_ic.ic_if
+#define sc_if sc_arp.ac_if
#define sc_tx_th u_tx_rt.th
#define sc_rx_th u_rx_rt.th
diff -N -u -r src.preview/sys/dev/usbmisc/umass/umass.c src/sys/dev/usbmisc/umass/umass.c
--- src.preview/sys/dev/usbmisc/umass/umass.c 2004-12-18 01:22:48.000000000 -0500
+++ src/sys/dev/usbmisc/umass/umass.c 2005-09-23 11:24:22.000000000 -0400
@@ -407,6 +407,10 @@
UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I,
FORCE_SHORT_INQUIRY
},
+ { USB_VENDOR_IRIVER, USB_PRODUCT_IRIVER_IFP_1XX, RID_WILDCARD,
+ UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
+ IGNORE_RESIDUE | NO_GETMAXLUN | RS_NO_CLEAR_UA
+ },
{ VID_EOT, PID_EOT, RID_EOT, 0, 0 }
};
diff -N -u -r src.preview/sys/i386/conf/AB-MOBILE-FAST_IPSEC src/sys/i386/conf/AB-MOBILE-FAST_IPSEC
--- src.preview/sys/i386/conf/AB-MOBILE-FAST_IPSEC 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/i386/conf/AB-MOBILE-FAST_IPSEC 2005-09-23 11:59:42.000000000 -0400
@@ -0,0 +1,194 @@
+#
+# GENERIC -- Generic kernel configuration file for DragonFly/i386
+#
+# Check the LINT configuration file in sys/i386/conf, for an
+# exhaustive list of options.
+#
+# $DragonFly: src/sys/i386/conf/GENERIC,v 1.20 2004/09/26 01:52:48 dillon Exp $
+
+machine i386
+cpu I686_CPU
+ident AB-MOBILE
+maxusers 0
+
+makeoptions DEBUG=-gstabs+ #Build kernel with gdb(1) debug symbols
+
+options INCLUDE_CONFIG_FILE
+
+options INET #InterNETworking
+options INET6 #IPv6 communications protocols
+options FAST_IPSEC #new IPsec
+
+#options IPSEC #IP security
+#options IPSEC_ESP #IP security (crypto; define w/ IPSEC)
+#options IPSEC_DEBUG #debug for IP security
+
+options FFS #Berkeley Fast Filesystem
+options FFS_ROOT #FFS usable as root device [keep this!]
+options SOFTUPDATES #Enable FFS soft updates support
+options UFS_DIRHASH #Improve performance on big directories
+options MFS #Memory Filesystem
+options MD_ROOT #MD is a potential root device
+options NFS #Network Filesystem
+options NFS_ROOT #NFS usable as root device, NFS required
+options MSDOSFS #MSDOS Filesystem
+options CD9660 #ISO 9660 Filesystem
+options CD9660_ROOT #CD-ROM usable as root, CD9660 required
+options PROCFS #Process filesystem
+options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
+options COMPAT_LINUX #Compatible with BSD 4.3 [KEEP THIS!]
+options COMPAT_DF12 #Compatible with DragonFly 1.2 and earlier
+options DEBUG_LINUX #Compatible with BSD 4.3 [KEEP THIS!]
+options UCONSOLE #Allow users to grab the console
+options USERCONFIG #boot -c editor
+options VISUAL_USERCONFIG #visual boot -c editor
+options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options P1003_1B #Posix P1003_1B real-time extensions
+options _KPOSIX_PRIORITY_SCHEDULING
+options ICMP_BANDLIM #Rate limit bad replies
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+
+# To make an SMP kernel, the next two are needed
+# options SMP # Symmetric MultiProcessor Kernel
+# options APIC_IO # Symmetric (APIC) I/O
+
+# Debugging for Development
+options DDB
+options DDB_TRACE
+options INVARIANTS
+options INVARIANT_SUPPORT
+
+device isa
+device eisa
+device pci
+
+# Floppy drives
+#device fdc0 at isa? port IO_FD1 irq 6 drq 2
+#device fd0 at fdc0 drive 0
+#device fd1 at fdc0 drive 1
+#
+# If you have a Toshiba Libretto with its Y-E Data PCMCIA floppy,
+# don't use the above line for fdc0 but the following one:
+#device fdc0
+
+# ATA and ATAPI devices
+device ata0 at isa? port IO_WD1 irq 14
+device ata1 at isa? port IO_WD2 irq 15
+device ata
+device atadisk # ATA disk drives
+device atapicd # ATAPI CDROM drives
+device atapifd # ATAPI floppy drives
+device atapist # ATAPI tape drives
+device atapicam # Emulate ATAPI devices as SCSI via CAM
+options ATA_STATIC_ID #Static device numbering
+
+# SCSI peripherals
+device scbus # SCSI bus (required)
+device da # Direct Access (disks)
+device sa # Sequential Access (tape etc)
+device cd # CD
+device pass # Passthrough device (direct SCSI access)
+
+# atkbdc0 controls both the keyboard and the PS/2 mouse
+device atkbdc0 at isa? port IO_KBD
+device atkbd0 at atkbdc? irq 1 flags 0x1
+device psm0 at atkbdc? irq 12
+
+device vga0 at isa?
+
+# splash screen/screen saver
+pseudo-device splash
+
+# syscons is the default console driver, resembling an SCO console
+device sc0 at isa? flags 0x100
+
+# Enable this and PCVT_FREEBSD for pcvt vt220 compatible console driver
+#device vt0 at isa?
+#options XSERVER # support for X server on a vt console
+#options FAT_CURSOR # start with block cursor
+# If you have a ThinkPAD, uncomment this along with the rest of the PCVT lines
+#options PCVT_SCANSET=2 # IBM keyboards are non-std
+
+#device agp # support several AGP chipsets
+
+# Floating point support - do not disable.
+device npx0 at nexus? port IO_NPX irq 13
+
+# Power management support (see LINT for more options)
+device apm0 at nexus? disable flags 0x20 # Advanced Power Management
+
+# PCCARD (PCMCIA) support
+device pccard
+device cardbus
+device cbb
+
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device miibus # MII bus support
+device bfe # Broadcom BCM440x 10/100 Ethernet
+
+# Generic 802.11 stack, used by wi
+device wlan
+options WLCACHE # enables the signal-strength cache
+options WLDEBUG # enables verbose debugging output
+
+# Pseudo devices - the number indicates how many units to allocate.
+pseudo-device loop # Network loopback
+pseudo-device ether # Ethernet support
+pseudo-device sl 1 # Kernel SLIP
+pseudo-device ppp 2 # Kernel PPP
+pseudo-device tun # Packet tunnel.
+pseudo-device pty # Pseudo-ttys (telnet etc)
+pseudo-device md # Memory "disks"
+pseudo-device gif # IPv6 and IPv4 tunneling
+pseudo-device faith 1 # IPv6-to-IPv4 relaying (translation)
+
+# The `bpf' pseudo-device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+pseudo-device bpf #Berkeley packet filter
+
+pseudo-device crypto # core crypto support, used by wlan
+pseudo-device cryptodev # /dev/crypto for access to h/w
+
+# USB support
+# USB support
+#device ehci # UHCI PCI->USB interface
+device uhci # UHCI PCI->USB interface
+#device ohci # OHCI PCI->USB interface
+device usb # USB Bus (required)
+device uplcom # Generic
+device ugen # Generic
+device ukbd # Keyboard
+device umass # Disks/Mass storage - Requires scbus and da
+device ums # Mouse
+options USB_DEBUG
+
+# FireWire support
+device firewire # FireWire bus code
+device sbp # SCSI over FireWire (Requires scbus and da)
+device fwe # Ethernet over FireWire (non-standard!)
+device dcons # dumb console driver
+device dcons_crom # FireWire attachment
+options ALT_BREAK_TO_DEBUGGER
+
+device pcm
+device snd
+
+device pf
+device pfsync
+device pflog
+
+options ALTQ #alternate queueing
+options ALTQ_CBQ #class based queueing
+options ALTQ_RED #random early detection
+options ALTQ_RIO #triple red for diffserv (needs RED)
+options ALTQ_HFSC #hierarchical fair service curve
+options ALTQ_PRIQ #priority queue
+#options ALTQ_NOPCC #don't use processor cycle counter
+options ALTQ_DEBUG #for debugging
+
+
diff -N -u -r src.preview/sys/i386/conf/WRAP-AUTO src/sys/i386/conf/WRAP-AUTO
--- src.preview/sys/i386/conf/WRAP-AUTO 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/i386/conf/WRAP-AUTO 2005-09-23 11:24:22.000000000 -0400
@@ -0,0 +1,129 @@
+#
+# GENERIC -- Generic kernel configuration file for DragonFly/i386
+#
+# Check the LINT configuration file in sys/i386/conf, for an
+# exhaustive list of options.
+#
+# $DragonFly: src/sys/i386/conf/GENERIC,v 1.20 2004/09/26 01:52:48 dillon Exp $
+
+machine i386
+cpu I586_CPU
+ident WRAP-AUTO
+maxusers 0
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+
+options INCLUDE_CONFIG_FILE
+
+options INET #InterNETworking
+options INET6 #IPv6 communications protocols
+options FAST_IPSEC #new IPsec
+
+options NO_F00F_HACK
+
+options FFS #Berkeley Fast Filesystem
+options FFS_ROOT #FFS usable as root device [keep this!]
+
+options SOFTUPDATES #Enable FFS soft updates support
+options UFS_DIRHASH #Improve performance on big directories
+
+options MFS #Memory Filesystem
+options MD_ROOT #MD is a potential root device
+options NFS #Network Filesystem
+options NFS_ROOT #NFS usable as root device, NFS required
+options MSDOSFS #MSDOS Filesystem
+options CD9660 #ISO 9660 Filesystem
+options CD9660_ROOT #CD-ROM usable as root, CD9660 required
+options PROCFS #Process filesystem
+options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
+options COMPAT_LINUX #Compatible with BSD 4.3 [KEEP THIS!]
+options DEBUG_LINUX #Compatible with BSD 4.3 [KEEP THIS!]
+options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options P1003_1B #Posix P1003_1B real-time extensions
+options _KPOSIX_PRIORITY_SCHEDULING
+options ICMP_BANDLIM #Rate limit bad replies
+
+options NO_SWAPPING
+
+# Debugging for Development
+options DDB
+options DDB_TRACE
+options DDB_UNATTENDED
+options INVARIANTS
+options INVARIANT_SUPPORT
+
+device isa
+device pci
+
+# ATA and ATAPI devices
+device ata0 at isa? port IO_WD1 irq 14
+device ata1 at isa? port IO_WD2 irq 15
+device ata
+device atadisk # ATA disk drives
+device atapicd # ATAPI CDROM drives
+device atapifd # ATAPI floppy drives
+device atapist # ATAPI tape drives
+device atapicam # Emulate ATAPI devices as SCSI via CAM
+options ATA_STATIC_ID #Static device numbering
+
+# SCSI peripherals
+device scbus # SCSI bus (required)
+device da # Direct Access (disks)
+device sa # Sequential Access (tape etc)
+device cd # CD
+device pass # Passthrough device (direct SCSI access)
+
+device sio0 at isa? port IO_COM1 flags 0x30 irq 4
+
+# Floating point support - do not disable.
+device npx0 at nexus? port IO_NPX irq 13
+
+# Power management support (see LINT for more options)
+device apm0 at nexus? disable flags 0x20 # Advanced Power Management
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device miibus # MII bus support
+device sis
+
+# Generic 802.11 stack, used by wi
+device wlan
+options WLCACHE # enables the signal-strength cache
+options WLDEBUG # enables verbose debugging output
+
+# Pseudo devices - the number indicates how many units to allocate.
+pseudo-device loop # Network loopback
+pseudo-device ether # Ethernet support
+pseudo-device sl 1 # Kernel SLIP
+pseudo-device ppp 1 # Kernel PPP
+pseudo-device tun # Packet tunnel.
+pseudo-device pty # Pseudo-ttys (telnet etc)
+pseudo-device md # Memory "disks"
+pseudo-device gif # IPv6 and IPv4 tunneling
+pseudo-device faith 1 # IPv6-to-IPv4 relaying (translation)
+
+# The `bpf' pseudo-device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+pseudo-device bpf #Berkeley packet filter
+
+pseudo-device crypto # core crypto support, used by wlan
+pseudo-device cryptodev # /dev/crypto for access to h/w
+
+device pf
+device pfsync
+device pflog
+
+options ALTQ #alternate queueing
+options ALTQ_CBQ #class based queueing
+options ALTQ_RED #random early detection
+options ALTQ_RIO #triple red for diffserv (needs RED)
+options ALTQ_HFSC #hierarchical fair service curve
+options ALTQ_PRIQ #priority queue
+#options ALTQ_NOPCC #don't use processor cycle counter
+options ALTQ_DEBUG #for debugging
+
+options BROKEN_KEYBOARD_RESET
+
diff -N -u -r src.preview/sys/i386/i386/identcpu.c src/sys/i386/i386/identcpu.c
--- src.preview/sys/i386/i386/identcpu.c 2004-04-29 15:43:35.000000000 -0400
+++ src/sys/i386/i386/identcpu.c 2005-09-23 11:24:22.000000000 -0400
@@ -151,7 +151,8 @@
(strcmp(cpu_vendor, "GenuineIntel") == 0 ||
strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
- strcmp(cpu_vendor, "TransmetaCPU") == 0)) {
+ strcmp(cpu_vendor, "TransmetaCPU") == 0 ||
+ strcmp(cpu_vendor, "Geode by NSC") == 0)) {
do_cpuid(0x80000000, regs);
if (regs[0] >= 0x80000000) {
cpu_exthigh = regs[0];
@@ -532,6 +533,17 @@
}
} else if (strcmp(cpu_vendor, "IBM") == 0) {
strcpy(cpu_model, "Blue Lightning CPU");
+ } else if (strcmp(cpu_vendor, "Geode by NSC") == 0) {
+ switch (cpu_id & 0xfff) {
+ case 0x540:
+ strcpy(cpu_model, "Geode SC1100");
+ cpu = CPU_GEODE1100;
+ tsc_is_broken = 1;
+ break;
+ default:
+ strcpy(cpu_model, "Geode/NSC unknown");
+ break;
+ }
}
/*
@@ -592,6 +604,7 @@
strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
strcmp(cpu_vendor, "RiseRiseRise") == 0 ||
strcmp(cpu_vendor, "CentaurHauls") == 0 ||
+ strcmp(cpu_vendor, "Geode by NSC") == 0 ||
((strcmp(cpu_vendor, "CyrixInstead") == 0) &&
((cpu_id & 0xf00) > 0x500))) {
printf(" Stepping = %u", cpu_id & 0xf);
diff -N -u -r src.preview/sys/i386/i386/vm_machdep.c src/sys/i386/i386/vm_machdep.c
--- src.preview/sys/i386/i386/vm_machdep.c 2005-06-16 17:12:44.000000000 -0400
+++ src/sys/i386/i386/vm_machdep.c 2005-09-23 11:24:22.000000000 -0400
@@ -60,6 +60,7 @@
#include <machine/clock.h>
#include <machine/cpu.h>
+#include <machine/cputypes.h>
#include <machine/md_var.h>
#ifdef SMP
#include <machine/smp.h>
@@ -461,6 +462,18 @@
static void
cpu_reset_real()
{
+
+ if ( cpu == CPU_GEODE1100 ) {
+ int i = 50;
+ while(i--) {
+ outl(0xcf8, 0x80009044ul);
+ outb(0xcfc, 0xf);
+ DELAY(100000); /* wait 0.1 sec */
+ }
+ printf("GEODE reset failed, attempting CPU shutdown\n");
+ DELAY(1000000); /* wait 1 sec for printf to complete */
+ }
+
/*
* Attempt to do a CPU reset via the keyboard controller,
* do not turn of the GateA20, as any machine that fails
diff -N -u -r src.preview/sys/i386/include/cputypes.h src/sys/i386/include/cputypes.h
--- src.preview/sys/i386/include/cputypes.h 2003-06-17 00:28:35.000000000 -0400
+++ src/sys/i386/include/cputypes.h 2005-09-23 11:24:22.000000000 -0400
@@ -60,6 +60,7 @@
#define CPU_PII 14 /* Intel Pentium II */
#define CPU_PIII 15 /* Intel Pentium III */
#define CPU_P4 16 /* Intel Pentium 4 */
+#define CPU_GEODE1100 17 /* NS Geode SC1100 */
#ifndef LOCORE
struct cpu_nameclass {
diff -N -u -r src.preview/sys/net/altq/altq_subr.c src/sys/net/altq/altq_subr.c
--- src.preview/sys/net/altq/altq_subr.c 2005-06-03 14:20:36.000000000 -0400
+++ src/sys/net/altq/altq_subr.c 2005-09-23 11:24:22.000000000 -0400
@@ -151,9 +151,10 @@
return 0;
crit_enter();
+
ifq_purge(ifq);
KKASSERT(ifq->ifq_len == 0);
- ifq->altq_flags |= ALTQF_ENABLED;
if (ifq->altq_clfier != NULL)
ifq->altq_flags |= ALTQF_CLASSIFY;
crit_exit();
diff -N -u -r src.preview/sys/net/altq/if_altq.h src/sys/net/altq/if_altq.h
--- src.preview/sys/net/altq/if_altq.h 2005-02-11 17:25:57.000000000 -0500
+++ src/sys/net/altq/if_altq.h 2005-09-23 11:24:22.000000000 -0400
@@ -41,6 +41,7 @@
int ifq_len;
int ifq_maxlen;
int ifq_drops;
+ struct lwkt_token ifq_mtx;
/* alternate queueing related fields */
int altq_type; /* discipline type */
diff -N -u -r src.preview/sys/net/ethernet.h src/sys/net/ethernet.h
--- src.preview/sys/net/ethernet.h 2005-02-11 17:25:57.000000000 -0500
+++ src/sys/net/ethernet.h 2005-09-23 11:24:22.000000000 -0400
@@ -326,6 +326,7 @@
#define ETHERTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */
#define ETHERTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */
#define ETHERTYPE_LANPROBE 0x8888 /* HP LanProbe test? */
+#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */
#define ETHERTYPE_LOOPBACK 0x9000 /* Loopback: used to test interfaces */
#define ETHERTYPE_LBACK ETHERTYPE_LOOPBACK /* DEC MOP loopback */
#define ETHERTYPE_XNSSM 0x9001 /* 3Com (Formerly Bridge Communications), XNS Systems Management */
@@ -348,6 +349,7 @@
#define ETHERMTU (ETHER_MAX_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
#define ETHERMIN (ETHER_MIN_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define ETHERMTU_JUMBO (ETHER_MAX_LEN_JUMBO - ETHER_HDR_LEN - ETHER_CRC_LEN)
#ifdef _KERNEL
diff -N -u -r src.preview/sys/net/if.h src/sys/net/if.h
--- src.preview/sys/net/if.h 2005-05-25 10:59:05.000000000 -0400
+++ src/sys/net/if.h 2005-09-23 11:24:22.000000000 -0400
@@ -142,6 +142,9 @@
#define IFF_MULTICAST 0x8000 /* supports multicast */
#define IFF_POLLING 0x10000 /* Interface is in polling mode. */
#define IFF_PPROMISC 0x20000 /* user-requested promisc mode */
+#define IFF_MONITOR 0x40000 /* user-requested monitor mode */
+#define IFF_STATICARP 0x80000 /* static ARP */
+#define IFF_NEEDSGIANT 0x100000 /* hold Giant over if_start calls */
/* flags set internally only: */
#define IFF_CANTCHANGE \
diff -N -u -r src.preview/sys/net/if_media.h src/sys/net/if_media.h
--- src.preview/sys/net/if_media.h 2005-02-14 11:21:34.000000000 -0500
+++ src/sys/net/if_media.h 2005-09-23 11:24:22.000000000 -0400
@@ -205,6 +205,24 @@
#define IFM_IEEE80211_FH 0x00040000 /* 2Ghz, GFSK mode */
/*
+ * ATM
+ */
+#define IFM_ATM 0x000000a0
+#define IFM_ATM_UNKNOWN 3
+#define IFM_ATM_UTP_25 4
+#define IFM_ATM_TAXI_100 5
+#define IFM_ATM_TAXI_140 6
+#define IFM_ATM_MM_155 7
+#define IFM_ATM_SM_155 8
+#define IFM_ATM_UTP_155 9
+#define IFM_ATM_MM_622 10
+#define IFM_ATM_SM_622 11
+#define IFM_ATM_VIRTUAL 12
+#define IFM_ATM_SDH 0x00000100 /* SDH instead of SONET */
+#define IFM_ATM_NOSCRAMB 0x00000200 /* no scrambling */
+#define IFM_ATM_UNASSIGNED 0x00000400 /* unassigned cells */
+
+/*
* Shared media sub-types
*/
#define IFM_AUTO 0 /* Autoselect best media */
@@ -429,6 +447,56 @@
{ 0, NULL }, \
}
+#define IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS { \
+ { IFM_AUTO, "autoselect" }, \
+ { IFM_IEEE80211_11A, "11a" }, \
+ { IFM_IEEE80211_11B, "11b" }, \
+ { IFM_IEEE80211_11G, "11g" }, \
+ { IFM_IEEE80211_FH, "fh" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_IEEE80211_MODE_ALIASES { \
+ { IFM_AUTO, "auto" }, \
+ { 0, NULL }, \
+}
+
+# define IFM_SUBTYPE_ATM_DESCRIPTIONS { \
+ { IFM_ATM_UNKNOWN, "Unknown" }, \
+ { IFM_ATM_UTP_25, "UTP/25.6MBit" }, \
+ { IFM_ATM_TAXI_100, "Taxi/100MBit" }, \
+ { IFM_ATM_TAXI_140, "Taxi/140MBit" }, \
+ { IFM_ATM_MM_155, "Multi-mode/155MBit" }, \
+ { IFM_ATM_SM_155, "Single-mode/155MBit" }, \
+ { IFM_ATM_UTP_155, "UTP/155MBit" }, \
+ { IFM_ATM_MM_622, "Multi-mode/622MBit" }, \
+ { IFM_ATM_SM_622, "Single-mode/622MBit" }, \
+ { IFM_ATM_VIRTUAL, "Virtual" }, \
+ { 0, NULL }, \
+}
+
+# define IFM_SUBTYPE_ATM_ALIASES { \
+ { IFM_ATM_UNKNOWN, "UNKNOWN" }, \
+ { IFM_ATM_UTP_25, "UTP-25" }, \
+ { IFM_ATM_TAXI_100, "TAXI-100" }, \
+ { IFM_ATM_TAXI_140, "TAXI-140" }, \
+ { IFM_ATM_MM_155, "MM-155" }, \
+ { IFM_ATM_SM_155, "SM-155" }, \
+ { IFM_ATM_UTP_155, "UTP-155" }, \
+ { IFM_ATM_MM_622, "MM-622" }, \
+ { IFM_ATM_SM_622, "SM-622" }, \
+ { IFM_ATM_VIRTUAL, "VIRTUAL" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS { \
+ { IFM_ATM_SDH, "SDH" }, \
+ { IFM_ATM_NOSCRAMB, "Noscramb" }, \
+ { IFM_ATM_UNASSIGNED, "Unassigned" }, \
+ { 0, NULL }, \
+}
+
+
#define IFM_SUBTYPE_SHARED_DESCRIPTIONS { \
{ IFM_AUTO, "autoselect" }, \
{ IFM_MANUAL, "manual" }, \
diff -N -u -r src.preview/sys/net/if_var.h src/sys/net/if_var.h
--- src.preview/sys/net/if_var.h 2005-06-15 15:29:30.000000000 -0400
+++ src/sys/net/if_var.h 2005-09-23 11:24:22.000000000 -0400
@@ -77,6 +77,8 @@
struct ucred;
#include <sys/queue.h> /* get TAILQ macros */
+#include <machine/thread.h>
+#include <sys/thread.h>
#include <net/altq/if_altq.h>
@@ -103,6 +105,7 @@
int ifq_len;
int ifq_maxlen;
int ifq_drops;
+ struct lwkt_token ifq_mtx;
};
#ifdef DEVICE_POLLING
diff -N -u -r src.preview/sys/net/ifq_var.h src/sys/net/ifq_var.h
--- src.preview/sys/net/ifq_var.h 2005-06-15 15:29:30.000000000 -0400
+++ src/sys/net/ifq_var.h 2005-09-23 11:24:22.000000000 -0400
@@ -49,13 +49,13 @@
}
#else
static __inline int
-ifq_is_enabled(struct ifaltq *_ifq)
+ifq_is_enabled(struct ifaltq *_ifq __unused)
{
return(0);
}
static __inline int
-ifq_is_attached(struct ifaltq *_ifq)
+ifq_is_attached(struct ifaltq *_ifq __unused)
{
return(0);
}
diff -N -u -r src.preview/sys/net/route.h src/sys/net/route.h
--- src.preview/sys/net/route.h 2005-05-01 00:05:35.000000000 -0400
+++ src/sys/net/route.h 2005-09-27 15:26:17.000000000 -0400
@@ -262,6 +262,7 @@
#define RTM_NEWMADDR 0xf /* mcast group membership being added to if */
#define RTM_DELMADDR 0x10 /* mcast group membership being deleted */
#define RTM_IFANNOUNCE 0x11 /* iface arrival/departure */
+#define RTM_IEEE80211 0x12 /* IEEE80211 wireless event */
/*
* Bitmask values for rtm_inits and rmx_locks.
@@ -308,6 +309,11 @@
struct ifnet *rti_ifp;
};
+#define SA_SIZE(sa) \
+ ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
+ sizeof(long) : \
+ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
+
#ifdef _KERNEL
#define rti_dst rti_info[RTAX_DST]
@@ -327,6 +333,7 @@
void route_init (void);
void rt_dstmsg(int type, struct sockaddr *dst, int error);
int rt_getifa (struct rt_addrinfo *);
+void rt_ieee80211msg(struct ifnet *, int, void *, size_t);
void rt_ifannouncemsg (struct ifnet *, int);
void rt_ifmsg (struct ifnet *);
int rt_llroute (struct sockaddr *dst, struct rtentry *rt0,
diff -N -u -r src.preview/sys/net/rtsock.c src/sys/net/rtsock.c
--- src.preview/sys/net/rtsock.c 2005-07-15 13:54:47.000000000 -0400
+++ src/sys/net/rtsock.c 2005-09-23 11:24:22.000000000 -0400
@@ -694,6 +694,7 @@
case RTM_IFINFO:
return sizeof(struct if_msghdr);
case RTM_IFANNOUNCE:
+ case RTM_IEEE80211:
return sizeof(struct if_announcemsghdr);
default:
return sizeof(struct rt_msghdr);
@@ -1007,6 +1008,59 @@
/*
* This is called to generate routing socket messages indicating
+ * IEEE80211 wireless events.
+ * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way.
+ */
+void
+rt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len)
+{
+ struct mbuf *m;
+ struct rt_addrinfo info;
+
+ struct rt_addrinfo addrinfo;
+ struct if_announcemsghdr *ifan;
+
+ if (route_cb.any_count == 0)
+ return;
+
+ bzero(&addrinfo, sizeof addrinfo);
+ m = rt_msg_mbuf(RTM_IEEE80211, &addrinfo);
+ if (m == NULL)
+ return;
+
+ ifan = mtod(m, struct if_announcemsghdr *);
+ ifan->ifan_index = ifp->if_index;
+ strlcpy(ifan->ifan_name, ifp->if_xname, sizeof ifan->ifan_name);
+ ifan->ifan_what = what;
+
+ /*
+ * Append the ieee80211 data. Try to stick it in the
+ * mbuf containing the ifannounce msg; otherwise allocate
+ * a new mbuf and append.
+ *
+ * NB: we assume m is a single mbuf.
+ */
+ if (data_len > M_TRAILINGSPACE(m)) {
+ struct mbuf *n = m_get(M_NOWAIT, MT_DATA);
+ if (n == NULL) {
+ m_freem(m);
+ return;
+ }
+ bcopy(data, mtod(n, void *), data_len);
+ n->m_len = data_len;
+ m->m_next = n;
+ } else if (data_len > 0) {
+ bcopy(data, mtod(m, u_int8_t *) + m->m_len, data_len);
+ m->m_len += data_len;
+ }
+ if (m->m_flags & M_PKTHDR)
+ m->m_pkthdr.len += data_len;
+ mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len;
+ rts_input(m, 0);
+}
+
+/*
+ * This is called to generate routing socket messages indicating
* network interface arrival and departure.
*/
void
diff -N -u -r src.preview/sys/netproto/802_11/_ieee80211.h src/sys/netproto/802_11/_ieee80211.h
--- src.preview/sys/netproto/802_11/_ieee80211.h 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/netproto/802_11/_ieee80211.h 2005-09-23 11:44:24.000000000 -0400
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 2001 Atsushi Onoe
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NET80211__IEEE80211_H_
+#define _NET80211__IEEE80211_H_
+
+enum ieee80211_phytype {
+ IEEE80211_T_DS, /* direct sequence spread spectrum */
+ IEEE80211_T_FH, /* frequency hopping */
+ IEEE80211_T_OFDM, /* frequency division multiplexing */
+ IEEE80211_T_TURBO, /* high rate OFDM, aka turbo mode */
+};
+#define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */
+
+/* XXX not really a mode; there are really multiple PHY's */
+enum ieee80211_phymode {
+ IEEE80211_MODE_AUTO = 0, /* autoselect */
+ IEEE80211_MODE_11A = 1, /* 5GHz, OFDM */
+ IEEE80211_MODE_11B = 2, /* 2GHz, CCK */
+ IEEE80211_MODE_11G = 3, /* 2GHz, OFDM */
+ IEEE80211_MODE_FH = 4, /* 2GHz, GFSK */
+ IEEE80211_MODE_TURBO_A = 5, /* 5GHz, OFDM, 2x clock */
+ IEEE80211_MODE_TURBO_G = 6, /* 2GHz, OFDM, 2x clock */
+};
+#define IEEE80211_MODE_MAX (IEEE80211_MODE_TURBO_G+1)
+
+enum ieee80211_opmode {
+ IEEE80211_M_STA = 1, /* infrastructure station */
+ IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */
+ IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */
+ IEEE80211_M_HOSTAP = 6, /* Software Access Point */
+ IEEE80211_M_MONITOR = 8 /* Monitor mode */
+};
+
+/*
+ * 802.11g protection mode.
+ */
+enum ieee80211_protmode {
+ IEEE80211_PROT_NONE = 0, /* no protection */
+ IEEE80211_PROT_CTSONLY = 1, /* CTS to self */
+ IEEE80211_PROT_RTSCTS = 2, /* RTS-CTS */
+};
+
+/*
+ * Authentication mode.
+ */
+enum ieee80211_authmode {
+ IEEE80211_AUTH_NONE = 0,
+ IEEE80211_AUTH_OPEN = 1, /* open */
+ IEEE80211_AUTH_SHARED = 2, /* shared-key */
+ IEEE80211_AUTH_8021X = 3, /* 802.1x */
+ IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */
+ /* NB: these are used only for ioctls */
+ IEEE80211_AUTH_WPA = 5, /* WPA/RSN w/ 802.1x/PSK */
+};
+
+/*
+ * Roaming mode is effectively who controls the operation
+ * of the 802.11 state machine when operating as a station.
+ * State transitions are controlled either by the driver
+ * (typically when management frames are processed by the
+ * hardware/firmware), the host (auto/normal operation of
+ * the 802.11 layer), or explicitly through ioctl requests
+ * when applications like wpa_supplicant want control.
+ */
+enum ieee80211_roamingmode {
+ IEEE80211_ROAMING_DEVICE= 0, /* driver/hardware control */
+ IEEE80211_ROAMING_AUTO = 1, /* 802.11 layer control */
+ IEEE80211_ROAMING_MANUAL= 2, /* application control */
+};
+
+/*
+ * Channels are specified by frequency and attributes.
+ */
+struct ieee80211_channel {
+ u_int16_t ic_freq; /* setting in Mhz */
+ u_int16_t ic_flags; /* see below */
+};
+
+#define IEEE80211_CHAN_MAX 255
+#define IEEE80211_CHAN_BYTES 32 /* howmany(IEEE80211_CHAN_MAX, NBBY) */
+#define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */
+#define IEEE80211_CHAN_ANYC \
+ ((struct ieee80211_channel *) IEEE80211_CHAN_ANY)
+
+/* bits 0-3 are for private use by drivers */
+/* channel attributes */
+#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
+#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
+#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
+#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
+#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
+#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
+#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
+#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+
+/*
+ * Useful combinations of channel characteristics.
+ */
+#define IEEE80211_CHAN_FHSS \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
+#define IEEE80211_CHAN_A \
+ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
+#define IEEE80211_CHAN_B \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
+#define IEEE80211_CHAN_PUREG \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
+#define IEEE80211_CHAN_G \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
+#define IEEE80211_CHAN_T \
+ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
+#define IEEE80211_CHAN_108G \
+ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
+
+#define IEEE80211_IS_CHAN_FHSS(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
+#define IEEE80211_IS_CHAN_A(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
+#define IEEE80211_IS_CHAN_B(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
+#define IEEE80211_IS_CHAN_PUREG(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
+#define IEEE80211_IS_CHAN_G(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
+#define IEEE80211_IS_CHAN_ANYG(_c) \
+ (IEEE80211_IS_CHAN_PUREG(_c) || IEEE80211_IS_CHAN_G(_c))
+#define IEEE80211_IS_CHAN_T(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_T) == IEEE80211_CHAN_T)
+#define IEEE80211_IS_CHAN_108G(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)
+
+#define IEEE80211_IS_CHAN_2GHZ(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
+#define IEEE80211_IS_CHAN_5GHZ(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0)
+#define IEEE80211_IS_CHAN_OFDM(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_OFDM) != 0)
+#define IEEE80211_IS_CHAN_CCK(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0)
+#define IEEE80211_IS_CHAN_GFSK(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0)
+
+/* ni_chan encoding for FH phy */
+#define IEEE80211_FH_CHANMOD 80
+#define IEEE80211_FH_CHAN(set,pat) (((set)-1)*IEEE80211_FH_CHANMOD+(pat))
+#define IEEE80211_FH_CHANSET(chan) ((chan)/IEEE80211_FH_CHANMOD+1)
+#define IEEE80211_FH_CHANPAT(chan) ((chan)%IEEE80211_FH_CHANMOD)
+
+/*
+ * 802.11 rate set.
+ */
+#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */
+#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */
+
+struct ieee80211_rateset {
+ u_int8_t rs_nrates;
+ u_int8_t rs_rates[IEEE80211_RATE_MAXSIZE];
+};
+
+#endif /* _NET80211__IEEE80211_H_ */
diff -N -u -r src.preview/sys/netproto/802_11/ieee80211.c src/sys/netproto/802_11/ieee80211.c
--- src.preview/sys/netproto/802_11/ieee80211.c 2005-01-25 19:37:40.000000000 -0500
+++ src/sys/netproto/802_11/ieee80211.c 2005-09-23 11:44:24.000000000 -0400
@@ -1,6 +1,6 @@
-/*
+/*-
* Copyright (c) 2001 Atsushi Onoe
- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,79 +28,114 @@
* 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: src/sys/net80211/ieee80211.c,v 1.13 2004/05/30 17:57:45 phk Exp $
- * $DragonFly: src/sys/netproto/802_11/ieee80211.c,v 1.3 2005/01/26 00:37:40 joerg Exp $
*/
+#include <sys/cdefs.h>
+
/*
* IEEE 802.11 generic handler
*/
-#include "opt_inet.h"
-
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
#include <sys/kernel.h>
-#include <sys/module.h>
+
#include <sys/socket.h>
-#include <sys/sockio.h>
-#include <sys/endian.h>
-#include <sys/errno.h>
-#include <sys/bus.h>
-#include <sys/proc.h>
-#include <sys/sysctl.h>
-#include <machine/atomic.h>
-
+#include <sys/thread.h>
+#include <sys/thread2.h>
#include <net/if.h>
-#include <net/if_dl.h>
#include <net/if_media.h>
-#include <net/if_arp.h>
#include <net/ethernet.h>
-#include <net/if_llc.h>
-#include <net/route.h>
#include <netproto/802_11/ieee80211_var.h>
#include <net/bpf.h>
-#ifdef INET
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#endif
-
-#ifdef IEEE80211_DEBUG
-int ieee80211_debug = 0;
-SYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug,
- 0, "IEEE 802.11 media debugging printfs");
-#endif
-
-static void ieee80211_set11gbasicrates(struct ieee80211_rateset *,
- enum ieee80211_phymode);
-
-static const char *ieee80211_phymode_name[] = {
+const char *ieee80211_phymode_name[] = {
"auto", /* IEEE80211_MODE_AUTO */
"11a", /* IEEE80211_MODE_11A */
"11b", /* IEEE80211_MODE_11B */
"11g", /* IEEE80211_MODE_11G */
"FH", /* IEEE80211_MODE_FH */
- "turbo", /* IEEE80211_MODE_TURBO */
+ "turboA", /* IEEE80211_MODE_TURBO_A */
+ "turboG", /* IEEE80211_MODE_TURBO_G */
};
+/* list of all instances */
+SLIST_HEAD(ieee80211_list, ieee80211com);
+static struct ieee80211_list ieee80211_list =
+ SLIST_HEAD_INITIALIZER(ieee80211_list);
+static u_int8_t ieee80211_vapmap[32]; /* enough for 256 */
+static struct lwkt_token ieee80211_vap_mtx;
+static int vap_initted = 0;
+#if 0
+MTX_SYSINIT(ieee80211, &ieee80211_vap_mtx, "net80211 instances", MTX_DEF);
+#endif
+
+static void
+ieee80211_add_vap(struct ieee80211com *ic)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ int i;
+ u_int8_t b;
+ struct lwkt_tokref tokinfo;
+
+ lwkt_gettoken(&tokinfo, &ieee80211_vap_mtx);
+ ic->ic_vap = 0;
+ for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++)
+ ic->ic_vap += NBBY;
+ if (i == N(ieee80211_vapmap))
+ panic("vap table full");
+ for (b = ieee80211_vapmap[i]; b & 1; b >>= 1)
+ ic->ic_vap++;
+ setbit(ieee80211_vapmap, ic->ic_vap);
+ SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next);
+ lwkt_reltoken(&tokinfo);
+#undef N
+}
+
+static void
+ieee80211_remove_vap(struct ieee80211com *ic)
+{
+ struct lwkt_tokref tokinfo;
+ lwkt_gettoken(&tokinfo, &ieee80211_vap_mtx);
+ SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next);
+ KASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY,
+ ("invalid vap id %d", ic->ic_vap));
+ KASSERT(isset(ieee80211_vapmap, ic->ic_vap),
+ ("vap id %d not allocated", ic->ic_vap));
+ clrbit(ieee80211_vapmap, ic->ic_vap);
+ lwkt_reltoken(&tokinfo);
+}
+
+/*
+ * Default reset method for use with the ioctl support. This
+ * method is invoked after any state change in the 802.11
+ * layer that should be propagated to the hardware but not
+ * require re-initialization of the 802.11 state machine (e.g
+ * rescanning for an ap). We always return ENETRESET which
+ * should cause the driver to re-initialize the device. Drivers
+ * can override this method to implement more optimized support.
+ */
+static int
+ieee80211_default_reset(struct ifnet *ifp)
+{
+ return ENETRESET;
+}
+
void
-ieee80211_ifattach(struct ifnet *ifp)
+ieee80211_ifattach(struct ieee80211com *ic)
{
- struct ieee80211com *ic = (void *)ifp;
+ struct ifnet *ifp = ic->ic_ifp;
struct ieee80211_channel *c;
int i;
ether_ifattach(ifp, ic->ic_myaddr);
bpfattach_dlt(ifp, DLT_IEEE802_11,
sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
- ieee80211_crypto_attach(ifp);
+
+ ieee80211_crypto_attach(ic);
/*
* Fill in 802.11 available channel set, mark
@@ -135,33 +170,75 @@
if (IEEE80211_IS_CHAN_FHSS(c))
ic->ic_modecaps |= 1<<IEEE80211_MODE_FH;
if (IEEE80211_IS_CHAN_T(c))
- ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO;
+ ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_A;
+ if (IEEE80211_IS_CHAN_108G(c))
+ ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_G;
+ if (ic->ic_curchan == NULL) {
+ /* arbitrarily pick the first channel */
+ ic->ic_curchan = &ic->ic_channels[i];
+ }
}
}
/* validate ic->ic_curmode */
if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0)
ic->ic_curmode = IEEE80211_MODE_AUTO;
ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */
-
+#if 0
+ /*
+ * Enable WME by default if we're capable.
+ */
+ if (ic->ic_caps & IEEE80211_C_WME)
+ ic->ic_flags |= IEEE80211_F_WME;
+#endif
(void) ieee80211_setmode(ic, ic->ic_curmode);
+ if (ic->ic_bintval == 0)
+ ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
+ ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */
+ ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT;
+ IEEE80211_BEACON_LOCK_INIT(ic, "beacon");
+
if (ic->ic_lintval == 0)
- ic->ic_lintval = 100; /* default sleep */
- ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
+ ic->ic_lintval = ic->ic_bintval;
+ ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
- ieee80211_node_attach(ifp);
- ieee80211_proto_attach(ifp);
+ ieee80211_node_attach(ic);
+ ieee80211_proto_attach(ic);
+
+ crit_enter();
+ if (!vap_initted) {
+ vap_initted = 1;
+ lwkt_token_init(&ieee80211_vap_mtx);
+ }
+ crit_exit();
+ ieee80211_add_vap(ic);
+
+ ieee80211_sysctl_attach(ic); /* NB: requires ic_vap */
+
+ /*
+ * Install a default reset method for the ioctl support.
+ * The driver is expected to fill this in before calling us.
+ */
+ if (ic->ic_reset == NULL)
+ ic->ic_reset = ieee80211_default_reset;
}
void
-ieee80211_ifdetach(struct ifnet *ifp)
+ieee80211_ifdetach(struct ieee80211com *ic)
{
- struct ieee80211com *ic = (void *)ifp;
+ struct ifnet *ifp = ic->ic_ifp;
+
+ ieee80211_remove_vap(ic);
- ieee80211_proto_detach(ifp);
- ieee80211_crypto_detach(ifp);
- ieee80211_node_detach(ifp);
+ ieee80211_sysctl_detach(ic);
+ ieee80211_proto_detach(ic);
+ ieee80211_crypto_detach(ic);
+ ieee80211_node_detach(ic);
ifmedia_removeall(&ic->ic_media);
+
+ IEEE80211_BEACON_LOCK_DESTROY(ic);
+
+ bpfdetach(ifp);
ether_ifdetach(ifp);
}
@@ -202,11 +279,11 @@
else if (c == IEEE80211_CHAN_ANYC)
return IEEE80211_CHAN_ANY;
else if (c != NULL) {
- if_printf(&ic->ic_if, "invalid channel freq %u flags %x\n",
+ if_printf(ic->ic_ifp, "invalid channel freq %u flags %x\n",
c->ic_freq, c->ic_flags);
return 0; /* XXX */
} else {
- if_printf(&ic->ic_if, "invalid channel (NULL)\n");
+ if_printf(ic->ic_ifp, "invalid channel (NULL)\n");
return 0; /* XXX */
}
}
@@ -243,13 +320,13 @@
* ieee80211_attach and before most anything else.
*/
void
-ieee80211_media_init(struct ifnet *ifp,
+ieee80211_media_init(struct ieee80211com *ic,
ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
{
#define ADD(_ic, _s, _o) \
ifmedia_add(&(_ic)->ic_media, \
IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
- struct ieee80211com *ic = (void *)ifp;
+ struct ifnet *ifp = ic->ic_ifp;
struct ifmediareq imr;
int i, j, mode, rate, maxrate, mword, mopt, r;
struct ieee80211_rateset *rs;
@@ -259,7 +336,7 @@
* Do late attach work that must wait for any subclass
* (i.e. driver) work such as overriding methods.
*/
- ieee80211_node_lateattach(ifp);
+ ieee80211_node_lateattach(ic);
/*
* Fill in media characteristics.
@@ -275,6 +352,7 @@
IFM_IEEE80211_11G,
IFM_IEEE80211_FH,
IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
+ IFM_IEEE80211_11G | IFM_IEEE80211_TURBO,
};
if ((ic->ic_modecaps & (1<<mode)) == 0)
continue;
@@ -290,16 +368,12 @@
ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR);
if (mode == IEEE80211_MODE_AUTO)
continue;
- if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
rs = &ic->ic_sup_rates[mode];
for (i = 0; i < rs->rs_nrates; i++) {
rate = rs->rs_rates[i];
mword = ieee80211_rate2media(ic, rate, mode);
if (mword == 0)
continue;
- printf("%s%d%sMbps", (i != 0 ? " " : ""),
- (rate & IEEE80211_RATE_VAL) / 2,
- ((rate & 0x1) != 0 ? ".5" : ""));
ADD(ic, mword, mopt);
if (ic->ic_caps & IEEE80211_C_IBSS)
ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
@@ -325,7 +399,6 @@
if (rate > maxrate)
maxrate = rate;
}
- printf("\n");
}
for (i = 0; i < allrates.rs_nrates; i++) {
mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
@@ -351,6 +424,31 @@
#undef ADD
}
+void
+ieee80211_announce(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ int i, mode, rate, mword;
+ struct ieee80211_rateset *rs;
+
+ for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
+ if ((ic->ic_modecaps & (1<<mode)) == 0)
+ continue;
+ if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
+ rs = &ic->ic_sup_rates[mode];
+ for (i = 0; i < rs->rs_nrates; i++) {
+ rate = rs->rs_rates[i];
+ mword = ieee80211_rate2media(ic, rate, mode);
+ if (mword == 0)
+ continue;
+ printf("%s%d%sMbps", (i != 0 ? " " : ""),
+ (rate & IEEE80211_RATE_VAL) / 2,
+ ((rate & 0x1) != 0 ? ".5" : ""));
+ }
+ printf("\n");
+ }
+}
+
static int
findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
{
@@ -365,17 +463,50 @@
}
/*
+ * Find an instance by it's mac address.
+ */
+struct ieee80211com *
+ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct ieee80211com *ic;
+
+ /* XXX lock */
+ SLIST_FOREACH(ic, &ieee80211_list, ic_next)
+ if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr))
+ return ic;
+ return NULL;
+}
+
+static struct ieee80211com *
+ieee80211_find_instance(struct ifnet *ifp)
+{
+ struct ieee80211com *ic;
+
+ /* XXX lock */
+ /* XXX not right for multiple instances but works for now */
+ SLIST_FOREACH(ic, &ieee80211_list, ic_next)
+ if (ic->ic_ifp == ifp)
+ return ic;
+ return NULL;
+}
+
+/*
* Handle a media change request.
*/
int
ieee80211_media_change(struct ifnet *ifp)
{
- struct ieee80211com *ic = (void *)ifp;
+ struct ieee80211com *ic;
struct ifmedia_entry *ime;
enum ieee80211_opmode newopmode;
enum ieee80211_phymode newphymode;
int i, j, newrate, error = 0;
+ ic = ieee80211_find_instance(ifp);
+ if (!ic) {
+ if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
+ return EINVAL;
+ }
ime = ic->ic_media.ifm_cur;
/*
* First, identify the phy mode.
@@ -400,13 +531,16 @@
return EINVAL;
}
/*
- * Turbo mode is an ``option''. Eventually it
- * needs to be applied to 11g too.
+ * Turbo mode is an ``option''.
+ * XXX does not apply to AUTO
*/
if (ime->ifm_media & IFM_IEEE80211_TURBO) {
- if (newphymode != IEEE80211_MODE_11A)
+ if (newphymode == IEEE80211_MODE_11A)
+ newphymode = IEEE80211_MODE_TURBO_A;
+ else if (newphymode == IEEE80211_MODE_11G)
+ newphymode = IEEE80211_MODE_TURBO_G;
+ else
return EINVAL;
- newphymode = IEEE80211_MODE_TURBO;
}
/*
* Validate requested mode is available.
@@ -513,14 +647,15 @@
break;
case IEEE80211_M_IBSS:
ic->ic_flags |= IEEE80211_F_IBSSON;
-#ifdef notdef
- if (ic->ic_curmode == IEEE80211_MODE_11G)
- ieee80211_set11gbasicrates(
- &ic->ic_suprates[newphymode],
- IEEE80211_MODE_11B);
-#endif
break;
}
+ /*
+ * Yech, slot time may change depending on the
+ * operating mode so reset it to be sure everything
+ * is setup appropriately.
+ */
+ ieee80211_reset_erp(ic);
+ ieee80211_wme_initparams(ic); /* after opmode change */
error = ENETRESET;
}
#ifdef notdef
@@ -533,26 +668,39 @@
void
ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
{
- struct ieee80211com *ic = (void *)ifp;
- struct ieee80211_node *ni = NULL;
- int old_status = imr->ifm_status;
+ struct ieee80211com *ic;
+ struct ieee80211_rateset *rs;
+ ic = ieee80211_find_instance(ifp);
+ if (!ic) {
+ if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
+ return;
+ }
imr->ifm_status = IFM_AVALID;
imr->ifm_active = IFM_IEEE80211;
-/* XXX
- if (ic->ic_state == IEEE80211_S_RUN) {
+ if (ic->ic_state == IEEE80211_S_RUN)
imr->ifm_status |= IFM_ACTIVE;
- ifp->if_link_state = LINK_STATE_UP;
+ /*
+ * Calculate a current rate if possible.
+ */
+ if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
+ /*
+ * A fixed rate is set, report that.
+ */
+ rs = &ic->ic_sup_rates[ic->ic_curmode];
+ imr->ifm_active |= ieee80211_rate2media(ic,
+ rs->rs_rates[ic->ic_fixed_rate], ic->ic_curmode);
+ } else if (ic->ic_opmode == IEEE80211_M_STA) {
+ /*
+ * In station mode report the current transmit rate.
+ */
+ rs = &ic->ic_bss->ni_rates;
+ imr->ifm_active |= ieee80211_rate2media(ic,
+ rs->rs_rates[ic->ic_bss->ni_txrate], ic->ic_curmode);
} else
- ifp->if_link_state = LINK_STATE_DOWN;
-*/
- imr->ifm_active |= IFM_AUTO;
+ imr->ifm_active |= IFM_AUTO;
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
- ni = ic->ic_bss;
- /* calculate rate subtype */
- imr->ifm_active |= ieee80211_rate2media(ic,
- ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
break;
case IEEE80211_M_IBSS:
imr->ifm_active |= IFM_IEEE80211_ADHOC;
@@ -580,58 +728,41 @@
case IEEE80211_MODE_FH:
imr->ifm_active |= IFM_IEEE80211_FH;
break;
- case IEEE80211_MODE_TURBO:
+ case IEEE80211_MODE_TURBO_A:
imr->ifm_active |= IFM_IEEE80211_11A
| IFM_IEEE80211_TURBO;
break;
+ case IEEE80211_MODE_TURBO_G:
+ imr->ifm_active |= IFM_IEEE80211_11G
+ | IFM_IEEE80211_TURBO;
+ break;
}
-
- /* Notify that the link state has changed. */
- if (imr->ifm_status != old_status)
- rt_ifmsg(ifp);
}
void
-ieee80211_watchdog(struct ifnet *ifp)
-{
- struct ieee80211com *ic = (void *)ifp;
-
- if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- if (ic->ic_inact_timer && --ic->ic_inact_timer == 0)
- ieee80211_timeout_nodes(ic);
-
- if (ic->ic_mgt_timer != 0 || ic->ic_inact_timer != 0)
- ifp->if_timer = 1;
-}
-
-/*
- * Mark the basic rates for the 11g rate table based on the
- * operating mode. For real 11g we mark all the 11b rates
- * and 6, 12, and 24 OFDM. For 11b compatibility we mark only
- * 11b rates. There's also a pseudo 11a-mode used to mark only
- * the basic OFDM rates.
- */
-static void
-ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode)
+ieee80211_watchdog(struct ieee80211com *ic)
{
- static const struct ieee80211_rateset basic[] = {
- { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
- { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11B */
- { 7, { 2, 4, 11, 22, 12, 24, 48 } },/* IEEE80211_MODE_11G */
- { 0 }, /* IEEE80211_MODE_FH */
- { 0 }, /* IEEE80211_MODE_TURBO */
- };
- int i, j;
+ struct ieee80211_node_table *nt;
+ int need_inact_timer = 0;
- for (i = 0; i < rs->rs_nrates; i++) {
- rs->rs_rates[i] &= IEEE80211_RATE_VAL;
- for (j = 0; j < basic[mode].rs_nrates; j++)
- if (basic[mode].rs_rates[j] == rs->rs_rates[i]) {
- rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
- break;
- }
+ if (ic->ic_state != IEEE80211_S_INIT) {
+ if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
+ nt = &ic->ic_scan;
+ if (nt->nt_inact_timer) {
+ if (--nt->nt_inact_timer == 0)
+ nt->nt_timeout(nt);
+ need_inact_timer += nt->nt_inact_timer;
+ }
+ nt = &ic->ic_sta;
+ if (nt->nt_inact_timer) {
+ if (--nt->nt_inact_timer == 0)
+ nt->nt_timeout(nt);
+ need_inact_timer += nt->nt_inact_timer;
+ }
}
+ if (ic->ic_mgt_timer != 0 || need_inact_timer)
+ ic->ic_ifp->if_timer = 1;
}
/*
@@ -650,7 +781,8 @@
IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */
IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */
IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */
- IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */
+ IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */
+ IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */
};
struct ieee80211_channel *c;
u_int modeflags;
@@ -658,8 +790,9 @@
/* validate new mode */
if ((ic->ic_modecaps & (1<<mode)) == 0) {
- IEEE80211_DPRINTF(("%s: mode %u not supported (caps 0x%x)\n",
- __func__, mode, ic->ic_modecaps));
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
+ "%s: mode %u not supported (caps 0x%x)\n",
+ __func__, mode, ic->ic_modecaps);
return EINVAL;
}
@@ -681,8 +814,8 @@
}
}
if (i > IEEE80211_CHAN_MAX) {
- IEEE80211_DPRINTF(("%s: no channels found for mode %u\n",
- __func__, mode));
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
+ "%s: no channels found for mode %u\n", __func__, mode);
return EINVAL;
}
@@ -714,56 +847,82 @@
ic->ic_ibss_chan = &ic->ic_channels[i];
break;
}
+ KASSERT(ic->ic_ibss_chan != NULL &&
+ isset(ic->ic_chan_active,
+ ieee80211_chan2ieee(ic, ic->ic_ibss_chan)),
+ ("Bad IBSS channel %u",
+ ieee80211_chan2ieee(ic, ic->ic_ibss_chan)));
}
+ /*
+ * If the desired channel is set but no longer valid then reset it.
+ */
+ if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
+ isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_des_chan)))
+ ic->ic_des_chan = IEEE80211_CHAN_ANYC;
/*
- * Set/reset state flags that influence beacon contents, etc.
- *
- * XXX what if we have stations already associated???
- * XXX probably not right for autoselect?
+ * Do mode-specific rate setup.
*/
- if (ic->ic_caps & IEEE80211_C_SHPREAMBLE)
- ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
if (mode == IEEE80211_MODE_11G) {
- if (ic->ic_caps & IEEE80211_C_SHSLOT)
- ic->ic_flags |= IEEE80211_F_SHSLOT;
+ /*
+ * Use a mixed 11b/11g rate set.
+ */
ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode],
IEEE80211_MODE_11G);
- } else {
- ic->ic_flags &= ~IEEE80211_F_SHSLOT;
+ } else if (mode == IEEE80211_MODE_11B) {
+ /*
+ * Force pure 11b rate set.
+ */
+ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode],
+ IEEE80211_MODE_11B);
}
+ /*
+ * Setup an initial rate set according to the
+ * current/default channel selected above. This
+ * will be changed when scanning but must exist
+ * now so driver have a consistent state of ic_ibss_chan.
+ */
+ if (ic->ic_bss) /* NB: can be called before lateattach */
+ ic->ic_bss->ni_rates = ic->ic_sup_rates[mode];
ic->ic_curmode = mode;
+ ieee80211_reset_erp(ic); /* reset ERP state */
+ ieee80211_wme_initparams(ic); /* reset WME stat */
+
return 0;
#undef N
}
/*
* Return the phy mode for with the specified channel so the
- * caller can select a rate set. This is problematic and the
- * work here assumes how things work elsewhere in this code.
+ * caller can select a rate set. This is problematic for channels
+ * where multiple operating modes are possible (e.g. 11g+11b).
+ * In those cases we defer to the current operating mode when set.
*/
enum ieee80211_phymode
ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan)
{
- /*
- * NB: this assumes the channel would not be supplied to us
- * unless it was already compatible with the current mode.
- */
- if (ic->ic_curmode != IEEE80211_MODE_AUTO)
- return ic->ic_curmode;
- /*
- * In autoselect mode; deduce a mode based on the channel
- * characteristics. We assume that turbo-only channels
- * are not considered when the channel set is constructed.
- */
- if (IEEE80211_IS_CHAN_5GHZ(chan))
+ if (IEEE80211_IS_CHAN_5GHZ(chan)) {
+ /*
+ * This assumes all 11a turbo channels are also
+ * usable withut turbo, which is currently true.
+ */
+ if (ic->ic_curmode == IEEE80211_MODE_TURBO_A)
+ return IEEE80211_MODE_TURBO_A;
return IEEE80211_MODE_11A;
- else if (IEEE80211_IS_CHAN_FHSS(chan))
+ } else if (IEEE80211_IS_CHAN_FHSS(chan))
return IEEE80211_MODE_FH;
- else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN))
+ else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) {
+ /*
+ * This assumes all 11g channels are also usable
+ * for 11b, which is currently true.
+ */
+ if (ic->ic_curmode == IEEE80211_MODE_TURBO_G)
+ return IEEE80211_MODE_TURBO_G;
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ return IEEE80211_MODE_11B;
return IEEE80211_MODE_11G;
- else
+ } else
return IEEE80211_MODE_11B;
}
@@ -813,7 +972,7 @@
mask = rate & IEEE80211_RATE_VAL;
switch (mode) {
case IEEE80211_MODE_11A:
- case IEEE80211_MODE_TURBO:
+ case IEEE80211_MODE_TURBO_A:
mask |= IFM_IEEE80211_11A;
break;
case IEEE80211_MODE_11B:
@@ -831,6 +990,7 @@
/* NB: hack, 11g matches both 11b+11a rates */
/* fall thru... */
case IEEE80211_MODE_11G:
+ case IEEE80211_MODE_TURBO_G:
mask |= IFM_IEEE80211_11G;
break;
}
@@ -870,33 +1030,3 @@
ieeerates[IFM_SUBTYPE(mword)] : 0;
#undef N
}
-
-/*
- * Module glue.
- *
- * NB: the module name is "wlan" for compatibility with NetBSD.
- */
-
-static int
-ieee80211_modevent(module_t mod, int type, void *unused)
-{
- switch (type) {
- case MOD_LOAD:
- if (bootverbose)
- printf("wlan: <802.11 Link Layer>\n");
- return 0;
- case MOD_UNLOAD:
- case MOD_SHUTDOWN:
- return 0;
- }
- return EINVAL;
-}
-
-static moduledata_t ieee80211_mod = {
- "wlan",
- ieee80211_modevent,
- 0
-};
-DECLARE_MODULE(wlan, ieee80211_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
-MODULE_VERSION(wlan, 1);
-MODULE_DEPEND(wlan, crypto, 1, 1, 1);
diff -N -u -r src.preview/sys/netproto/802_11/ieee80211.h src/sys/netproto/802_11/ieee80211.h
--- src.preview/sys/netproto/802_11/ieee80211.h 2004-07-26 12:30:17.000000000 -0400
+++ src/sys/netproto/802_11/ieee80211.h 2005-09-23 11:45:04.000000000 -0400
@@ -1,6 +1,6 @@
-/*
+/*-
* Copyright (c) 2001 Atsushi Onoe
- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,12 +29,10 @@
* (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: src/sys/net80211/ieee80211.h,v 1.5 2004/04/05 17:47:40 sam Exp $
- * $DragonFly: src/sys/netproto/802_11/ieee80211.h,v 1.1 2004/07/26 16:30:17 joerg Exp $
+ * $FreeBSD$
*/
-
-#ifndef _NETPROTO_802_11_IEEE80211_H_
-#define _NETPROTO_802_11_IEEE80211_H_
+#ifndef _NET80211_IEEE80211_H_
+#define _NET80211_IEEE80211_H_
* 802.11 protocol definitions.
@@ -42,112 +40,71 @@
#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
/* is 802.11 address multicast/broadcast? */
-#define IEEE80211_IS_MULTICAST(a) ETHER_IS_MULTICAST(a)
+#define IEEE80211_IS_MULTICAST(_a) (*(_a) & 0x01)
/* IEEE 802.11 PLCP header */
struct ieee80211_plcp_hdr {
- uint16_t i_sfd;
- uint8_t i_signal;
- uint8_t i_service;
- uint16_t i_length;
- uint16_t i_crc;
-} __attribute__((__packed__));
+ u_int16_t i_sfd;
+ u_int8_t i_signal;
+ u_int8_t i_service;
+ u_int16_t i_length;
+ u_int16_t i_crc;
+} __packed;
-#define IEEE80211_PLCP_SFD 0xF3A0
-#define IEEE80211_PLCP_SERVICE 0x00
+#define IEEE80211_PLCP_SFD 0xF3A0
+#define IEEE80211_PLCP_SERVICE 0x00
/*
* generic definitions for IEEE 802.11 frames
*/
struct ieee80211_frame {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_addr1[IEEE80211_ADDR_LEN];
- uint8_t i_addr2[IEEE80211_ADDR_LEN];
- uint8_t i_addr3[IEEE80211_ADDR_LEN];
- uint8_t i_seq[2];
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_addr1[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr2[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr3[IEEE80211_ADDR_LEN];
+ u_int8_t i_seq[2];
/* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
/* see below */
-} __attribute__((__packed__));
+} __packed;
struct ieee80211_qosframe {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_addr1[IEEE80211_ADDR_LEN];
- uint8_t i_addr2[IEEE80211_ADDR_LEN];
- uint8_t i_addr3[IEEE80211_ADDR_LEN];
- uint8_t i_seq[2];
- uint8_t i_qos[2];
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_addr1[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr2[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr3[IEEE80211_ADDR_LEN];
+ u_int8_t i_seq[2];
+ u_int8_t i_qos[2];
/* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
/* see below */
-} __attribute__((__packed__));
+} __packed;
struct ieee80211_qoscntl {
- uint8_t i_qos[2];
+ u_int8_t i_qos[2];
};
struct ieee80211_frame_addr4 {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_addr1[IEEE80211_ADDR_LEN];
- uint8_t i_addr2[IEEE80211_ADDR_LEN];
- uint8_t i_addr3[IEEE80211_ADDR_LEN];
- uint8_t i_seq[2];
- uint8_t i_addr4[IEEE80211_ADDR_LEN];
-} __attribute__((__packed__));
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_addr1[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr2[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr3[IEEE80211_ADDR_LEN];
+ u_int8_t i_seq[2];
+ u_int8_t i_addr4[IEEE80211_ADDR_LEN];
+} __packed;
struct ieee80211_qosframe_addr4 {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_addr1[IEEE80211_ADDR_LEN];
- uint8_t i_addr2[IEEE80211_ADDR_LEN];
- uint8_t i_addr3[IEEE80211_ADDR_LEN];
- uint8_t i_seq[2];
- uint8_t i_addr4[IEEE80211_ADDR_LEN];
- uint8_t i_qos[2];
-} __attribute__((__packed__));
-
-/*
- * Management Notification Frame
- */
-struct ieee80211_mnf {
- uint8_t mnf_category;
- uint8_t mnf_action;
- uint8_t mnf_dialog;
- uint8_t mnf_status;
-} __attribute__((__packed__));
-#define MNF_SETUP_REQ 0
-#define MNF_SETUP_RESP 1
-#define MNF_TEARDOWN 2
-
-/*
- * WME/802.11e Tspec Element
- */
-struct ieee80211_wme_tspec {
- uint8_t ts_id;
- uint8_t ts_len;
- uint8_t ts_oui[3];
- uint8_t ts_oui_type;
- uint8_t ts_oui_subtype;
- uint8_t ts_version;
- uint8_t ts_tsinfo[3];
- uint8_t ts_nom_msdu[2];
- uint8_t ts_max_msdu[2];
- uint8_t ts_min_svc[4];
- uint8_t ts_max_svc[4];
- uint8_t ts_inactv_intv[4];
- uint8_t ts_susp_intv[4];
- uint8_t ts_start_svc[4];
- uint8_t ts_min_rate[4];
- uint8_t ts_mean_rate[4];
- uint8_t ts_max_burst[4];
- uint8_t ts_min_phy[4];
- uint8_t ts_peak_rate[4];
- uint8_t ts_delay[4];
- uint8_t ts_surplus[2];
- uint8_t ts_medium_time[2];
-} __attribute__((__packed__));
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_addr1[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr2[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr3[IEEE80211_ADDR_LEN];
+ u_int8_t i_seq[2];
+ u_int8_t i_addr4[IEEE80211_ADDR_LEN];
+ u_int8_t i_qos[2];
+} __packed;
#define IEEE80211_FC0_VERSION_MASK 0x03
#define IEEE80211_FC0_VERSION_SHIFT 0
@@ -189,6 +146,7 @@
#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60
#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70
#define IEEE80211_FC0_SUBTYPE_QOS 0x80
+#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0
#define IEEE80211_FC1_DIR_MASK 0x03
#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */
@@ -212,58 +170,170 @@
#define IEEE80211_QOS_TXOP 0x00ff
/* bit 8 is reserved */
-#define IEEE80211_QOS_ACKPOLICY 0x0600
-#define IEEE80211_QOS_ESOP 0x0800
-#define IEEE80211_QOS_TID 0xf000
+#define IEEE80211_QOS_ACKPOLICY 0x60
+#define IEEE80211_QOS_ACKPOLICY_S 5
+#define IEEE80211_QOS_ESOP 0x10
+#define IEEE80211_QOS_ESOP_S 4
+#define IEEE80211_QOS_TID 0x0f
+
+/* does frame have QoS sequence control data */
+#define IEEE80211_QOS_HAS_SEQ(wh) \
+ (((wh)->i_fc[0] & \
+ (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \
+ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS))
+
+/*
+ * WME/802.11e information element.
+ */
+struct ieee80211_wme_info {
+ u_int8_t wme_id; /* IEEE80211_ELEMID_VENDOR */
+ u_int8_t wme_len; /* length in bytes */
+ u_int8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */
+ u_int8_t wme_type; /* OUI type */
+ u_int8_t wme_subtype; /* OUI subtype */
+ u_int8_t wme_version; /* spec revision */
+ u_int8_t wme_info; /* QoS info */
+} __packed;
+
+/*
+ * WME/802.11e Tspec Element
+ */
+struct ieee80211_wme_tspec {
+ u_int8_t ts_id;
+ u_int8_t ts_len;
+ u_int8_t ts_oui[3];
+ u_int8_t ts_oui_type;
+ u_int8_t ts_oui_subtype;
+ u_int8_t ts_version;
+ u_int8_t ts_tsinfo[3];
+ u_int8_t ts_nom_msdu[2];
+ u_int8_t ts_max_msdu[2];
+ u_int8_t ts_min_svc[4];
+ u_int8_t ts_max_svc[4];
+ u_int8_t ts_inactv_intv[4];
+ u_int8_t ts_susp_intv[4];
+ u_int8_t ts_start_svc[4];
+ u_int8_t ts_min_rate[4];
+ u_int8_t ts_mean_rate[4];
+ u_int8_t ts_max_burst[4];
+ u_int8_t ts_min_phy[4];
+ u_int8_t ts_peak_rate[4];
+ u_int8_t ts_delay[4];
+ u_int8_t ts_surplus[2];
+ u_int8_t ts_medium_time[2];
+} __packed;
+
+/*
+ * WME AC parameter field
+ */
+struct ieee80211_wme_acparams {
+ u_int8_t acp_aci_aifsn;
+ u_int8_t acp_logcwminmax;
+ u_int16_t acp_txop;
+} __packed;
+
+#define WME_NUM_AC 4 /* 4 AC categories */
+
+#define WME_PARAM_ACI 0x60 /* Mask for ACI field */
+#define WME_PARAM_ACI_S 5 /* Shift for ACI field */
+#define WME_PARAM_ACM 0x10 /* Mask for ACM bit */
+#define WME_PARAM_ACM_S 4 /* Shift for ACM bit */
+#define WME_PARAM_AIFSN 0x0f /* Mask for aifsn field */
+#define WME_PARAM_AIFSN_S 0 /* Shift for aifsn field */
+#define WME_PARAM_LOGCWMIN 0x0f /* Mask for CwMin field (in log) */
+#define WME_PARAM_LOGCWMIN_S 0 /* Shift for CwMin field */
+#define WME_PARAM_LOGCWMAX 0xf0 /* Mask for CwMax field (in log) */
+#define WME_PARAM_LOGCWMAX_S 4 /* Shift for CwMax field */
+
+#define WME_AC_TO_TID(_ac) ( \
+ ((_ac) == WME_AC_VO) ? 6 : \
+ ((_ac) == WME_AC_VI) ? 5 : \
+ ((_ac) == WME_AC_BK) ? 1 : \
+ 0)
+
+#define TID_TO_WME_AC(_tid) ( \
+ ((_tid) < 1) ? WME_AC_BE : \
+ ((_tid) < 3) ? WME_AC_BK : \
+ ((_tid) < 6) ? WME_AC_VI : \
+ WME_AC_VO)
+
+/*
+ * WME Parameter Element
+ */
+struct ieee80211_wme_param {
+ u_int8_t param_id;
+ u_int8_t param_len;
+ u_int8_t param_oui[3];
+ u_int8_t param_oui_type;
+ u_int8_t param_oui_sybtype;
+ u_int8_t param_version;
+ u_int8_t param_qosInfo;
+#define WME_QOSINFO_COUNT 0x0f /* Mask for param count field */
+ u_int8_t param_reserved;
+ struct ieee80211_wme_acparams params_acParams[WME_NUM_AC];
+} __packed;
+
+/*
+ * Management Notification Frame
+ */
+struct ieee80211_mnf {
+ u_int8_t mnf_category;
+ u_int8_t mnf_action;
+ u_int8_t mnf_dialog;
+ u_int8_t mnf_status;
+} __packed;
+#define MNF_SETUP_REQ 0
+#define MNF_SETUP_RESP 1
+#define MNF_TEARDOWN 2
/*
* Control frames.
*/
struct ieee80211_frame_min {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_addr1[IEEE80211_ADDR_LEN];
- uint8_t i_addr2[IEEE80211_ADDR_LEN];
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_addr1[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr2[IEEE80211_ADDR_LEN];
/* FCS */
-} __attribute__((__packed__));
+} __packed;
struct ieee80211_frame_rts {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_ra[IEEE80211_ADDR_LEN];
- uint8_t i_ta[IEEE80211_ADDR_LEN];
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_ra[IEEE80211_ADDR_LEN];
+ u_int8_t i_ta[IEEE80211_ADDR_LEN];
/* FCS */
-} __attribute__((__packed__));
+} __packed;
struct ieee80211_frame_cts {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_ra[IEEE80211_ADDR_LEN];
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_ra[IEEE80211_ADDR_LEN];
/* FCS */
-} __attribute__((__packed__));
+} __packed;
struct ieee80211_frame_ack {
- uint8_t i_fc[2];
- uint8_t i_dur[2];
- uint8_t i_ra[IEEE80211_ADDR_LEN];
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_ra[IEEE80211_ADDR_LEN];
/* FCS */
-} __attribute__((__packed__));
+} __packed;
struct ieee80211_frame_pspoll {
- uint8_t i_fc[2];
- uint8_t i_aid[2];
- uint8_t i_bssid[IEEE80211_ADDR_LEN];
- uint8_t i_ta[IEEE80211_ADDR_LEN];
+ u_int8_t i_fc[2];
+ u_int8_t i_aid[2];
+ u_int8_t i_bssid[IEEE80211_ADDR_LEN];
+ u_int8_t i_ta[IEEE80211_ADDR_LEN];
/* FCS */
-} __attribute__((__packed__));
+} __packed;
struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */
- uint8_t i_fc[2];
- uint8_t i_dur[2]; /* should be zero */
- uint8_t i_ra[IEEE80211_ADDR_LEN];
- uint8_t i_bssid[IEEE80211_ADDR_LEN];
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2]; /* should be zero */
+ u_int8_t i_ra[IEEE80211_ADDR_LEN];
+ u_int8_t i_bssid[IEEE80211_ADDR_LEN];
/* FCS */
-} __attribute__((__packed__));
+} __packed;
/*
* BEACON management packets
@@ -277,7 +347,7 @@
* octet information[length]
*/
-typedef uint8_t *ieee80211_mgt_beacon_t;
+typedef u_int8_t *ieee80211_mgt_beacon_t;
#define IEEE80211_BEACON_INTERVAL(beacon) \
((beacon)[8] | ((beacon)[9] << 8))
@@ -303,103 +373,80 @@
* 802.11i/WPA information element (maximally sized).
*/
struct ieee80211_ie_wpa {
- uint8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */
- uint8_t wpa_type; /* OUI type */
- uint16_t wpa_version; /* spec revision */
- uint32_t wpa_mcipher[1]; /* multicast/group key cipher */
- uint16_t wpa_uciphercnt; /* # pairwise key ciphers */
- uint32_t wpa_uciphers[8];/* ciphers */
- uint16_t wpa_authselcnt; /* authentication selector cnt*/
- uint32_t wpa_authsels[8];/* selectors */
-} __attribute__((__packed__));
-
-/*
- * Management information elements
- */
-struct ieee80211_information {
- char ssid[IEEE80211_NWID_LEN+1];
- struct rates {
- uint8_t *p;
- } rates;
- struct fh {
- uint16_t dwell;
- uint8_t set;
- uint8_t pattern;
- uint8_t index;
- } fh;
- struct ds {
- uint8_t channel;
- } ds;
- struct cf {
- uint8_t count;
- uint8_t period;
- uint8_t maxdur[2];
- uint8_t dur[2];
- } cf;
- struct tim {
- uint8_t count;
- uint8_t period;
- uint8_t bitctl;
- /* uint8_t pvt[251]; The driver needs to use this. */
- } tim;
- struct ibss {
- uint16_t atim;
- } ibss;
- struct challenge {
- uint8_t *p;
- uint8_t len;
- } challenge;
- struct erp {
- uint8_t flags;
- } erp;
- struct country {
- uint8_t cc[3]; /* ISO CC+(I)ndoor/(O)utdoor */
- struct {
- uint8_t schan; /* starting channel */
- uint8_t nchan; /* number channels */
- uint8_t maxtxpwr;
- } band[4]; /* up to 4 sub bands */
- } country;
- struct ath {
- uint8_t flags;
- } ath;
- struct ieee80211_ie_wpa wpa;
-};
+ u_int8_t wpa_id; /* IEEE80211_ELEMID_VENDOR */
+ u_int8_t wpa_len; /* length in bytes */
+ u_int8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */
+ u_int8_t wpa_type; /* OUI type */
+ u_int16_t wpa_version; /* spec revision */
+ u_int32_t wpa_mcipher[1]; /* multicast/group key cipher */
+ u_int16_t wpa_uciphercnt; /* # pairwise key ciphers */
+ u_int32_t wpa_uciphers[8];/* ciphers */
+ u_int16_t wpa_authselcnt; /* authentication selector cnt*/
+ u_int32_t wpa_authsels[8];/* selectors */
+ u_int16_t wpa_caps; /* 802.11i capabilities */
+ u_int16_t wpa_pmkidcnt; /* 802.11i pmkid count */
+ u_int16_t wpa_pmkids[8]; /* 802.11i pmkids */
+} __packed;
+
+/*
+ * Management information element payloads.
+ */
enum {
- IEEE80211_ELEMID_SSID = 0,
- IEEE80211_ELEMID_RATES = 1,
- IEEE80211_ELEMID_FHPARMS = 2,
- IEEE80211_ELEMID_DSPARMS = 3,
- IEEE80211_ELEMID_CFPARMS = 4,
- IEEE80211_ELEMID_TIM = 5,
- IEEE80211_ELEMID_IBSSPARMS = 6,
- IEEE80211_ELEMID_COUNTRY = 7,
- IEEE80211_ELEMID_CHALLENGE = 16,
+ IEEE80211_ELEMID_SSID = 0,
+ IEEE80211_ELEMID_RATES = 1,
+ IEEE80211_ELEMID_FHPARMS = 2,
+ IEEE80211_ELEMID_DSPARMS = 3,
+ IEEE80211_ELEMID_CFPARMS = 4,
+ IEEE80211_ELEMID_TIM = 5,
+ IEEE80211_ELEMID_IBSSPARMS = 6,
+ IEEE80211_ELEMID_COUNTRY = 7,
+ IEEE80211_ELEMID_CHALLENGE = 16,
/* 17-31 reserved for challenge text extension */
- IEEE80211_ELEMID_ERP = 42,
- IEEE80211_ELEMID_XRATES = 50,
- IEEE80211_ELEMID_TPC = 150,
- IEEE80211_ELEMID_CCKM = 156,
- IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
+ IEEE80211_ELEMID_ERP = 42,
+ IEEE80211_ELEMID_RSN = 48,
+ IEEE80211_ELEMID_XRATES = 50,
+ IEEE80211_ELEMID_TPC = 150,
+ IEEE80211_ELEMID_CCKM = 156,
+ IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
};
-#define IEEE80211_CHALLENGE_LEN 128
+struct ieee80211_tim_ie {
+ u_int8_t tim_ie; /* IEEE80211_ELEMID_TIM */
+ u_int8_t tim_len;
+ u_int8_t tim_count; /* DTIM count */
+ u_int8_t tim_period; /* DTIM period */
+ u_int8_t tim_bitctl; /* bitmap control */
+ u_int8_t tim_bitmap[1]; /* variable-length bitmap */
+} __packed;
+
+struct ieee80211_country_ie {
+ u_int8_t ie; /* IEEE80211_ELEMID_COUNTRY */
+ u_int8_t len;
+ u_int8_t cc[3]; /* ISO CC+(I)ndoor/(O)utdoor */
+ struct {
+ u_int8_t schan; /* starting channel */
+ u_int8_t nchan; /* number channels */
+ u_int8_t maxtxpwr; /* tx power cap */
+ } band[4] __packed; /* up to 4 sub bands */
+} __packed;
+
+#define IEEE80211_CHALLENGE_LEN 128
-#define IEEE80211_RATE_BASIC 0x80
-#define IEEE80211_RATE_VAL 0x7f
+#define IEEE80211_RATE_BASIC 0x80
+#define IEEE80211_RATE_VAL 0x7f
/* EPR information element flags */
-#define IEEE80211_ERP_NON_ERP_PRESENT 0x01
-#define IEEE80211_ERP_USE_PROTECTION 0x02
-#define IEEE80211_ERP_BARKER_MODE 0x04
+#define IEEE80211_ERP_NON_ERP_PRESENT 0x01
+#define IEEE80211_ERP_USE_PROTECTION 0x02
+#define IEEE80211_ERP_LONG_PREAMBLE 0x04
/* Atheros private advanced capabilities info */
-#define ATHEROS_CAP_TURBO_PRIME 0x01
-#define ATHEROS_CAP_COMPRESSION 0x02
-#define ATHEROS_CAP_FAST_FRAME 0x04
+#define ATHEROS_CAP_TURBO_PRIME 0x01
+#define ATHEROS_CAP_COMPRESSION 0x02
+#define ATHEROS_CAP_FAST_FRAME 0x04
/* bits 3-6 reserved */
-#define ATHEROS_CAP_BOOST 0x80
+#define ATHEROS_CAP_BOOST 0x80
#define ATH_OUI 0x7f0300 /* Atheros OUI */
#define ATH_OUI_TYPE 0x01
@@ -407,12 +454,11 @@
#define WPA_OUI 0xf25000
#define WPA_OUI_TYPE 0x01
-#define WPA_OUI_VERSION 1 /* current supported version */
+#define WPA_VERSION 1 /* current supported version */
#define WPA_CSE_NULL 0x00
#define WPA_CSE_WEP40 0x01
#define WPA_CSE_TKIP 0x02
-#define WPA_CSE_WRAP 0x03 /* WPA2/802.11i */
#define WPA_CSE_CCMP 0x04
#define WPA_CSE_WEP104 0x05
@@ -420,6 +466,34 @@
#define WPA_ASE_8021X_UNSPEC 0x01
#define WPA_ASE_8021X_PSK 0x02
+#define RSN_OUI 0xac0f00
+#define RSN_VERSION 1 /* current supported version */
+
+#define RSN_CSE_NULL 0x00
+#define RSN_CSE_WEP40 0x01
+#define RSN_CSE_TKIP 0x02
+#define RSN_CSE_WRAP 0x03
+#define RSN_CSE_CCMP 0x04
+#define RSN_CSE_WEP104 0x05
+
+#define RSN_ASE_NONE 0x00
+#define RSN_ASE_8021X_UNSPEC 0x01
+#define RSN_ASE_8021X_PSK 0x02
+
+#define RSN_CAP_PREAUTH 0x01
+
+#define WME_OUI 0xf25000
+#define WME_OUI_TYPE 0x02
+#define WME_INFO_OUI_SUBTYPE 0x00
+#define WME_PARAM_OUI_SUBTYPE 0x01
+#define WME_VERSION 1
+
+/* WME stream classes */
+#define WME_AC_BE 0 /* best effort */
+#define WME_AC_BK 1 /* background */
+#define WME_AC_VI 2 /* video */
+#define WME_AC_VO 3 /* voice */
+
/*
* AUTH management packets
*
@@ -431,7 +505,7 @@
* octet chal.text[253]
*/
-typedef uint8_t *ieee80211_mgt_auth_t;
+typedef u_int8_t *ieee80211_mgt_auth_t;
#define IEEE80211_AUTH_ALGORITHM(auth) \
((auth)[0] | ((auth)[1] << 8))
@@ -440,9 +514,9 @@
#define IEEE80211_AUTH_STATUS(auth) \
((auth)[4] | ((auth)[5] << 8))
-#define IEEE80211_AUTH_ALG_OPEN 0x0000
-#define IEEE80211_AUTH_ALG_SHARED 0x0001
-#define IEEE80211_AUTH_ALG_LEAP 0x0080
+#define IEEE80211_AUTH_ALG_OPEN 0x0000
+#define IEEE80211_AUTH_ALG_SHARED 0x0001
+#define IEEE80211_AUTH_ALG_LEAP 0x0080
enum {
IEEE80211_AUTH_OPEN_REQUEST = 1,
@@ -498,13 +572,24 @@
IEEE80211_STATUS_DSSSOFDM_REQUIRED = 26,
};
-#define IEEE80211_WEP_KEYLEN 5 /* 40bit */
-#define IEEE80211_WEP_IVLEN 3 /* 24bit */
-#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */
-#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */
-#define IEEE80211_WEP_NKID 4 /* number of key ids */
+#define IEEE80211_WEP_KEYLEN 5 /* 40bit */
+#define IEEE80211_WEP_IVLEN 3 /* 24bit */
+#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */
+#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */
+#define IEEE80211_WEP_NKID 4 /* number of key ids */
+
+/*
+ * 802.11i defines an extended IV for use with non-WEP ciphers.
+ * When the EXTIV bit is set in the key id byte an additional
+ * 4 bytes immediately follow the IV for TKIP. For CCMP the
+ * EXTIV bit is likewise set but the 8 bytes represent the
+ * CCMP header rather than IV+extended-IV.
+ */
+#define IEEE80211_WEP_EXTIV 0x20
+#define IEEE80211_WEP_EXTIVLEN 4 /* extended IV length */
+#define IEEE80211_WEP_MICLEN 8 /* trailing MIC */
-#define IEEE80211_CRC_LEN 4
+#define IEEE80211_CRC_LEN 4
/*
* Maximum acceptable MTU is:
@@ -513,26 +598,42 @@
* Min is arbitrarily chosen > IEEE80211_MIN_LEN. The default
* mtu is Ethernet-compatible; it's set by ether_ifattach.
*/
-#define IEEE80211_MTU_MAX 2290
-#define IEEE80211_MTU_MIN 32
+#define IEEE80211_MTU_MAX 2290
+#define IEEE80211_MTU_MIN 32
-#define IEEE80211_MAX_LEN (2300 + IEEE80211_CRC_LEN + \
+#define IEEE80211_MAX_LEN (2300 + IEEE80211_CRC_LEN + \
(IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN))
+#define IEEE80211_ACK_LEN \
+ (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
#define IEEE80211_MIN_LEN \
(sizeof(struct ieee80211_frame_min) + IEEE80211_CRC_LEN)
+/*
+ * The 802.11 spec says at most 2007 stations may be
+ * associated at once. For most AP's this is way more
+ * than is feasible so we use a default of 128. This
+ * number may be overridden by the driver and/or by
+ * user configuration.
+ */
+#define IEEE80211_AID_MAX 2007
+#define IEEE80211_AID_DEF 128
+
+#define IEEE80211_AID(b) ((b) &~ 0xc000)
+
/*
* RTS frame length parameters. The default is specified in
- * the 802.11 spec. The max may be wrong for jumbo frames.
+ * the 802.11 spec as 512; we treat it as implementation-dependent
+ * so it's defined in ieee80211_var.h. The max may be wrong
+ * for jumbo frames.
*/
-#define IEEE80211_RTS_DEFAULT 512
-#define IEEE80211_RTS_MIN 1
-#define IEEE80211_RTS_MAX IEEE80211_MAX_LEN
+#define IEEE80211_RTS_MIN 1
+#define IEEE80211_RTS_MAX 2346
-enum {
- IEEE80211_AUTH_NONE = 0,
- IEEE80211_AUTH_OPEN = 1,
- IEEE80211_AUTH_SHARED = 2,
-};
+/*
+ * TX fragmentation parameters. As above for RTS, we treat
+ * default as implementation-dependent so define it elsewhere.
+ */
+#define IEEE80211_FRAG_MIN 256
+#define IEEE80211_FRAG_MAX 2346
-#endif /* _NETPROTO_802_11_IEEE80211_H_ */
+#endif /* _NET80211_IEEE80211_H_ */
diff -N -u -r src.preview/sys/netproto/802_11/ieee80211_acl.c src/sys/netproto/802_11/ieee80211_acl.c
--- src.preview/sys/netproto/802_11/ieee80211_acl.c 1969-12-31 19:00:00.000000000 -0500
+++ src/sys/netproto/802_11/ieee80211_acl.c 2005-09-23 11:46:00.000000000 -0400
@@ -0,0 +1,357 @@
+/*-
+ * Copyright (c) 2004-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * IEEE 802.11 MAC ACL support.
+ *
+ * When this module is loaded the sender address of each received
+ * frame is passed to the iac_check method and the module indicates
+ * if the frame should be accepted or rejected. If the policy is
+ * set to ACL_POLICY_OPEN then all frames are accepted w/o checking
+ * the address. Otherwise, the address is looked up in the database
+ * and if found the frame is either accepted (ACL_POLICY_ALLOW)
+ * or rejected (ACL_POLICY_DENT).
+ */
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+
+#include <sys/socket.h>
+#include <sys/thread.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/ethernet.h>
+#include <net/route.h>
+
+#include <netproto/802_11/ieee80211_var.h>
+
+enum {
+ ACL_POLICY_OPEN = 0, /* open, don't check ACL's */
+ ACL_POLICY_ALLOW = 1, /* allow traffic from MAC */
+ ACL_POLICY_DENY = 2, /* deny traffic from MAC */
+};
+
+#define ACL_HASHSIZE 32
+
+struct acl {
+ TAILQ_ENTRY(acl) acl_list;
+ LIST_ENTRY(acl) acl_hash;
+ u_int8_t acl_macaddr[IEEE80211_ADDR_LEN];
+};
+struct aclstate {
+ acl_lock_t as_lock;
+ int as_policy;
+ int as_nacls;
+ TAILQ_HEAD(, acl) as_list; /* list of all ACL's */
+ LIST_HEAD(, acl) as_hash[ACL_HASHSIZE];
+ struct ieee80211com *as_ic;
+};
+
+/* simple hash is enough for variation of macaddr */
+#define ACL_HASH(addr) \
+ (((const u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE)
+
+MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl");
+
+static int acl_free_all(struct ieee80211com *);
+
+static int
+acl_attach(struct ieee80211com *ic)
+{
+ struct aclstate *as;
+
+ MALLOC(as, struct aclstate *, sizeof(struct aclstate),
+ M_80211_ACL, M_NOWAIT | M_ZERO);
+ if (as == NULL)
+ return 0;
+ ACL_LOCK_INIT(as, "acl");
+ TAILQ_INIT(&as->as_list);
+ as->as_policy = ACL_POLICY_OPEN;
+ as->as_ic = ic;
+ ic->ic_as = as;
+ return 1;
+}
+
+static void
+acl_detach(struct ieee80211com *ic)
+{
+ struct aclstate *as = ic->ic_as;
+
+ acl_free_all(ic);
+ ic->ic_as = NULL;
+ ACL_LOCK_DESTROY(as);
+ FREE(as, M_DEVBUF);
+}
+
+static __inline struct acl *
+_find_acl(struct aclstate *as, const u_int8_t *macaddr)
+{
+ struct acl *acl;
+ int hash;
+
+ hash = ACL_HASH(macaddr);
+ LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
+ if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
+ return acl;
+ }
+ return NULL;
+}
+
+static void
+_acl_free(struct aclstate *as, struct acl *acl)
+{
+ ACL_LOCK_ASSERT(as);
+
+ TAILQ_REMOVE(&as->as_list, acl, acl_list);
+ LIST_REMOVE(acl, acl_hash);
+ FREE(acl, M_80211_ACL);
+ as->as_nacls--;
+}
+
+static int
+acl_check(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct aclstate *as = ic->ic_as;
+
+ switch (as->as_policy) {
+ case ACL_POLICY_OPEN:
+ return 1;
+ case ACL_POLICY_ALLOW:
+ return _find_acl(as, mac) != NULL;
+ case ACL_POLICY_DENY:
+ return _find_acl(as, mac) == NULL;
+ }
+ return 0; /* should not happen */
+}
+
+static int
+acl_add(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct aclstate *as = ic->ic_as;
+ struct acl *acl, *new;
+ int hash;
+ IEEE80211_LOCK_INFO;
+
+ MALLOC(new, struct acl *, sizeof(struct acl), M_80211_ACL, M_NOWAIT | M_ZERO);
+ if (new == NULL) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ACL,
+ "ACL: add %6D failed, no memory\n", mac, ":");
+ /* XXX statistic */
+ return ENOMEM;
+ }
+
+ ACL_LOCK(as);
+ hash = ACL_HASH(mac);
+ LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
+ if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
+ ACL_UNLOCK(as);
+ FREE(new, M_80211_ACL);
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ACL,
+ "ACL: add %6D failed, already present\n",
+ (mac), ":");
+ return EEXIST;
+ }
+ }
+ IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
+ TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
+ LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
+ as->as_nacls++;
+ ACL_UNLOCK(as);
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ACL,
+ "ACL: add %6D\n", (mac), ":");
+ return 0;
+}
+
+static int
+acl_remove(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct aclstate *as = ic->ic_as;
+ struct acl *acl;
+ IEEE80211_LOCK_INFO;
+
+ ACL_LOCK(as);
+ acl = _find_acl(as, mac);
+ if (acl != NULL)
+ _acl_free(as, acl);
+ ACL_UNLOCK(as);
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ACL,
+ "ACL: remove %6D%s\n", (mac), ":",
+ acl == NULL ? ", not present" : "");
+
+ return (acl == NULL ? ENOENT : 0);
+}
+
+static int
+acl_free_all(struct ieee80211com *ic)
+{
+ struct aclstate *as = ic->ic_as;
+ struct acl *acl;
+ IEEE80211_LOCK_INFO;
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
+
+ ACL_LOCK(as);
+ while ((acl = TAILQ_FIRST(&as->as_list)) != NULL)
+ _acl_free(as, acl);
+ ACL_UNLOCK(as);
+
+ return 0;
+}
+
+static int
+acl_setpolicy(struct ieee80211com *ic, int policy)
+{
+ struct aclstate *as = ic->ic_as;
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ACL,
+ "ACL: set policy to %u\n", policy);
+
+ switch (policy) {
+ case IEEE80211_MACCMD_POLICY_OPEN:
+ as->as_policy = ACL_POLICY_OPEN;
+ break;
+ case IEEE80211_MACCMD_POLICY_ALLOW:
+ as->as_policy = ACL_POLICY_ALLOW;
+ break;
+ case IEEE80211_MACCMD_POLICY_DENY:
+ as->as_policy = ACL_POLICY_DENY;
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
+static int
+acl_getpolicy(struct ieee80211com *ic)
+{
+ struct aclstate *as = ic->ic_as;
+
+ return as->as_policy;
+}
+
+static int
+acl_setioctl(struct ieee80211com *ic, struct ieee80211req *ireq)
+{
+
+ return EINVAL;
+}
+
+static int
+acl_getioctl(struct ieee80211com *ic, struct ieee80211req *ireq)
+{
+ struct aclstate *as = ic->ic_as;
+ struct acl *acl;
+ struct ieee80211req_maclist *ap;
+ int error, space, i;
+ IEEE80211_LOCK_INFO;
+
+ switch (ireq->i_val) {
+ case IEEE80211_MACCMD_POLICY:
+ ireq->i_val = as->as_policy;
+ return 0;
+ case IEEE80211_MACCMD_LIST:
+ space = as->as_nacls * IEEE80211_ADDR_LEN;
+ if (ireq->i_len == 0) {
+ ireq->i_len = space; /* return required space */
+ return 0; /* NB: must not error */
+ }
+ MALLOC(ap, struct ieee80211req_maclist *, space,
+ M_TEMP, M_NOWAIT);
+ if (ap == NULL)
+ return ENOMEM;
+ i = 0;
+ ACL_LOCK(as);
+ TAILQ_FOREACH(acl, &as->as_list, acl_list) {
+ IEEE80211_ADDR_COPY(ap[i].ml_macaddr, acl->acl_macaddr);
+ i++;
+ }
+ ACL_UNLOCK(as);
+ if (ireq->i_len >= space) {
+ error = copyout(ap, ireq->i_data, space);
+ ireq->i_len = space;
+ } else
+ error = copyout(ap, ireq->i_data, ireq->i_len);
+ FREE(ap, M_TEMP);
+ return error;
+ }
+ return EINVAL;
+}
+
+static const struct ieee80211_aclator mac = {
+ .iac_name = "mac",
+ .iac_attach = acl_attach,
+ .iac_detach = acl_detach,
+ .iac_check = acl_check,
+ .iac_add = acl_add,
+ .iac_remove = acl_remove,
+ .iac_flush = acl_free_all,
+ .iac_setpolicy = acl_setpolicy,
+ .iac_getpolicy = acl_getpolicy,
+ .iac_setioctl = acl_setioctl,
+ .iac_getioctl = acl_getioctl,
+};
+
+/*
+ * Module glue.
+ */
+static int
+wlan_acl_modevent(module_t mod, int type, void *unused)
+{
+ switch (type) {
+ case MOD_LOAD:
+ if (bootverbose)
+ printf("wlan: <802.11 MAC ACL support>\n");
+ ieee80211_aclator_register(&mac);
+ return 0;
+ case MOD_UNLOAD:
+ ieee80211_aclator_unregister(&mac);
+ return 0;
+ }
+ return EINVAL;
+}
+
+static moduledata_t wlan_acl_mod = {
+ "wlan_acl",
+ wlan_acl_modevent,
+ 0
+};
+DECLARE_MODULE(wlan_acl, wlan_acl_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(wlan_acl, 1);
+MODULE_DEPEND(wlan_acl, wlan, 1, 1, 1);
diff -N -u -r src.preview/sys/netproto/802_11/ieee80211_crypto.c src/sys/netproto/802_11/ieee80211_crypto.c
--- src.preview/sys/netproto/802_11/ieee80211_crypto.c 2005-06-08 19:29:29.000000000 -0400
+++ src/sys/netproto/802_11/ieee80211_crypto.c 2005-09-23 11:43:12.000000000 -0400
@@ -1,6 +1,6 @@
-/*
+/*-
* Copyright (c) 2001 Atsushi Onoe
- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,295 +28,622 @@
* 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: src/sys/net80211/ieee80211_crypto.c,v 1.3 2003/10/17 23:15:30 sam Exp $
- * $DragonFly: src/sys/netproto/802_11/ieee80211_crypto.c,v 1.2 2005/06/08 23:29:29 hsu Exp $
*/
-#include "opt_inet.h"
+#include <sys/cdefs.h>
+/*
+ * IEEE 802.11 generic crypto support.
+ */
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/mbuf.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
+
#include <sys/socket.h>
-#include <sys/sockio.h>
-#include <sys/endian.h>
-#include <sys/errno.h>
-#include <sys/bus.h>
-#include <sys/proc.h>
-#include <sys/sysctl.h>
-#include <machine/atomic.h>
-
+#include <sys/thread.h>
#include <net/if.h>
-#include <net/if_dl.h>
#include <net/if_media.h>
-#include <net/if_arp.h>
-#include <net/ethernet.h>
-#include <net/if_llc.h>
+#include <net/ethernet.h> /* XXX ETHER_HDR_LEN */
#include <netproto/802_11/ieee80211_var.h>
-#include <net/bpf.h>
+/*
+ * Table of registered cipher modules.
+ */
+static const struct ieee80211_cipher *ciphers[IEEE80211_CIPHER_MAX];
-#ifdef INET
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#endif
-
-#include <crypto/rc4/rc4.h>
-#define arc4_ctxlen() sizeof (struct rc4_state)
-#define arc4_setkey(_c,_k,_l) rc4_init(_c,_k,_l)
-#define arc4_encrypt(_c,_d,_s,_l) rc4_crypt(_c,_s,_d,_l)
+static int _ieee80211_crypto_delkey(struct ieee80211com *,
+ struct ieee80211_key *);
-static void ieee80211_crc_init(void);
-static uint32_t ieee80211_crc_update(uint32_t crc, uint8_t *buf, int len);
+/*
+ * Default "null" key management routines.
+ */
+static int
+null_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
+ ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
+{
+ if (!(&ic->ic_nw_keys[0] <= k &&
+ k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
+ /*
+ * Not in the global key table, the driver should handle this
+ * by allocating a slot in the h/w key table/cache. In
+ * lieu of that return key slot 0 for any unicast key
+ * request. We disallow the request if this is a group key.
+ * This default policy does the right thing for legacy hardware
+ * with a 4 key table. It also handles devices that pass
+ * packets through untouched when marked with the WEP bit
+ * and key index 0.
+ */
+ if (k->wk_flags & IEEE80211_KEY_GROUP)
+ return 0;
+ *keyix = 0; /* NB: use key index 0 for ucast key */
+ } else {
+ *keyix = k - ic->ic_nw_keys;
+ }
+ *rxkeyix = IEEE80211_KEYIX_NONE; /* XXX maybe *keyix? */
+ return 1;
+}
+static int
+null_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
+{
+ return 1;
+}
+static int
+null_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
+ const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ return 1;
+}
+static void null_key_update(struct ieee80211com *ic) {}
+/*
+ * Write-arounds for common operations.
+ */
+static __inline void
+cipher_detach(struct ieee80211_key *key)
+{
+ key->wk_cipher->ic_detach(key);
+}
+
+static __inline void *
+cipher_attach(struct ieee80211com *ic, struct ieee80211_key *key)
+{
+ return key->wk_cipher->ic_attach(ic, key);
+}
+
+/*
+ * Wrappers for driver key management methods.
+ */
+static __inline int
+dev_key_alloc(struct ieee80211com *ic,
+ const struct ieee80211_key *key,
+ ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
+{
+ return ic->ic_crypto.cs_key_alloc(ic, key, keyix, rxkeyix);
+}
+
+static __inline int
+dev_key_delete(struct ieee80211com *ic,
+ const struct ieee80211_key *key)
+{
+ return ic->ic_crypto.cs_key_delete(ic, key);
+}
+
+static __inline int
+dev_key_set(struct ieee80211com *ic, const struct ieee80211_key *key,
+ const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+ return ic->ic_crypto.cs_key_set(ic, key, mac);
+}
+
+/*
+ * Setup crypto support.
+ */
void
-ieee80211_crypto_attach(struct ifnet *ifp)
+ieee80211_crypto_attach(struct ieee80211com *ic)
{
- struct ieee80211com *ic = (void *)ifp;
+ struct ieee80211_crypto_state *cs = &ic->ic_crypto;
+ int i;
+ /* NB: we assume everything is pre-zero'd */
+ cs->cs_def_txkey = IEEE80211_KEYIX_NONE;
+ cs->cs_max_keyix = IEEE80211_WEP_NKID;
+ ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++)
+ ieee80211_crypto_resetkey(ic, &cs->cs_nw_keys[i],
+ IEEE80211_KEYIX_NONE);
/*
- * Setup crypto support.
+ * Initialize the driver key support routines to noop entries.
+ * This is useful especially for the cipher test modules.
*/
- ieee80211_crc_init();
- ic->ic_iv = arc4random();
+ cs->cs_key_alloc = null_key_alloc;
+ cs->cs_key_set = null_key_set;
+ cs->cs_key_delete = null_key_delete;
+ cs->cs_key_update_begin = null_key_update;
+ cs->cs_key_update_end = null_key_update;
}
+/*
+ * Teardown crypto support.
+ */
void
-ieee80211_crypto_detach(struct ifnet *ifp)
+ieee80211_crypto_detach(struct ieee80211com *ic)
{
- struct ieee80211com *ic = (void *)ifp;
+ ieee80211_crypto_delglobalkeys(ic);
+}
- if (ic->ic_wep_ctx != NULL) {
- free(ic->ic_wep_ctx, M_DEVBUF);
- ic->ic_wep_ctx = NULL;
+/*
+ * Register a crypto cipher module.
+ */
+void
+ieee80211_crypto_register(const struct ieee80211_cipher *cip)
+{
+ if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
+ printf("%s: cipher %s has an invalid cipher index %u\n",
+ __func__, cip->ic_name, cip->ic_cipher);
+ return;
+ }
+ if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
+ printf("%s: cipher %s registered with a different template\n",
+ __func__, cip->ic_name);
+ return;
}
+ ciphers[cip->ic_cipher] = cip;
}
-struct mbuf *
-ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag)
+/*
+ * Unregister a crypto cipher module.
+ */
+void
+ieee80211_crypto_unregister(const struct ieee80211_cipher *cip)
{
- struct ieee80211com *ic = (void *)ifp;
- struct mbuf *m, *n, *n0;
- struct ieee80211_frame *wh;
- int i, left, len, moff, noff, kid;
- uint32_t iv, crc;
- uint8_t *ivp;
- void *ctx;
- uint8_t keybuf[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
- uint8_t crcbuf[IEEE80211_WEP_CRCLEN];
-
- n0 = NULL;
- if ((ctx = ic->ic_wep_ctx) == NULL) {
- ctx = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT | M_ZERO); /* XXX */
- if (ctx == NULL) {
- ic->ic_stats.is_crypto_nomem++;
- goto fail;
- }
- ic->ic_wep_ctx = ctx;
+ if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
+ printf("%s: cipher %s has an invalid cipher index %u\n",
+ __func__, cip->ic_name, cip->ic_cipher);
+ return;
}
- m = m0;
- left = m->m_pkthdr.len;
- MGETHDR(n, MB_DONTWAIT, m->m_type);
- n0 = n;
- if (n == NULL) {
- if (txflag)
- ic->ic_stats.is_tx_nombuf++;
- else
- ic->ic_stats.is_rx_nombuf++;
- goto fail;
- }
- M_MOVE_PKTHDR(n, m);
- len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
- if (txflag) {
- n->m_pkthdr.len += len;
- } else {
- n->m_pkthdr.len -= len;
- left -= len;
+ if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
+ printf("%s: cipher %s registered with a different template\n",
+ __func__, cip->ic_name);
+ return;
+ }
+ /* NB: don't complain about not being registered */
+ /* XXX disallow if references */
+ ciphers[cip->ic_cipher] = NULL;
+}
+
+int
+ieee80211_crypto_available(u_int cipher)
+{
+ return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL;
+}
+
+/* XXX well-known names! */
+static const char *cipher_modnames[] = {
+ "wlan_wep", /* IEEE80211_CIPHER_WEP */
+ "wlan_tkip", /* IEEE80211_CIPHER_TKIP */
+ "wlan_aes_ocb", /* IEEE80211_CIPHER_AES_OCB */
+ "wlan_ccmp", /* IEEE80211_CIPHER_AES_CCM */
+ "wlan_ckip", /* IEEE80211_CIPHER_CKIP */
+};
+
+/*
+ * Establish a relationship between the specified key and cipher
+ * and, if necessary, allocate a hardware index from the driver.
+ * Note that when a fixed key index is required it must be specified
+ * and we blindly assign it w/o consulting the driver (XXX).
+ *
+ * This must be the first call applied to a key; all the other key
+ * routines assume wk_cipher is setup.
+ *
+ * Locking must be handled by the caller using:
+ * ieee80211_key_update_begin(ic);
+ * ieee80211_key_update_end(ic);
+ */
+int
+ieee80211_crypto_newkey(struct ieee80211com *ic,
+ int cipher, int flags, struct ieee80211_key *key)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ const struct ieee80211_cipher *cip;
+ ieee80211_keyix keyix, rxkeyix;
+ void *keyctx;
+ int oflags;
+
+ /*
+ * Validate cipher and set reference to cipher routines.
+ */
+ if (cipher >= IEEE80211_CIPHER_MAX) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: invalid cipher %u\n", __func__, cipher);
+ ic->ic_stats.is_crypto_badcipher++;
+ return 0;
}
- n->m_len = MHLEN;
- if (n->m_pkthdr.len >= MINCLSIZE) {
- MCLGET(n, MB_DONTWAIT);
- if (n->m_flags & M_EXT)
- n->m_len = n->m_ext.ext_size;
- }
- len = sizeof(struct ieee80211_frame);
- memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
- wh = mtod(n, struct ieee80211_frame *);
- left -= len;
- moff = len;
- noff = len;
- if (txflag) {
- kid = ic->ic_wep_txkey;
- wh->i_fc[1] |= IEEE80211_FC1_WEP;
- iv = ic->ic_iv;
+ if (cip == NULL) {
/*
- * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
- * (B, 255, N) with 3 <= B < 8
+ * Auto-load cipher module if we have a well-known name
+ * for it. It might be better to use string names rather
+ * than numbers and craft a module name based on the cipher
+ * name; e.g. wlan_cipher_<cipher-name>.
*/
- if (iv >= 0x03ff00 &&
- (iv & 0xf8ff00) == 0x00ff00)
- iv += 0x000100;
- ic->ic_iv = iv + 1;
- /* put iv in little endian to prepare 802.11i */
- ivp = mtod(n, uint8_t *) + noff;
- for (i = 0; i < IEEE80211_WEP_IVLEN; i++) {
- ivp[i] = iv & 0xff;
- iv >>= 8;
+ if (cipher < N(cipher_modnames)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: unregistered cipher %u, load module %s\n",
+ __func__, cipher, cipher_modnames[cipher]);
+ ieee80211_load_module(cipher_modnames[cipher]);
+ /*
+ * If cipher module loaded it should immediately
+ * call ieee80211_crypto_register which will fill
+ * in the entry in the ciphers array.
+ */
+ cip = ciphers[cipher];
}
- ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */
- noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
- } else {
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
- ivp = mtod(m, uint8_t *) + moff;
- kid = ivp[IEEE80211_WEP_IVLEN] >> 6;
- moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
- }
- memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN);
- memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key,
- ic->ic_nw_keys[kid].wk_len);
- arc4_setkey(ctx, keybuf,
- IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len);
-
- /* encrypt with calculating CRC */
- crc = ~0;
- while (left > 0) {
- len = m->m_len - moff;
- if (len == 0) {
- m = m->m_next;
- moff = 0;
- continue;
+ if (cip == NULL) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: unable to load cipher %u, module %s\n",
+ __func__, cipher,
+ cipher < N(cipher_modnames) ?
+ cipher_modnames[cipher] : "<unknown>");
+ ic->ic_stats.is_crypto_nocipher++;
+ return 0;
}
- if (len > n->m_len - noff) {
- len = n->m_len - noff;
- if (len == 0) {
- MGET(n->m_next, MB_DONTWAIT, n->m_type);
- if (n->m_next == NULL) {
- if (txflag)
- ic->ic_stats.is_tx_nombuf++;
- else
- ic->ic_stats.is_rx_nombuf++;
- goto fail;
- }
- n = n->m_next;
- n->m_len = MLEN;
- if (left >= MINCLSIZE) {
- MCLGET(n, MB_DONTWAIT);
- if (n->m_flags & M_EXT)
- n->m_len = n->m_ext.ext_size;
- }
- noff = 0;
- continue;
- }
+ }
+
+ oflags = key->wk_flags;
+ flags &= IEEE80211_KEY_COMMON;
+ /*
+ * If the hardware does not support the cipher then
+ * fallback to a host-based implementation.
+ */
+ if ((ic->ic_caps & (1<<cipher)) == 0) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: no h/w support for cipher %s, falling back to s/w\n",
+ __func__, cip->ic_name);
+ flags |= IEEE80211_KEY_SWCRYPT;
+ }
+ /*
+ * Hardware TKIP with software MIC is an important
+ * combination; we handle it by flagging each key,
+ * the cipher modules honor it.
+ */
+ if (cipher == IEEE80211_CIPHER_TKIP &&
+ (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: no h/w support for TKIP MIC, falling back to s/w\n",
+ __func__);
+ flags |= IEEE80211_KEY_SWMIC;
+ }
+
+ /*
+ * Bind cipher to key instance. Note we do this
+ * after checking the device capabilities so the
+ * cipher module can optimize space usage based on
+ * whether or not it needs to do the cipher work.
+ */
+ if (key->wk_cipher != cip || key->wk_flags != flags) {
+again:
+ /*
+ * Fillin the flags so cipher modules can see s/w
+ * crypto requirements and potentially allocate
+ * different state and/or attach different method
+ * pointers.
+ *
+ * XXX this is not right when s/w crypto fallback
+ * fails and we try to restore previous state.
+ */
+ key->wk_flags = flags;
+ keyctx = cip->ic_attach(ic, key);
+ if (keyctx == NULL) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: unable to attach cipher %s\n",
+ __func__, cip->ic_name);
+ key->wk_flags = oflags; /* restore old flags */
+ ic->ic_stats.is_crypto_attachfail++;
+ return 0;
}
- if (len > left)
- len = left;
- arc4_encrypt(ctx, mtod(n, caddr_t) + noff,
- mtod(m, caddr_t) + moff, len);
- if (txflag)
- crc = ieee80211_crc_update(crc,
- mtod(m, uint8_t *) + moff, len);
- else
- crc = ieee80211_crc_update(crc,
- mtod(n, uint8_t *) + noff, len);
- left -= len;
- moff += len;
- noff += len;
- }
- crc = ~crc;
- if (txflag) {
- *(uint32_t *)crcbuf = htole32(crc);
- if (n->m_len >= noff + sizeof(crcbuf))
- n->m_len = noff + sizeof(crcbuf);
- else {
- n->m_len = noff;
- MGET(n->m_next, MB_DONTWAIT, n->m_type);
- if (n->m_next == NULL) {
- ic->ic_stats.is_tx_nombuf++;
- goto fail;
+ cipher_detach(key);
+ key->wk_cipher = cip; /* XXX refcnt? */
+ key->wk_private = keyctx;
+ }
+ /*
+ * Commit to requested usage so driver can see the flags.
+ */
+ key->wk_flags = flags;
+
+ /*
+ * Ask the driver for a key index if we don't have one.
+ * Note that entries in the global key table always have
+ * an index; this means it's safe to call this routine
+ * for these entries just to setup the reference to the
+ * cipher template. Note also that when using software
+ * crypto we also call the driver to give us a key index.
+ */
+ if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
+ if (!dev_key_alloc(ic, key, &keyix, &rxkeyix)) {
+ /*
+ * Driver has no room; fallback to doing crypto
+ * in the host. We change the flags and start the
+ * procedure over. If we get back here then there's
+ * no hope and we bail. Note that this can leave
+ * the key in a inconsistent state if the caller
+ * continues to use it.
+ */
+ if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
+ ic->ic_stats.is_crypto_swfallback++;
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: no h/w resources for cipher %s, "
+ "falling back to s/w\n", __func__,
+ cip->ic_name);
+ oflags = key->wk_flags;
+ flags |= IEEE80211_KEY_SWCRYPT;
+ if (cipher == IEEE80211_CIPHER_TKIP)
+ flags |= IEEE80211_KEY_SWMIC;
+ goto again;
}
- n = n->m_next;
- n->m_len = sizeof(crcbuf);
- noff = 0;
+ ic->ic_stats.is_crypto_keyfail++;
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: unable to setup cipher %s\n",
+ __func__, cip->ic_name);
+ return 0;
}
- arc4_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
- sizeof(crcbuf));
- } else {
- n->m_len = noff;
- for (noff = 0; noff < sizeof(crcbuf); noff += len) {
- len = sizeof(crcbuf) - noff;
- if (len > m->m_len - moff)
- len = m->m_len - moff;
- if (len > 0)
- arc4_encrypt(ctx, crcbuf + noff,
- mtod(m, caddr_t) + moff, len);
- m = m->m_next;
- moff = 0;
- }
- if (crc != le32toh(*(uint32_t *)crcbuf)) {
-#ifdef IEEE80211_DEBUG
- if (ieee80211_debug) {
- if_printf(ifp, "decrypt CRC error\n");
- if (ieee80211_debug > 1)
- ieee80211_dump_pkt(n0->m_data,
- n0->m_len, -1, -1);
- }
-#endif
- ic->ic_stats.is_rx_decryptcrc++;
- goto fail;
+ key->wk_keyix = keyix;
+ key->wk_rxkeyix = rxkeyix;
+ }
+ return 1;
+#undef N
+}
+
+/*
+ * Remove the key (no locking, for internal use).
+ */
+static int
+_ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
+{
+ ieee80211_keyix keyix;
+
+ KASSERT(key->wk_cipher != NULL, ("No cipher!"));
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n",
+ __func__, key->wk_cipher->ic_name,
+ key->wk_keyix, key->wk_flags,
+ key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
+
+ keyix = key->wk_keyix;
+ if (keyix != IEEE80211_KEYIX_NONE) {
+ /*
+ * Remove hardware entry.
+ */
+ /* XXX key cache */
+ if (!dev_key_delete(ic, key)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: driver did not delete key index %u\n",
+ __func__, keyix);
+ ic->ic_stats.is_crypto_delkey++;
+ /* XXX recovery? */
}
}
- m_freem(m0);
- return n0;
+ cipher_detach(key);
+ memset(key, 0, sizeof(*key));
+ ieee80211_crypto_resetkey(ic, key, IEEE80211_KEYIX_NONE);
+ return 1;
+}
+
+/*
+ * Remove the specified key.
+ */
+int
+ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
+{
+ int status;
+
+ ieee80211_key_update_begin(ic);
+ status = _ieee80211_crypto_delkey(ic, key);
+ ieee80211_key_update_end(ic);
+ return status;
+}
+
+/*
+ * Clear the global key table.
+ */
+void
+ieee80211_crypto_delglobalkeys(struct ieee80211com *ic)
+{
+ int i;
- fail:
- m_freem(m0);
- m_freem(n0);
- return NULL;
+ ieee80211_key_update_begin(ic);
+ for (i = 0; i < IEEE80211_WEP_NKID; i++)
+ (void) _ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[i]);
+ ieee80211_key_update_end(ic);
}
/*
- * CRC 32 -- routine from RFC 2083
+ * Set the contents of the specified key.
+ *
+ * Locking must be handled by the caller using:
+ * ieee80211_key_update_begin(ic);
+ * ieee80211_key_update_end(ic);
*/
+int
+ieee80211_crypto_setkey(struct ieee80211com *ic, struct ieee80211_key *key,
+ const u_int8_t macaddr[IEEE80211_ADDR_LEN])
+{
+ const struct ieee80211_cipher *cip = key->wk_cipher;
+
+ KASSERT(cip != NULL, ("No cipher!"));
-/* Table of CRCs of all 8-bit messages */
-static uint32_t ieee80211_crc_table[256];
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: %s keyix %u flags 0x%x mac %6D rsc %ju tsc %ju len %u\n",
+ __func__, cip->ic_name, key->wk_keyix,
+ key->wk_flags, (macaddr), ":",
+ key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
+
+ /*
+ * Give cipher a chance to validate key contents.
+ * XXX should happen before modifying state.
+ */
+ if (!cip->ic_setkey(key)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: cipher %s rejected key index %u len %u flags 0x%x\n",
+ __func__, cip->ic_name, key->wk_keyix,
+ key->wk_keylen, key->wk_flags);
+ ic->ic_stats.is_crypto_setkey_cipher++;
+ return 0;
+ }
+ if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
+ /* XXX nothing allocated, should not happen */
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "%s: no key index; should not happen!\n", __func__);
+ ic->ic_stats.is_crypto_setkey_nokey++;
+ return 0;
+ }
+ return dev_key_set(ic, key, macaddr);
+}
-/* Make the table for a fast CRC. */
-static void
-ieee80211_crc_init(void)
+/*
+ * Add privacy headers appropriate for the specified key.
+ */
+struct ieee80211_key *
+ieee80211_crypto_encap(struct ieee80211com *ic,
+ struct ieee80211_node *ni, struct mbuf *m)
{
- uint32_t c;
- int n, k;
+ struct ieee80211_key *k;
+ struct ieee80211_frame *wh;
+ const struct ieee80211_cipher *cip;
+ u_int8_t keyid;
- for (n = 0; n < 256; n++) {
- c = (uint32_t)n;
- for (k = 0; k < 8; k++) {
- if (c & 1)
- c = 0xedb88320UL ^ (c >> 1);
- else
- c = c >> 1;
+ /*
+ * Multicast traffic always uses the multicast key.
+ * Otherwise if a unicast key is set we use that and
+ * it is always key index 0. When no unicast key is
+ * set we fall back to the default transmit key.
+ */
+ wh = mtod(m, struct ieee80211_frame *);
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+ ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
+ if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "[%6D] no default transmit key (%s) deftxkey %u\n",
+ (wh->i_addr1), ":", __func__,
+ ic->ic_def_txkey);
+ ic->ic_stats.is_tx_nodefkey++;
+ return NULL;
}
- ieee80211_crc_table[n] = c;
+ keyid = ic->ic_def_txkey;
+ k = &ic->ic_nw_keys[ic->ic_def_txkey];
+ } else {
+ keyid = 0;
+ k = &ni->ni_ucastkey;
}
+ cip = k->wk_cipher;
+ return (cip->ic_encap(k, m, keyid<<6) ? k : NULL);
}
/*
- * Update a running CRC with the bytes buf[0..len-1]--the CRC
- * should be initialized to all 1's, and the transmitted value
- * is the 1's complement of the final running CRC
+ * Validate and strip privacy headers (and trailer) for a
+ * received frame that has the WEP/Privacy bit set.
*/
+struct ieee80211_key *
+ieee80211_crypto_decap(struct ieee80211com *ic,
+ struct ieee80211_node *ni, struct mbuf *m, int hdrlen)
+{
+#define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
+#define IEEE80211_WEP_MINLEN \
+ (sizeof(struct ieee80211_frame) + \
+ IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
+ struct ieee80211_key *k;
+ struct ieee80211_frame *wh;
+ const struct ieee80211_cipher *cip;
+ const u_int8_t *ivp;
+ u_int8_t keyid;
+
+ /* NB: this minimum size data frame could be bigger */
+ if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
+ "%s: WEP data frame too short, len %u\n",
+ __func__, m->m_pkthdr.len);
+ ic->ic_stats.is_rx_tooshort++; /* XXX need unique stat? */
+ return NULL;
+ }
+
+ /*
+ * Locate the key. If unicast and there is no unicast
+ * key then we fall back to the key id in the header.
+ * This assumes unicast keys are only configured when
+ * the key id in the header is meaningless (typically 0).
+ */
+ wh = mtod(m, struct ieee80211_frame *);
+ ivp = mtod(m, const u_int8_t *) + hdrlen; /* XXX contig */
+ keyid = ivp[IEEE80211_WEP_IVLEN];
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+ ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none)
+ k = &ic->ic_nw_keys[keyid >> 6];
+ else
+ k = &ni->ni_ucastkey;
+
+ /*
+ * Insure crypto header is contiguous for all decap work.
+ */
+ cip = k->wk_cipher;
+ if (m->m_len < hdrlen + cip->ic_header &&
+ (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
+ "[%6D] unable to pullup %s header\n",
+ (wh->i_addr2), ":", cip->ic_name);
+ ic->ic_stats.is_rx_wepfail++; /* XXX */
+ return 0;
+ }
+
+ return (cip->ic_decap(k, m, hdrlen) ? k : NULL);
+#undef IEEE80211_WEP_MINLEN
+#undef IEEE80211_WEP_HDRLEN
+}
-static uint32_t
-ieee80211_crc_update(uint32_t crc, uint8_t *buf, int len)
+/*
+ * Append the specified data to the indicated mbuf chain,
+ * Extend the mbuf chain if the new data does not fit in
+ * existing space.
+ *
+ * Return 1 if able to complete the job; otherwise 0.
+ */
+int
+m_append(struct mbuf *m0, int len, c_caddr_t cp)
{
- uint8_t *endbuf;
+ struct mbuf *m, *n;
+ int remainder, space;
- for (endbuf = buf + len; buf < endbuf; buf++)
- crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
- return crc;
+ for (m = m0; m->m_next != NULL; m = m->m_next)
+ ;
+ remainder = len;
+ space = M_TRAILINGSPACE(m);
+ if (space > 0) {
+ /*
+ * Copy into available space.
+ */
+ if (space > remainder)
+ space = remainder;
+ bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
+ m->m_len += space;
+ cp += space, remainder -= space;
+ }
+ while (remainder > 0) {
+ /*
+ * Allocate a new mbuf; could check space
+ * and allocate a cluster instead.
+ */
+ n = m_get(MB_DONTWAIT, m->m_type);
+ if (n == NULL)
+ break;
+ n->m_len = min(MLEN, remainder);
+ bcopy(cp, mtod(n, caddr_t), n->m_len);
+ cp += n->m_len, remainder -= n->m_len;
+ m->m_next = n;
+ m = n;
+ }
+ if (m0->m_flags & M_PKTHDR)
+ m0->m_pkthdr.len += len - remainder;
+ return (remainder == 0);
}
+
+
diff -N -u -r src.preview/sys/netproto/802_11/ieee80211_crypto.h src/sys/netproto/802_11/ieee80211_crypto.h
--- src.preview/sys/netproto/802_11/ieee80211_crypto.h 2004-07-26 12:30:17.000000000 -0400
+++ src/sys/netproto/802_11/ieee80211_crypto.h 2005-09-23 11:46:12.000000000 -0400
@@ -1,6 +1,6 @@
-/*
+/*-
* Copyright (c) 2001 Atsushi Onoe
- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,24 +29,209 @@
* (INCLUDING NEGLIGENCE OR OTH