[haiku-commits] BRANCH waddlesplash-github.freebsd11 [d1413aa07636] in src: add-ons/kernel/drivers/network/wlan/idualwifi3160/dev/iwm libs/compat/freebsd_wlan/net80211

  • From: waddlesplash-github.freebsd11 <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 13 Nov 2017 22:45:34 +0100 (CET)

added 2 changesets to branch 'refs/remotes/waddlesplash-github/freebsd11'
old head: 0000000000000000000000000000000000000000
new head: d1413aa07636d1d602d65bf6cdfdaaaa9e39be4a
overview: https://github.com/waddlesplash/haiku/compare/d1413aa07636

----------------------------------------------------------------------------

2d8975621eca: Initial merge of FreeBSD 11.1 wlan stack.
  
  I've merged all of the net80211 code from FreeBSD 11.1 mainline,
  and made all the "easy"/"moderate" modifications to the compat code,
  but most of the major changes (counter(9), see
  https://dev.haiku-os.org/ticket/12328#comment:7), added mutex functions,
  post-interrupt deferred init, etc. are beyond my skill level to implement.
  
  This should serve as a much cleaner basis than Anarchos' branch (which
  I used as a reference in spots but took very little of directly) for
  @PulkoMandy's (or anyone else's) work during the coding sprint.

d1413aa07636: drivers/network/wlan: Import idualwifi3160 ('iwm' from FreeBSD 
11.)
  
  This is the driver for the chipset in my laptop (Intel Dual Band Wireless-AC 
7265)
  as well as most other chipsets in the "Intel Dual Band" series. Hopefully
  I've followed our naming convention correctly in calling it "idualwifi3160".
  
  I don't have any way to test it (as the preceding commit is unfinished),
  so I didn't attempt to locate the proper firmware that goes with it,
  but I did at least clean up the C99isms in it so that it compiles with GCC2.

                              [ Augustin Cavalier <waddlesplash@xxxxxxxxx> ]

----------------------------------------------------------------------------

105 files changed, 27958 insertions(+), 3972 deletions(-)
src/add-ons/kernel/drivers/network/wlan/Jamfile  |    3 +
.../drivers/network/wlan/idualwifi3160/Jamfile   |   49 +
.../network/wlan/idualwifi3160/dev/iwm/if_iwm.c  | 6191 +++++++++++++++++
.../wlan/idualwifi3160/dev/iwm/if_iwm_binding.c  |  214 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_binding.h  |  113 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_debug.h    |   58 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_led.c      |  182 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_led.h      |   99 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_mac_ctxt.c |  536 ++
.../wlan/idualwifi3160/dev/iwm/if_iwm_mac_ctxt.h |  113 +
.../idualwifi3160/dev/iwm/if_iwm_pcie_trans.c    |  580 ++
.../idualwifi3160/dev/iwm/if_iwm_pcie_trans.h    |  132 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_phy_ctxt.c |  306 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_phy_ctxt.h |  117 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_phy_db.c   |  482 ++
.../wlan/idualwifi3160/dev/iwm/if_iwm_phy_db.h   |  113 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_power.c    |  336 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_power.h    |  100 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_scan.c     |  738 ++
.../wlan/idualwifi3160/dev/iwm/if_iwm_scan.h     |  113 +
.../idualwifi3160/dev/iwm/if_iwm_time_event.c    |  274 +
.../idualwifi3160/dev/iwm/if_iwm_time_event.h    |  113 +
.../wlan/idualwifi3160/dev/iwm/if_iwm_util.c     |  459 ++
.../wlan/idualwifi3160/dev/iwm/if_iwm_util.h     |  122 +
.../wlan/idualwifi3160/dev/iwm/if_iwmreg.h       | 6445 ++++++++++++++++++
.../wlan/idualwifi3160/dev/iwm/if_iwmvar.h       |  534 ++
.../wlan/idualwifi3160/dev/iwm/opt_wlan.h        |    2 +
.../drivers/network/wlan/idualwifi3160/glue.c    |   67 +
src/libs/compat/freebsd_network/Jamfile          |    1 +
.../compat/freebsd_network/compat/net/if_var.h   |    4 +
.../compat/freebsd_network/compat/sys/cdefs.h    |   11 +
.../compat/freebsd_network/compat/sys/conf.h     |    1 +
.../compat/freebsd_network/compat/sys/kernel.h   |    8 +
.../compat/freebsd_network/compat/sys/mbuf.h     |  111 +
.../compat/freebsd_network/compat/sys/sbuf.h     |  111 +
src/libs/compat/freebsd_network/if.c             |    1 +
src/libs/compat/freebsd_network/subr_sbuf.c      |  877 +++
.../compat/freebsd_wlan/net80211/_ieee80211.h    |   14 +-
.../compat/freebsd_wlan/net80211/ieee80211.c     |  784 ++-
.../compat/freebsd_wlan/net80211/ieee80211.h     |  396 +-
.../compat/freebsd_wlan/net80211/ieee80211_acl.c |   28 +-
.../freebsd_wlan/net80211/ieee80211_action.c     |  110 +-
.../freebsd_wlan/net80211/ieee80211_action.h     |    6 +-
.../freebsd_wlan/net80211/ieee80211_adhoc.c      |  122 +-
.../freebsd_wlan/net80211/ieee80211_adhoc.h      |    6 +-
.../freebsd_wlan/net80211/ieee80211_ageq.c       |    2 +
.../freebsd_wlan/net80211/ieee80211_ageq.h       |    6 +-
.../compat/freebsd_wlan/net80211/ieee80211_alq.c |   27 +-
.../compat/freebsd_wlan/net80211/ieee80211_alq.h |    4 +-
.../freebsd_wlan/net80211/ieee80211_amrr.c       |  173 +-
.../freebsd_wlan/net80211/ieee80211_amrr.h       |    6 +-
.../freebsd_wlan/net80211/ieee80211_crypto.c     |   52 +-
.../freebsd_wlan/net80211/ieee80211_crypto.h     |   16 +-
.../net80211/ieee80211_crypto_ccmp.c             |   44 +-
.../net80211/ieee80211_crypto_none.c             |   19 +-
.../net80211/ieee80211_crypto_tkip.c             |   60 +-
.../freebsd_wlan/net80211/ieee80211_crypto_wep.c |   66 +-
.../compat/freebsd_wlan/net80211/ieee80211_ddb.c |   97 +-
.../compat/freebsd_wlan/net80211/ieee80211_dfs.c |  116 +-
.../compat/freebsd_wlan/net80211/ieee80211_dfs.h |   12 +-
.../freebsd_wlan/net80211/ieee80211_haiku.h      |   81 +-
.../freebsd_wlan/net80211/ieee80211_hostap.c     |  171 +-
.../freebsd_wlan/net80211/ieee80211_hostap.h     |   12 +-
.../compat/freebsd_wlan/net80211/ieee80211_ht.c  |  401 +-
.../compat/freebsd_wlan/net80211/ieee80211_ht.h  |   34 +-
.../freebsd_wlan/net80211/ieee80211_hwmp.c       | 1538 +++--
.../freebsd_wlan/net80211/ieee80211_input.c      |  148 +-
.../freebsd_wlan/net80211/ieee80211_input.h      |   78 +-
.../freebsd_wlan/net80211/ieee80211_ioctl.c      |  586 +-
.../freebsd_wlan/net80211/ieee80211_ioctl.h      |   62 +-
.../freebsd_wlan/net80211/ieee80211_mesh.c       | 1512 +++-
.../freebsd_wlan/net80211/ieee80211_mesh.h       |  290 +-
.../freebsd_wlan/net80211/ieee80211_monitor.c    |    8 +-
.../freebsd_wlan/net80211/ieee80211_monitor.h    |    6 +-
.../freebsd_wlan/net80211/ieee80211_node.c       |  618 +-
.../freebsd_wlan/net80211/ieee80211_node.h       |   18 +-
.../freebsd_wlan/net80211/ieee80211_output.c     | 1267 ++--
.../compat/freebsd_wlan/net80211/ieee80211_phy.c |  201 +-
.../compat/freebsd_wlan/net80211/ieee80211_phy.h |   73 +-
.../freebsd_wlan/net80211/ieee80211_power.c      |  161 +-
.../freebsd_wlan/net80211/ieee80211_power.h      |   14 +-
.../freebsd_wlan/net80211/ieee80211_proto.c      |  449 +-
.../freebsd_wlan/net80211/ieee80211_proto.h      |   89 +-
.../freebsd_wlan/net80211/ieee80211_radiotap.c   |   41 +-
.../freebsd_wlan/net80211/ieee80211_radiotap.h   |   27 +-
.../freebsd_wlan/net80211/ieee80211_ratectl.c    |   45 +-
.../freebsd_wlan/net80211/ieee80211_ratectl.h    |   23 +-
.../net80211/ieee80211_ratectl_none.c            |    5 +-
.../freebsd_wlan/net80211/ieee80211_regdomain.c  |   91 +-
.../freebsd_wlan/net80211/ieee80211_regdomain.h  |   17 +-
.../freebsd_wlan/net80211/ieee80211_rssadapt.c   |   16 +-
.../freebsd_wlan/net80211/ieee80211_rssadapt.h   |    6 +-
.../freebsd_wlan/net80211/ieee80211_scan.c       |  737 +-
.../freebsd_wlan/net80211/ieee80211_scan.h       |   53 +-
.../freebsd_wlan/net80211/ieee80211_scan_sta.c   |  132 +-
.../compat/freebsd_wlan/net80211/ieee80211_sta.c |  287 +-
.../compat/freebsd_wlan/net80211/ieee80211_sta.h |   12 +-
.../freebsd_wlan/net80211/ieee80211_superg.c     |  407 +-
.../freebsd_wlan/net80211/ieee80211_superg.h     |   60 +-
[ *** stats truncated: 6 lines dropped *** ]

############################################################################

Commit:      2d8975621eca452cb135153d8d4f57a86beb4bd8
Author:      Augustin Cavalier <waddlesplash@xxxxxxxxx>
Date:        Mon Nov 13 21:30:35 2017 UTC

Initial merge of FreeBSD 11.1 wlan stack.

I've merged all of the net80211 code from FreeBSD 11.1 mainline,
and made all the "easy"/"moderate" modifications to the compat code,
but most of the major changes (counter(9), see
https://dev.haiku-os.org/ticket/12328#comment:7), added mutex functions,
post-interrupt deferred init, etc. are beyond my skill level to implement.

This should serve as a much cleaner basis than Anarchos' branch (which
I used as a reference in spots but took very little of directly) for
@PulkoMandy's (or anyone else's) work during the coding sprint.

----------------------------------------------------------------------------

diff --git a/src/libs/compat/freebsd_network/Jamfile 
b/src/libs/compat/freebsd_network/Jamfile
index 3d7b496..36abb3c 100644
--- a/src/libs/compat/freebsd_network/Jamfile
+++ b/src/libs/compat/freebsd_network/Jamfile
@@ -39,6 +39,7 @@ KernelStaticLibrary libfreebsd_network.a :
        mii.c
        mutex.c
        priv.cpp
+       subr_sbuf.c
        synch.c
        systm.c
        taskqueue.c
diff --git a/src/libs/compat/freebsd_network/compat/net/if_var.h 
b/src/libs/compat/freebsd_network/compat/net/if_var.h
index 6a766f5..ae6f47d 100644
--- a/src/libs/compat/freebsd_network/compat/net/if_var.h
+++ b/src/libs/compat/freebsd_network/compat/net/if_var.h
@@ -181,6 +181,10 @@ struct ifnet {
                (struct ifnet *, struct sockaddr **, struct sockaddr *);
        int     (*if_transmit)          /* initiate output routine */
                (struct ifnet *, struct mbuf *);
+
+       uint64_t (*if_get_counter)       /* get counter values */
+               (if_t, ift_counter);
+
        void    *if_spare1;             /* spare pointer 1 */
        void    *if_spare2;             /* spare pointer 2 */
        void    *if_spare3;             /* spare pointer 3 */
diff --git a/src/libs/compat/freebsd_network/compat/sys/cdefs.h 
b/src/libs/compat/freebsd_network/compat/sys/cdefs.h
index f971269..70a8fb4 100644
--- a/src/libs/compat/freebsd_network/compat/sys/cdefs.h
+++ b/src/libs/compat/freebsd_network/compat/sys/cdefs.h
@@ -307,4 +307,15 @@
 #define        __UNCONST(var)  ((void*)(uintptr_t)(const void *)(var))
 #endif
 
+#if __GNUC_PREREQ__(4,6) && !defined(__cplusplus)
+/* Nothing, gcc 4.6 and higher has _Static_assert built-in */
+#elif defined(__COUNTER__)
+#define        _Static_assert(x, y)    __Static_assert(x, __COUNTER__)
+#define        __Static_assert(x, y)   ___Static_assert(x, y)
+#define        ___Static_assert(x, y)  typedef char __assert_ ## y[(x) ? 1 : 
-1] \
+                               __unused
+#else
+#define        _Static_assert(x, y)    struct __hack
+#endif
+
 #endif
diff --git a/src/libs/compat/freebsd_network/compat/sys/conf.h 
b/src/libs/compat/freebsd_network/compat/sys/conf.h
new file mode 100644
index 0000000..3053583
--- /dev/null
+++ b/src/libs/compat/freebsd_network/compat/sys/conf.h
@@ -0,0 +1 @@
+/* nothing here */
diff --git a/src/libs/compat/freebsd_network/compat/sys/kernel.h 
b/src/libs/compat/freebsd_network/compat/sys/kernel.h
index 0124a68..2503e08 100644
--- a/src/libs/compat/freebsd_network/compat/sys/kernel.h
+++ b/src/libs/compat/freebsd_network/compat/sys/kernel.h
@@ -36,6 +36,14 @@ struct __system_init {
        system_init_func_t func;
 };
 
+typedef void (*ich_func_t)(void *_arg);
+
+struct intr_config_hook {
+       TAILQ_ENTRY(intr_config_hook) ich_links;
+       ich_func_t      ich_func;
+       void            *ich_arg;
+};
+
 /* TODO implement SYSINIT/SYSUNINIT subsystem */
 #define SYSINIT(uniquifier, subsystem, order, func, ident) \
        struct __system_init __init_##uniquifier = { (system_init_func_t) func }
diff --git a/src/libs/compat/freebsd_network/compat/sys/mbuf.h 
b/src/libs/compat/freebsd_network/compat/sys/mbuf.h
index 8c6e6c5..bfac7f7 100644
--- a/src/libs/compat/freebsd_network/compat/sys/mbuf.h
+++ b/src/libs/compat/freebsd_network/compat/sys/mbuf.h
@@ -120,6 +120,17 @@ struct m_ext {
 };
 
 struct mbuf {
+       union { /* next buffer in chain */
+               struct mbuf             *m_next;
+               SLIST_ENTRY(mbuf)       m_slist;
+               STAILQ_ENTRY(mbuf)      m_stailq;
+       };
+       union { /* next chain in queue/record */
+               struct mbuf             *m_nextpkt;
+               SLIST_ENTRY(mbuf)       m_slistpkt;
+               STAILQ_ENTRY(mbuf)      m_stailqpkt;
+       };
+
        struct m_hdr m_hdr;
        union {
                struct {
@@ -221,6 +232,106 @@ m_tag_unlink(struct mbuf* memoryBuffer, struct m_tag* tag)
        SLIST_REMOVE(&memoryBuffer->m_pkthdr.tags, tag, m_tag, m_tag_link);
 }
 
+/* mbufq */
+
+struct mbufq {
+       STAILQ_HEAD(, mbuf)     mq_head;
+       int                     mq_len;
+       int                     mq_maxlen;
+};
+
+static inline void
+mbufq_init(struct mbufq *mq, int maxlen)
+{
+
+       STAILQ_INIT(&mq->mq_head);
+       mq->mq_maxlen = maxlen;
+       mq->mq_len = 0;
+}
+
+static inline struct mbuf *
+mbufq_flush(struct mbufq *mq)
+{
+       struct mbuf *m;
+
+       m = STAILQ_FIRST(&mq->mq_head);
+       STAILQ_INIT(&mq->mq_head);
+       mq->mq_len = 0;
+       return (m);
+}
+
+static inline void
+mbufq_drain(struct mbufq *mq)
+{
+       struct mbuf *m, *n;
+
+       n = mbufq_flush(mq);
+       while ((m = n) != NULL) {
+               n = STAILQ_NEXT(m, m_stailqpkt);
+               m_freem(m);
+       }
+}
+
+static inline struct mbuf *
+mbufq_first(const struct mbufq *mq)
+{
+
+       return (STAILQ_FIRST(&mq->mq_head));
+}
+
+static inline struct mbuf *
+mbufq_last(const struct mbufq *mq)
+{
+
+       return (STAILQ_LAST(&mq->mq_head, mbuf, m_stailqpkt));
+}
+
+static inline int
+mbufq_full(const struct mbufq *mq)
+{
+
+       return (mq->mq_len >= mq->mq_maxlen);
+}
+
+static inline int
+mbufq_len(const struct mbufq *mq)
+{
+
+       return (mq->mq_len);
+}
+
+static inline int
+mbufq_enqueue(struct mbufq *mq, struct mbuf *m)
+{
+
+       if (mbufq_full(mq))
+               return (ENOBUFS);
+       STAILQ_INSERT_TAIL(&mq->mq_head, m, m_stailqpkt);
+       mq->mq_len++;
+       return (0);
+}
+
+static inline struct mbuf *
+mbufq_dequeue(struct mbufq *mq)
+{
+       struct mbuf *m;
+
+       m = STAILQ_FIRST(&mq->mq_head);
+       if (m) {
+               STAILQ_REMOVE_HEAD(&mq->mq_head, m_stailqpkt);
+               m->m_nextpkt = NULL;
+               mq->mq_len--;
+       }
+       return (m);
+}
+
+static inline void
+mbufq_prepend(struct mbufq *mq, struct mbuf *m)
+{
+
+       STAILQ_INSERT_HEAD(&mq->mq_head, m, m_stailqpkt);
+       mq->mq_len++;
+}
 
 #include <sys/mbuf-fbsd.h>
 
diff --git a/src/libs/compat/freebsd_network/compat/sys/sbuf.h 
b/src/libs/compat/freebsd_network/compat/sys/sbuf.h
new file mode 100644
index 0000000..9513604
--- /dev/null
+++ b/src/libs/compat/freebsd_network/compat/sys/sbuf.h
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2000-2008 Poul-Henning Kamp
+ * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav
+ * 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
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      $FreeBSD$
+ */
+
+#ifndef _SYS_SBUF_H_
+#define        _SYS_SBUF_H_
+
+#include <sys/_types.h>
+
+struct sbuf;
+typedef int (sbuf_drain_func)(void *, const char *, int);
+
+/*
+ * Structure definition
+ */
+struct sbuf {
+       char            *s_buf;         /* storage buffer */
+       sbuf_drain_func *s_drain_func;  /* drain function */
+       void            *s_drain_arg;   /* user-supplied drain argument */
+       int              s_error;       /* current error code */
+       ssize_t          s_size;        /* size of storage buffer */
+       ssize_t          s_len;         /* current length of string */
+#define        SBUF_FIXEDLEN   0x00000000      /* fixed length buffer 
(default) */
+#define        SBUF_AUTOEXTEND 0x00000001      /* automatically extend buffer 
*/
+#define        SBUF_INCLUDENUL 0x00000002      /* nulterm byte is counted in 
len */
+#define        SBUF_USRFLAGMSK 0x0000ffff      /* mask of flags the user may 
specify */
+#define        SBUF_DYNAMIC    0x00010000      /* s_buf must be freed */
+#define        SBUF_FINISHED   0x00020000      /* set by sbuf_finish() */
+#define        SBUF_DYNSTRUCT  0x00080000      /* sbuf must be freed */
+#define        SBUF_INSECTION  0x00100000      /* set by sbuf_start_section() 
*/
+       int              s_flags;       /* flags */
+       ssize_t          s_sect_len;    /* current length of section */
+};
+
+#ifndef HD_COLUMN_MASK
+#define        HD_COLUMN_MASK  0xff
+#define        HD_DELIM_MASK   0xff00
+#define        HD_OMIT_COUNT   (1 << 16)
+#define        HD_OMIT_HEX     (1 << 17)
+#define        HD_OMIT_CHARS   (1 << 18)
+#endif /* HD_COLUMN_MASK */
+
+__BEGIN_DECLS
+/*
+ * API functions
+ */
+struct sbuf    *sbuf_new(struct sbuf *, char *, int, int);
+#define                 sbuf_new_auto()                                \
+       sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND)
+int             sbuf_get_flags(struct sbuf *);
+void            sbuf_clear_flags(struct sbuf *, int);
+void            sbuf_set_flags(struct sbuf *, int);
+void            sbuf_clear(struct sbuf *);
+int             sbuf_setpos(struct sbuf *, ssize_t);
+int             sbuf_bcat(struct sbuf *, const void *, size_t);
+int             sbuf_bcpy(struct sbuf *, const void *, size_t);
+int             sbuf_cat(struct sbuf *, const char *);
+int             sbuf_cpy(struct sbuf *, const char *);
+int             sbuf_printf(struct sbuf *, const char *, ...)
+       __printflike(2, 3);
+int             sbuf_vprintf(struct sbuf *, const char *, __va_list)
+       __printflike(2, 0);
+int             sbuf_putc(struct sbuf *, int);
+void            sbuf_set_drain(struct sbuf *, sbuf_drain_func *, void *);
+int             sbuf_trim(struct sbuf *);
+int             sbuf_error(const struct sbuf *);
+int             sbuf_finish(struct sbuf *);
+char           *sbuf_data(struct sbuf *);
+ssize_t                 sbuf_len(struct sbuf *);
+int             sbuf_done(const struct sbuf *);
+void            sbuf_delete(struct sbuf *);
+void            sbuf_start_section(struct sbuf *, ssize_t *);
+ssize_t                 sbuf_end_section(struct sbuf *, ssize_t, size_t, int);
+void            sbuf_hexdump(struct sbuf *, const void *, int, const char *,
+                    int);
+
+#if 0
+struct uio;
+struct sbuf    *sbuf_uionew(struct sbuf *, struct uio *, int *);
+int             sbuf_bcopyin(struct sbuf *, const void *, size_t);
+int             sbuf_copyin(struct sbuf *, const void *, size_t);
+#endif
+__END_DECLS
+
+#endif
diff --git a/src/libs/compat/freebsd_network/if.c 
b/src/libs/compat/freebsd_network/if.c
index dc67514..554a089 100644
--- a/src/libs/compat/freebsd_network/if.c
+++ b/src/libs/compat/freebsd_network/if.c
@@ -676,6 +676,7 @@ ether_ifattach(struct ifnet *ifp, const uint8_t *macAddress)
        ifp->if_output = ether_output;
        ifp->if_input = ether_input;
        ifp->if_resolvemulti = NULL; // done in the stack
+       ifp->if_get_counter = NULL;
        ifp->if_broadcastaddr = etherbroadcastaddr;
 
        memcpy(IF_LLADDR(ifp), macAddress, ETHER_ADDR_LEN);
diff --git a/src/libs/compat/freebsd_network/subr_sbuf.c 
b/src/libs/compat/freebsd_network/subr_sbuf.c
new file mode 100644
index 0000000..087359c
--- /dev/null
+++ b/src/libs/compat/freebsd_network/subr_sbuf.c
@@ -0,0 +1,877 @@
+/*-
+ * Copyright (c) 2000-2008 Poul-Henning Kamp
+ * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav
+ * 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
+ *    in this position and unchanged.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#ifdef _KERNEL
+#include <sys/ctype.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <machine/stdarg.h>
+#else /* _KERNEL */
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* _KERNEL */
+
+#include <sys/sbuf.h>
+
+#ifdef _KERNEL
+//static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
+#define        SBMALLOC(size)          malloc(size)
+#define        SBFREE(buf)             free(buf)
+#else /* _KERNEL */
+#define        KASSERT(e, m)
+#define        SBMALLOC(size)          calloc(1, size)
+#define        SBFREE(buf)             free(buf)
+#endif /* _KERNEL */
+
+/*
+ * Predicates
+ */
+#define        SBUF_ISDYNAMIC(s)       ((s)->s_flags & SBUF_DYNAMIC)
+#define        SBUF_ISDYNSTRUCT(s)     ((s)->s_flags & SBUF_DYNSTRUCT)
+#define        SBUF_ISFINISHED(s)      ((s)->s_flags & SBUF_FINISHED)
+#define        SBUF_HASROOM(s)         ((s)->s_len < (s)->s_size - 1)
+#define        SBUF_FREESPACE(s)       ((s)->s_size - ((s)->s_len + 1))
+#define        SBUF_CANEXTEND(s)       ((s)->s_flags & SBUF_AUTOEXTEND)
+#define        SBUF_ISSECTION(s)       ((s)->s_flags & SBUF_INSECTION)
+#define        SBUF_NULINCLUDED(s)     ((s)->s_flags & SBUF_INCLUDENUL)
+
+/*
+ * Set / clear flags
+ */
+#define        SBUF_SETFLAG(s, f)      do { (s)->s_flags |= (f); } while (0)
+#define        SBUF_CLEARFLAG(s, f)    do { (s)->s_flags &= ~(f); } while (0)
+
+#define        SBUF_MINSIZE             2              /* Min is 1 byte + 
nulterm. */
+#define        SBUF_MINEXTENDSIZE      16              /* Should be power of 
2. */
+
+#ifdef PAGE_SIZE
+#define        SBUF_MAXEXTENDSIZE      PAGE_SIZE
+#define        SBUF_MAXEXTENDINCR      PAGE_SIZE
+#else
+#define        SBUF_MAXEXTENDSIZE      4096
+#define        SBUF_MAXEXTENDINCR      4096
+#endif
+
+/*
+ * Debugging support
+ */
+#if defined(_KERNEL) && defined(INVARIANTS)
+
+static void
+_assert_sbuf_integrity(const char *fun, struct sbuf *s)
+{
+
+       KASSERT(s != NULL,
+           ("%s called with a NULL sbuf pointer", fun));
+       KASSERT(s->s_buf != NULL,
+           ("%s called with uninitialized or corrupt sbuf", fun));
+        if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
+               KASSERT(s->s_len <= s->s_size,
+                   ("wrote past end of sbuf (%jd >= %jd)",
+                   (intmax_t)s->s_len, (intmax_t)s->s_size));
+       } else {
+               KASSERT(s->s_len < s->s_size,
+                   ("wrote past end of sbuf (%jd >= %jd)",
+                   (intmax_t)s->s_len, (intmax_t)s->s_size));
+       }
+}
+
+static void
+_assert_sbuf_state(const char *fun, struct sbuf *s, int state)
+{
+
+       KASSERT((s->s_flags & SBUF_FINISHED) == state,
+           ("%s called with %sfinished or corrupt sbuf", fun,
+           (state ? "un" : "")));
+}
+
+#define        assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
+#define        assert_sbuf_state(s, i)  _assert_sbuf_state(__func__, (s), (i))
+
+#else /* _KERNEL && INVARIANTS */
+
+#define        assert_sbuf_integrity(s) do { } while (0)
+#define        assert_sbuf_state(s, i)  do { } while (0)
+
+#endif /* _KERNEL && INVARIANTS */
+
+#if 0
+CTASSERT(powerof2(SBUF_MAXEXTENDSIZE));
+CTASSERT(powerof2(SBUF_MAXEXTENDINCR));
+#endif
+
+static int
+sbuf_extendsize(int size)
+{
+       int newsize;
+
+       if (size < (int)SBUF_MAXEXTENDSIZE) {
+               newsize = SBUF_MINEXTENDSIZE;
+               while (newsize < size)
+                       newsize *= 2;
+       } else {
+               newsize = roundup2(size, SBUF_MAXEXTENDINCR);
+       }
+       KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
+       return (newsize);
+}
+
+/*
+ * Extend an sbuf.
+ */
+static int
+sbuf_extend(struct sbuf *s, int addlen)
+{
+       char *newbuf;
+       int newsize;
+
+       if (!SBUF_CANEXTEND(s))
+               return (-1);
+       newsize = sbuf_extendsize(s->s_size + addlen);
+       newbuf = SBMALLOC(newsize);
+       if (newbuf == NULL)
+               return (-1);
+       memcpy(newbuf, s->s_buf, s->s_size);
+       if (SBUF_ISDYNAMIC(s))
+               SBFREE(s->s_buf);
+       else
+               SBUF_SETFLAG(s, SBUF_DYNAMIC);
+       s->s_buf = newbuf;
+       s->s_size = newsize;
+       return (0);
+}
+
+/*
+ * Initialize the internals of an sbuf.
+ * If buf is non-NULL, it points to a static or already-allocated string
+ * big enough to hold at least length characters.
+ */
+static struct sbuf *
+sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags)
+{
+
+       memset(s, 0, sizeof(*s));
+       s->s_flags = flags;
+       s->s_size = length;
+       s->s_buf = buf;
+
+       if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
+               KASSERT(s->s_size >= SBUF_MINSIZE,
+                   ("attempt to create an sbuf smaller than %d bytes",
+                   SBUF_MINSIZE));
+       }
+
+       if (s->s_buf != NULL)
+               return (s);
+
+       if ((flags & SBUF_AUTOEXTEND) != 0)
+               s->s_size = sbuf_extendsize(s->s_size);
+
+       s->s_buf = SBMALLOC(s->s_size);
+       if (s->s_buf == NULL)
+               return (NULL);
+       SBUF_SETFLAG(s, SBUF_DYNAMIC);
+       return (s);
+}
+
+/*
+ * Initialize an sbuf.
+ * If buf is non-NULL, it points to a static or already-allocated string
+ * big enough to hold at least length characters.
+ */
+struct sbuf *
+sbuf_new(struct sbuf *s, char *buf, int length, int flags)
+{
+
+       KASSERT(length >= 0,
+           ("attempt to create an sbuf of negative length (%d)", length));
+       KASSERT((flags & ~SBUF_USRFLAGMSK) == 0,
+           ("%s called with invalid flags", __func__));
+
+       flags &= SBUF_USRFLAGMSK;
+       if (s != NULL)
+               return (sbuf_newbuf(s, buf, length, flags));
+
+       s = SBMALLOC(sizeof(*s));
+       if (s == NULL)
+               return (NULL);
+       if (sbuf_newbuf(s, buf, length, flags) == NULL) {
+               SBFREE(s);
+               return (NULL);
+       }
+       SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
+       return (s);
+}
+
+#if 0
+/*
+ * Create an sbuf with uio data
+ */
+struct sbuf *
+sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
+{
+
+       KASSERT(uio != NULL,
+           ("%s called with NULL uio pointer", __func__));
+       KASSERT(error != NULL,
+           ("%s called with NULL error pointer", __func__));
+
+       s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
+       if (s == NULL) {
+               *error = ENOMEM;
+               return (NULL);
+       }
+       *error = uiomove(s->s_buf, uio->uio_resid, uio);
+       if (*error != 0) {
+               sbuf_delete(s);
+               return (NULL);
+       }
+       s->s_len = s->s_size - 1;
+       if (SBUF_ISSECTION(s))
+               s->s_sect_len = s->s_size - 1;
+       *error = 0;
+       return (s);
+}
+#endif
+
+int
+sbuf_get_flags(struct sbuf *s)
+{
+
+       return (s->s_flags & SBUF_USRFLAGMSK);
+}
+
+void
+sbuf_clear_flags(struct sbuf *s, int flags)
+{
+
+       s->s_flags &= ~(flags & SBUF_USRFLAGMSK);
+}
+
+void
+sbuf_set_flags(struct sbuf *s, int flags)
+{
+
+
+       s->s_flags |= (flags & SBUF_USRFLAGMSK);
+}
+
+/*
+ * Clear an sbuf and reset its position.
+ */
+void
+sbuf_clear(struct sbuf *s)
+{
+
+       assert_sbuf_integrity(s);
+       /* don't care if it's finished or not */
+
+       SBUF_CLEARFLAG(s, SBUF_FINISHED);
+       s->s_error = 0;
+       s->s_len = 0;
+       s->s_sect_len = 0;
+}
+
+/*
+ * Set the sbuf's end position to an arbitrary value.
+ * Effectively truncates the sbuf at the new position.
+ */
+int
+sbuf_setpos(struct sbuf *s, ssize_t pos)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       KASSERT(pos >= 0,
+           ("attempt to seek to a negative position (%jd)", (intmax_t)pos));
+       KASSERT(pos < s->s_size,
+           ("attempt to seek past end of sbuf (%jd >= %jd)",
+           (intmax_t)pos, (intmax_t)s->s_size));
+       KASSERT(!SBUF_ISSECTION(s),
+           ("attempt to seek when in a section"));
+
+       if (pos < 0 || pos > s->s_len)
+               return (-1);
+       s->s_len = pos;
+       return (0);
+}
+
+/*
+ * Set up a drain function and argument on an sbuf to flush data to
+ * when the sbuf buffer overflows.
+ */
+void
+sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx)
+{
+
+       assert_sbuf_state(s, 0);
+       assert_sbuf_integrity(s);
+       KASSERT(func == s->s_drain_func || s->s_len == 0,
+           ("Cannot change drain to %p on non-empty sbuf %p", func, s));
+       s->s_drain_func = func;
+       s->s_drain_arg = ctx;
+}
+
+/*
+ * Call the drain and process the return.
+ */
+static int
+sbuf_drain(struct sbuf *s)
+{
+       int len;
+
+       KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s));
+       KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s));
+       len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len);
+       if (len < 0) {
+               s->s_error = -len;
+               return (s->s_error);
+       }
+       KASSERT(len > 0 && len <= s->s_len,
+           ("Bad drain amount %d for sbuf %p", len, s));
+       s->s_len -= len;
+       /*
+        * Fast path for the expected case where all the data was
+        * drained.
+        */
+       if (s->s_len == 0)
+               return (0);
+       /*
+        * Move the remaining characters to the beginning of the
+        * string.
+        */
+       memmove(s->s_buf, s->s_buf + len, s->s_len);
+       return (0);
+}
+
+/*
+ * Append bytes to an sbuf.  This is the core function for appending
+ * to an sbuf and is the main place that deals with extending the
+ * buffer and marking overflow.
+ */
+static void
+sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len)
+{
+       size_t n;
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       if (s->s_error != 0)
+               return;
+       while (len > 0) {
+               if (SBUF_FREESPACE(s) <= 0) {
+                       /*
+                        * If there is a drain, use it, otherwise extend the
+                        * buffer.
+                        */
+                       if (s->s_drain_func != NULL)
+                               (void)sbuf_drain(s);
+                       else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len)
+                           < 0)
+                               s->s_error = ENOMEM;
+                       if (s->s_error != 0)
+                               return;
+               }
+               n = SBUF_FREESPACE(s);
+               if (len < n)
+                       n = len;
+               memcpy(&s->s_buf[s->s_len], buf, n);
+               s->s_len += n;
+               if (SBUF_ISSECTION(s))
+                       s->s_sect_len += n;
+               len -= n;
+               buf += n;
+       }
+}
+
+static void
+sbuf_put_byte(struct sbuf *s, char c)
+{
+
+       sbuf_put_bytes(s, &c, 1);
+}
+
+/*
+ * Append a byte string to an sbuf.
+ */
+int
+sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
+{
+
+       sbuf_put_bytes(s, buf, len);
+       if (s->s_error != 0)
+               return (-1);
+       return (0);
+}
+
+#ifdef _KERNEL
+/*
+ * Copy a byte string from userland into an sbuf.
+ */
+int
+sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+       KASSERT(s->s_drain_func == NULL,
+           ("Nonsensical copyin to sbuf %p with a drain", s));
+
+       if (s->s_error != 0)
+               return (-1);
+       if (len == 0)
+               return (0);
+       if (len > SBUF_FREESPACE(s)) {
+               sbuf_extend(s, len - SBUF_FREESPACE(s));
+               if (SBUF_FREESPACE(s) < len)
+                       len = SBUF_FREESPACE(s);
+       }
+       if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
+               return (-1);
+       s->s_len += len;
+
+       return (0);
+}
+#endif
+
+/*
+ * Copy a byte string into an sbuf.
+ */
+int
+sbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       sbuf_clear(s);
+       return (sbuf_bcat(s, buf, len));
+}
+
+/*
+ * Append a string to an sbuf.
+ */
+int
+sbuf_cat(struct sbuf *s, const char *str)
+{
+       size_t n;
+
+       n = strlen(str);
+       sbuf_put_bytes(s, str, n);
+       if (s->s_error != 0)
+               return (-1);
+       return (0);
+}
+
+#if 0
+/*
+ * Append a string from userland to an sbuf.
+ */
+int
+sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
+{
+       size_t done;
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+       KASSERT(s->s_drain_func == NULL,
+           ("Nonsensical copyin to sbuf %p with a drain", s));
+
+       if (s->s_error != 0)
+               return (-1);
+
+       if (len == 0)
+               len = SBUF_FREESPACE(s);        /* XXX return 0? */
+       if (len > SBUF_FREESPACE(s)) {
+               sbuf_extend(s, len);
+               if (SBUF_FREESPACE(s) < len)
+                       len = SBUF_FREESPACE(s);
+       }
+       switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
+       case ENAMETOOLONG:
+               s->s_error = ENOMEM;
+               /* fall through */
+       case 0:
+               s->s_len += done - 1;
+               if (SBUF_ISSECTION(s))
+                       s->s_sect_len += done - 1;
+               break;
+       default:
+               return (-1);    /* XXX */
+       }
+
+       return (done);
+}
+#endif
+
+/*
+ * Copy a string into an sbuf.
+ */
+int
+sbuf_cpy(struct sbuf *s, const char *str)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       sbuf_clear(s);
+       return (sbuf_cat(s, str));
+}
+
+/*
+ * Format the given argument list and append the resulting string to an sbuf.
+ */
+#if 0
+
+/*
+ * Append a non-NUL character to an sbuf.  This prototype signature is
+ * suitable for use with kvprintf(9).
+ */
+static void
+sbuf_putc_func(int c, void *arg)
+{
+
+       if (c != '\0')
+               sbuf_put_byte(arg, c);
+}
+
+int
+sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       KASSERT(fmt != NULL,
+           ("%s called with a NULL format string", __func__));
+
+       (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap);
+       if (s->s_error != 0)
+               return (-1);
+       return (0);
+}
+#else /* !_KERNEL */
+int
+sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
+{
+       va_list ap_copy;
+       int error, len;
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       KASSERT(fmt != NULL,
+           ("%s called with a NULL format string", __func__));
+
+       if (s->s_error != 0)
+               return (-1);
+
+       /*
+        * For the moment, there is no way to get vsnprintf(3) to hand
+        * back a character at a time, to push everything into
+        * sbuf_putc_func() as was done for the kernel.
+        *
+        * In userspace, while drains are useful, there's generally
+        * not a problem attempting to malloc(3) on out of space.  So
+        * expand a userland sbuf if there is not enough room for the
+        * data produced by sbuf_[v]printf(3).
+        */
+
+       error = 0;
+       do {
+               va_copy(ap_copy, ap);
+               len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
+                   fmt, ap_copy);
+               if (len < 0) {
+                       s->s_error = errno;
+                       return (-1);
+               }
+               va_end(ap_copy);
+
+               if (SBUF_FREESPACE(s) >= len)
+                       break;
+               /* Cannot print with the current available space. */
+               if (s->s_drain_func != NULL && s->s_len > 0)
+                       error = sbuf_drain(s);
+               else
+                       error = sbuf_extend(s, len - SBUF_FREESPACE(s));
+       } while (error == 0);
+
+       /*
+        * s->s_len is the length of the string, without the terminating nul.
+        * When updating s->s_len, we must subtract 1 from the length that
+        * we passed into vsnprintf() because that length includes the
+        * terminating nul.
+        *
+        * vsnprintf() returns the amount that would have been copied,
+        * given sufficient space, so don't over-increment s_len.
+        */
+       if (SBUF_FREESPACE(s) < len)
+               len = SBUF_FREESPACE(s);
+       s->s_len += len;
+       if (SBUF_ISSECTION(s))
+               s->s_sect_len += len;
+       if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s))
+               s->s_error = ENOMEM;
+
+       KASSERT(s->s_len < s->s_size,
+           ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
+
+       if (s->s_error != 0)
+               return (-1);
+       return (0);
+}
+#endif /* _KERNEL */
+
+/*
+ * Format the given arguments and append the resulting string to an sbuf.
+ */
+int
+sbuf_printf(struct sbuf *s, const char *fmt, ...)
+{
+       va_list ap;
+       int result;
+
+       va_start(ap, fmt);
+       result = sbuf_vprintf(s, fmt, ap);
+       va_end(ap);
+       return (result);
+}
+
+/*
+ * Append a character to an sbuf.
+ */
+int
+sbuf_putc(struct sbuf *s, int c)
+{
+
+       sbuf_put_byte(s, c);
+       if (s->s_error != 0)
+               return (-1);
+       return (0);
+}
+
+/*
+ * Trim whitespace characters from end of an sbuf.
+ */
+#define isspace(c) ((c) == ' ' || (c) == '\t')
+int
+sbuf_trim(struct sbuf *s)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+       KASSERT(s->s_drain_func == NULL,
+           ("%s makes no sense on sbuf %p with drain", __func__, s));
+
+       if (s->s_error != 0)
+               return (-1);
+
+       while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) {
+               --s->s_len;
+               if (SBUF_ISSECTION(s))
+                       s->s_sect_len--;
+       }
+
+       return (0);
+}
+
+/*
+ * Check if an sbuf has an error.
+ */
+int
+sbuf_error(const struct sbuf *s)
+{
+
+       return (s->s_error);
+}
+
+/*
+ * Finish off an sbuf.
+ */
+int
+sbuf_finish(struct sbuf *s)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       s->s_buf[s->s_len] = '\0';
+       if (SBUF_NULINCLUDED(s))
+               s->s_len++;
+       if (s->s_drain_func != NULL) {
+               while (s->s_len > 0 && s->s_error == 0)
+                       s->s_error = sbuf_drain(s);
+       }
+       SBUF_SETFLAG(s, SBUF_FINISHED);
+#ifdef _KERNEL
+       return (s->s_error);
+#else
+       if (s->s_error != 0) {
+               errno = s->s_error;
+               return (-1);
+       }
+       return (0);
+#endif
+}
+
+/*
+ * Return a pointer to the sbuf data.
+ */
+char *
+sbuf_data(struct sbuf *s)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, SBUF_FINISHED);
+       KASSERT(s->s_drain_func == NULL,
+           ("%s makes no sense on sbuf %p with drain", __func__, s));
+
+       return (s->s_buf);
+}
+
+/*
+ * Return the length of the sbuf data.
+ */
+ssize_t
+sbuf_len(struct sbuf *s)
+{
+
+       assert_sbuf_integrity(s);
+       /* don't care if it's finished or not */
+       KASSERT(s->s_drain_func == NULL,
+           ("%s makes no sense on sbuf %p with drain", __func__, s));
+
+       if (s->s_error != 0)
+               return (-1);
+
+       /* If finished, nulterm is already in len, else add one. */
+       if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s))
+               return (s->s_len + 1);
+       return (s->s_len);
+}
+
+/*
+ * Clear an sbuf, free its buffer if necessary.
+ */
+void
+sbuf_delete(struct sbuf *s)
+{
+       int isdyn;
+
+       assert_sbuf_integrity(s);
+       /* don't care if it's finished or not */
+
+       if (SBUF_ISDYNAMIC(s))
+               SBFREE(s->s_buf);
+       isdyn = SBUF_ISDYNSTRUCT(s);
+       memset(s, 0, sizeof(*s));
+       if (isdyn)
+               SBFREE(s);
+}
+
+/*
+ * Check if an sbuf has been finished.
+ */
+int
+sbuf_done(const struct sbuf *s)
+{
+
+       return (SBUF_ISFINISHED(s));
+}
+
+/*
+ * Start a section.
+ */
+void
+sbuf_start_section(struct sbuf *s, ssize_t *old_lenp)
+{
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+
+       if (!SBUF_ISSECTION(s)) {
+               KASSERT(s->s_sect_len == 0,
+                   ("s_sect_len != 0 when starting a section"));
+               if (old_lenp != NULL)
+                       *old_lenp = -1;
+               SBUF_SETFLAG(s, SBUF_INSECTION);
+       } else {
+               KASSERT(old_lenp != NULL,
+                   ("s_sect_len should be saved when starting a subsection"));
+               *old_lenp = s->s_sect_len;
+               s->s_sect_len = 0;
+       }
+}
+
+/*
+ * End the section padding to the specified length with the specified
+ * character.
+ */
+ssize_t
+sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c)
+{
+       ssize_t len;
+
+       assert_sbuf_integrity(s);
+       assert_sbuf_state(s, 0);
+       KASSERT(SBUF_ISSECTION(s),
+           ("attempt to end a section when not in a section"));
+
+       if (pad > 1) {
+               len = roundup(s->s_sect_len, pad) - s->s_sect_len;
+               for (; s->s_error == 0 && len > 0; len--)
+                       sbuf_put_byte(s, c);
+       }
+       len = s->s_sect_len;
+       if (old_len == -1) {
+               s->s_sect_len = 0;
+               SBUF_CLEARFLAG(s, SBUF_INSECTION);
+       } else {
+               s->s_sect_len += old_len;
+       }
+       if (s->s_error != 0)
+               return (-1);
+       return (len);
+}
diff --git a/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h 
b/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h
index 7cbc684..7cb524b 100644
--- a/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h
+++ b/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h
@@ -70,6 +70,7 @@ enum ieee80211_phymode {
        IEEE80211_MODE_QUARTER  = 11,   /* OFDM, 1/4x clock */
 };
 #define        IEEE80211_MODE_MAX      (IEEE80211_MODE_QUARTER+1)
+#define        IEEE80211_MODE_BYTES    howmany(IEEE80211_MODE_MAX, NBBY)
 
 /*
  * Operating mode.  Devices do not necessarily support
@@ -146,7 +147,7 @@ struct ieee80211_channel {
 };
 
 #define        IEEE80211_CHAN_MAX      256
-#define        IEEE80211_CHAN_BYTES    32      /* howmany(IEEE80211_CHAN_MAX, 
NBBY) */
+#define        IEEE80211_CHAN_BYTES    howmany(IEEE80211_CHAN_MAX, NBBY)
 #define        IEEE80211_CHAN_ANY      0xffff  /* token for ``any channel'' */
 #define        IEEE80211_CHAN_ANYC \
        ((struct ieee80211_channel *) IEEE80211_CHAN_ANY)
@@ -242,6 +243,8 @@ struct ieee80211_channel {
        (((_c)->ic_flags & (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN)) != 0)
 #define        IEEE80211_IS_CHAN_CCK(_c) \
        (((_c)->ic_flags & (IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN)) != 0)
+#define        IEEE80211_IS_CHAN_DYN(_c) \
+       (((_c)->ic_flags & IEEE80211_CHAN_DYN) == IEEE80211_CHAN_DYN)
 #define        IEEE80211_IS_CHAN_GFSK(_c) \
        (((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0)
 #define        IEEE80211_IS_CHAN_TURBO(_c) \
@@ -388,15 +391,14 @@ struct ieee80211_regdomain {
  * MIMO antenna/radio state.
  */
 
-#define        IEEE80211_MAX_CHAINS            3
-#define        IEEE80211_MAX_EVM_PILOTS        6
-
 /*
  * XXX This doesn't yet export both ctl/ext chain details
+ * XXX TODO: IEEE80211_MAX_CHAINS is defined in _freebsd.h, not here;
+ * figure out how to pull it in!
  */
 struct ieee80211_mimo_info {
-       int8_t          rssi[IEEE80211_MAX_CHAINS];     /* per-antenna rssi */
-       int8_t          noise[IEEE80211_MAX_CHAINS];    /* per-antenna noise 
floor */
+       int8_t          rssi[3];        /* per-antenna rssi */
+       int8_t          noise[3];       /* per-antenna noise floor */
        uint8_t         pad[2];
        uint32_t        evm[3];         /* EVM data */
 };
diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211.c 
b/src/libs/compat/freebsd_wlan/net80211/ieee80211.c
index a039041..36ec452 100644
--- a/src/libs/compat/freebsd_wlan/net80211/ieee80211.c
+++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211.c
@@ -35,10 +35,14 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-
+#include <sys/malloc.h>
 #include <sys/socket.h>
+#include <sys/sbuf.h>
+
+#include <machine/stdarg.h>
 
 #include <net/if.h>
+#include <net/if_var.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
 #include <net/if_types.h>
@@ -80,7 +84,7 @@ const int ieee80211_opcap[IEEE80211_OPMODE_MAX] = {
 #endif
 };
 
-static const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] =
+const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] =
        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag);
@@ -89,10 +93,11 @@ static      void ieee80211_syncflag_ext_locked(struct 
ieee80211com *ic, int flag);
 static int ieee80211_media_setup(struct ieee80211com *ic,
                struct ifmedia *media, int caps, int addsta,
                ifm_change_cb_t media_change, ifm_stat_cb_t media_stat);
-static void ieee80211com_media_status(struct ifnet *, struct ifmediareq *);
-static int ieee80211com_media_change(struct ifnet *);
 static int media_status(enum ieee80211_opmode,
                const struct ieee80211_channel *);
+static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter);
+
+MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state");
 
 /*
  * Default supported rates for 802.11 operation (in IEEE .5Mb units).
@@ -116,7 +121,7 @@ static const struct ieee80211_rateset ieee80211_rateset_11g 
=
  * all available channels as active, and pick
  * a default channel if not already specified.
  */
-static void
+void
 ieee80211_chan_init(struct ieee80211com *ic)
 {
 #define        DEFAULTRATES(m, def) do { \
@@ -220,71 +225,103 @@ ieee80211_chan_init(struct ieee80211com *ic)
 }
 
 static void
-null_update_mcast(struct ifnet *ifp)
+null_update_mcast(struct ieee80211com *ic)
 {
-       if_printf(ifp, "need multicast update callback\n");
+
+       ic_printf(ic, "need multicast update callback\n");
 }
 
 static void
-null_update_promisc(struct ifnet *ifp)
+null_update_promisc(struct ieee80211com *ic)
 {
-       if_printf(ifp, "need promiscuous mode update callback\n");
+
+       ic_printf(ic, "need promiscuous mode update callback\n");
 }
 
-static int
-null_transmit(struct ifnet *ifp, struct mbuf *m)
+static void
+null_update_chw(struct ieee80211com *ic)
 {
-       m_freem(m);
-       ifp->if_oerrors++;
-       return EACCES;          /* XXX EIO/EPERM? */
+
+       ic_printf(ic, "%s: need callback\n", __func__);
 }
 
-static int
-null_output(struct ifnet *ifp, struct mbuf *m,
-       struct sockaddr *dst, struct route *ro)
+int
+ic_printf(struct ieee80211com *ic, const char * fmt, ...)
 {
-       if_printf(ifp, "discard raw packet\n");
-       return null_transmit(ifp, m);
+       va_list ap;
+       int retval;
+
+       retval = printf("%s: ", ic->ic_name);
+       va_start(ap, fmt);
+       retval += vprintf(fmt, ap);
+       va_end(ap);
+       return (retval);
 }
 
-static void
-null_input(struct ifnet *ifp, struct mbuf *m)
+static LIST_HEAD(, ieee80211com) ic_head = LIST_HEAD_INITIALIZER(ic_head);
+static struct mtx ic_list_mtx;
+MTX_SYSINIT(ic_list, &ic_list_mtx, "ieee80211com list", MTX_DEF);
+
+static int
+sysctl_ieee80211coms(SYSCTL_HANDLER_ARGS)
 {
-       if_printf(ifp, "if_input should not be called\n");
-       m_freem(m);
+       struct ieee80211com *ic;
+       struct sbuf sb;
+       char *sp;
+       int error;
+
+       error = sysctl_wire_old_buffer(req, 0);
+       if (error)
+               return (error);
+       sbuf_new_for_sysctl(&sb, NULL, 8, req);
+       sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
+       sp = "";
+       mtx_lock(&ic_list_mtx);
+       LIST_FOREACH(ic, &ic_head, ic_next) {
+               sbuf_printf(&sb, "%s%s", sp, ic->ic_name);
+               sp = " ";
+       }
+       mtx_unlock(&ic_list_mtx);
+       error = sbuf_finish(&sb);
+       sbuf_delete(&sb);
+       return (error);
 }
 
+SYSCTL_PROC(_net_wlan, OID_AUTO, devices,
+    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+    sysctl_ieee80211coms, "A", "names of available 802.11 devices");
+
 /*
  * Attach/setup the common net80211 state.  Called by
  * the driver on attach to prior to creating any vap's.
  */
 void
-ieee80211_ifattach(struct ieee80211com *ic,
-       const uint8_t macaddr[IEEE80211_ADDR_LEN])
+ieee80211_ifattach(struct ieee80211com *ic)
 {
-       struct ifnet *ifp = ic->ic_ifp;
-       struct sockaddr_dl *sdl;
-       struct ifaddr *ifa;
 
-       KASSERT(ifp->if_type == IFT_IEEE80211, ("if_type %d", ifp->if_type));
-
-       IEEE80211_LOCK_INIT(ic, ifp->if_xname);
+       IEEE80211_LOCK_INIT(ic, ic->ic_name);
+       IEEE80211_TX_LOCK_INIT(ic, ic->ic_name);
        TAILQ_INIT(&ic->ic_vaps);
 
        /* Create a taskqueue for all state changes */
        ic->ic_tq = taskqueue_create("ic_taskq", M_WAITOK | M_ZERO,
            taskqueue_thread_enqueue, &ic->ic_tq);
-       taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s taskq",
-           ifp->if_xname);
+       taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s net80211 taskq",
+           ic->ic_name);
+#ifndef __HAIKU__ /* TODO: counter(9) */
+       ic->ic_ierrors = counter_u64_alloc(M_WAITOK);
+       ic->ic_oerrors = counter_u64_alloc(M_WAITOK);
+#endif
        /*
         * Fill in 802.11 available channel set, mark all
         * available channels as active, and pick a default
         * channel if not already specified.
         */
-       ieee80211_media_init(ic);
+       ieee80211_chan_init(ic);
 
        ic->ic_update_mcast = null_update_mcast;
        ic->ic_update_promisc = null_update_promisc;
+       ic->ic_update_chw = null_update_chw;
 
        ic->ic_hash_key = arc4random();
        ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
@@ -308,26 +345,9 @@ ieee80211_ifattach(struct ieee80211com *ic,
 
        ieee80211_sysctl_attach(ic);
 
-       ifp->if_addrlen = IEEE80211_ADDR_LEN;
-       ifp->if_hdrlen = 0;
-       if_attach(ifp);
-       ifp->if_mtu = IEEE80211_MTU_MAX;
-       ifp->if_broadcastaddr = ieee80211broadcastaddr;
-       ifp->if_output = null_output;
-       ifp->if_input = null_input;     /* just in case */
-       ifp->if_resolvemulti = NULL;    /* NB: callers check */
-
-#ifndef __HAIKU__
-       ifa = ifaddr_byindex(ifp->if_index);
-       KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
-       sdl = (struct sockaddr_dl *)ifa->ifa_addr;;
-#else
-       sdl = &ifp->if_lladdr;
-#endif
-       sdl->sdl_type = IFT_ETHER;              /* XXX IFT_IEEE80211? */
-       sdl->sdl_alen = IEEE80211_ADDR_LEN;
-       IEEE80211_ADDR_COPY(LLADDR(sdl), macaddr);
-       ifa_free(ifa);
+       mtx_lock(&ic_list_mtx);
+       LIST_INSERT_HEAD(&ic_head, ic, ic_next);
+       mtx_unlock(&ic_list_mtx);
 }
 
 /*
@@ -339,11 +359,18 @@ ieee80211_ifattach(struct ieee80211com *ic,
 void
 ieee80211_ifdetach(struct ieee80211com *ic)
 {
-       struct ifnet *ifp = ic->ic_ifp;
        struct ieee80211vap *vap;
 
-       if_detach(ifp);
+       mtx_lock(&ic_list_mtx);
+       LIST_REMOVE(ic, ic_next);
+       mtx_unlock(&ic_list_mtx);
 
+       taskqueue_drain(taskqueue_thread, &ic->ic_restart_task);
+
+       /*
+        * The VAP is responsible for setting and clearing
+        * the VIMAGE context.
+        */
        while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
                ieee80211_vap_destroy(vap);
        ieee80211_waitfor_parent(ic);
@@ -365,11 +392,41 @@ ieee80211_ifdetach(struct ieee80211com *ic)
        ieee80211_power_detach(ic);
        ieee80211_node_detach(ic);
 
-       ifmedia_removeall(&ic->ic_media);
+#ifndef __HAIKU__ /* TODO: counter(9) */
+       counter_u64_free(ic->ic_ierrors);
+       counter_u64_free(ic->ic_oerrors);
+#endif
+
        taskqueue_free(ic->ic_tq);
+       IEEE80211_TX_LOCK_DESTROY(ic);
        IEEE80211_LOCK_DESTROY(ic);
 }
 
+struct ieee80211com *
+ieee80211_find_com(const char *name)
+{
+       struct ieee80211com *ic;
+
+       mtx_lock(&ic_list_mtx);
+       LIST_FOREACH(ic, &ic_head, ic_next)
+               if (strcmp(ic->ic_name, name) == 0)
+                       break;
+       mtx_unlock(&ic_list_mtx);
+
+       return (ic);
+}
+
+void
+ieee80211_iterate_coms(ieee80211_com_iter_func *f, void *arg)
+{
+       struct ieee80211com *ic;
+
+       mtx_lock(&ic_list_mtx);
+       LIST_FOREACH(ic, &ic_head, ic_next)
+               (*f)(arg, ic);
+       mtx_unlock(&ic_list_mtx);
+}
+
 /*
  * Default reset method for use with the ioctl support.  This
  * method is invoked after any state change in the 802.11
@@ -386,34 +443,58 @@ default_reset(struct ieee80211vap *vap, u_long cmd)
 }
 
 /*
+ * Add underlying device errors to vap errors.
+ */
+static uint64_t
+ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt)
+{
+       struct ieee80211vap *vap = ifp->if_softc;
+       struct ieee80211com *ic = vap->iv_ic;
+       uint64_t rv;
+
+       rv = if_get_counter_default(ifp, cnt);
+       switch (cnt) {
+#ifndef __HAIKU__ /* TODO: counter(9) */
+       case IFCOUNTER_OERRORS:
+               rv += counter_u64_fetch(ic->ic_oerrors);
+               break;
+       case IFCOUNTER_IERRORS:
+               rv += counter_u64_fetch(ic->ic_ierrors);
+               break;
+#endif
+       default:
+               break;
+       }
+
+       return (rv);
+}
+
+/*
  * Prepare a vap for use.  Drivers use this call to
  * setup net80211 state in new vap's prior attaching
  * them with ieee80211_vap_attach (below).
  */
 int
 ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
-       const char name[IFNAMSIZ], int unit, int opmode, int flags,
-       const uint8_t bssid[IEEE80211_ADDR_LEN],
-       const uint8_t macaddr[IEEE80211_ADDR_LEN])
+    const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode,
+    int flags, const uint8_t bssid[IEEE80211_ADDR_LEN])
 {
        struct ifnet *ifp;
 
        ifp = if_alloc(IFT_ETHER);
        if (ifp == NULL) {
-               if_printf(ic->ic_ifp, "%s: unable to allocate ifnet\n",
+               ic_printf(ic, "%s: unable to allocate ifnet\n",
                    __func__);
                return ENOMEM;
        }
        if_initname(ifp, name, unit);
        ifp->if_softc = vap;                    /* back pointer */
        ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
-       ifp->if_start = ieee80211_start;
+       ifp->if_transmit = ieee80211_vap_transmit;
+       ifp->if_qflush = ieee80211_vap_qflush;
        ifp->if_ioctl = ieee80211_ioctl;
        ifp->if_init = ieee80211_init;
-       /* NB: input+output filled in by ether_ifattach */
-       IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
-       ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
-       IFQ_SET_READY(&ifp->if_snd);
+       ifp->if_get_counter = ieee80211_get_counter;
 
        vap->iv_ifp = ifp;
        vap->iv_ic = ic;
@@ -425,6 +506,7 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct 
ieee80211vap *vap,
        vap->iv_htextcaps = ic->ic_htextcaps;
        vap->iv_opmode = opmode;
        vap->iv_caps |= ieee80211_opcap[opmode];
+       IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_macaddr);
        switch (opmode) {
        case IEEE80211_M_WDS:
                /*
@@ -455,6 +537,8 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct 
ieee80211vap *vap,
                }
                break;
 #endif
+       default:
+               break;
        }
        /* auto-enable s/w beacon miss support */
        if (flags & IEEE80211_CLONE_NOBEACONS)
@@ -471,11 +555,9 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct 
ieee80211vap *vap,
        if (vap->iv_caps & IEEE80211_C_BURST)
                vap->iv_flags |= IEEE80211_F_BURST;
        /* NB: bg scanning only makes sense for station mode right now */
-#if 0
        if (vap->iv_opmode == IEEE80211_M_STA &&
            (vap->iv_caps & IEEE80211_C_BGSCAN))
                vap->iv_flags |= IEEE80211_F_BGSCAN;
-#endif
        vap->iv_flags |= IEEE80211_F_DOTH;      /* XXX no cap, just ena */
        /* NB: DFS support only makes sense for ap mode right now */
        if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
@@ -491,8 +573,6 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct 
ieee80211vap *vap,
         */
        vap->iv_reset = default_reset;
 
-       IEEE80211_ADDR_COPY(vap->iv_myaddr, macaddr);
-
        ieee80211_sysctl_vattach(vap);
        ieee80211_crypto_vattach(vap);
        ieee80211_node_vattach(vap);
@@ -516,8 +596,8 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct 
ieee80211vap *vap,
  * from this call the vap is ready for use.
  */
 int
-ieee80211_vap_attach(struct ieee80211vap *vap,
-       ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
+ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change,
+    ifm_stat_cb_t media_stat, const uint8_t macaddr[IEEE80211_ADDR_LEN])
 {
        struct ifnet *ifp = vap->iv_ifp;
        struct ieee80211com *ic = vap->iv_ic;
@@ -527,7 +607,7 @@ ieee80211_vap_attach(struct ieee80211vap *vap,
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
            "%s: %s parent %s flags 0x%x flags_ext 0x%x\n",
            __func__, ieee80211_opmode_name[vap->iv_opmode],
-           ic->ic_ifp->if_xname, vap->iv_flags, vap->iv_flags_ext);
+           ic->ic_name, vap->iv_flags, vap->iv_flags_ext);
 
        /*
         * Do late attach work that cannot happen until after
@@ -545,16 +625,11 @@ ieee80211_vap_attach(struct ieee80211vap *vap,
        if (maxrate)
                ifp->if_baudrate = IF_Mbps(maxrate);
 
-       ether_ifattach(ifp, vap->iv_myaddr);
-       if (vap->iv_opmode == IEEE80211_M_MONITOR) {
-               /* NB: disallow transmit */
-               ifp->if_transmit = null_transmit;
-               ifp->if_output = null_output;
-       } else {
-               /* hook output method setup by ether_ifattach */
-               vap->iv_output = ifp->if_output;
-               ifp->if_output = ieee80211_output;
-       }
+       ether_ifattach(ifp, macaddr);
+       IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
+       /* hook output method setup by ether_ifattach */
+       vap->iv_output = ifp->if_output;
+       ifp->if_output = ieee80211_output;
        /* NB: if_mtu set by ether_ifattach to ETHERMTU */
 
        IEEE80211_LOCK(ic);
@@ -567,14 +642,12 @@ ieee80211_vap_attach(struct ieee80211vap *vap,
        ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
        ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT);
        ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40);
-       ieee80211_syncifflag_locked(ic, IFF_PROMISC);
-       ieee80211_syncifflag_locked(ic, IFF_ALLMULTI);
        IEEE80211_UNLOCK(ic);
 
        return 1;
 }
 
-/* 
+/*
  * Tear down vap state and reclaim the ifnet.
  * The driver is assumed to have prepared for
  * this; e.g. by turning off interrupts for the
@@ -586,9 +659,10 @@ ieee80211_vap_detach(struct ieee80211vap *vap)
        struct ieee80211com *ic = vap->iv_ic;
        struct ifnet *ifp = vap->iv_ifp;
 
+       CURVNET_SET(ifp->if_vnet);
+
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n",
-           __func__, ieee80211_opmode_name[vap->iv_opmode],
-           ic->ic_ifp->if_xname);
+           __func__, ieee80211_opmode_name[vap->iv_opmode], ic->ic_name);
 
        /* NB: bpfdetach is called by ether_ifdetach and claims all taps */
        ether_ifdetach(ifp);
@@ -601,6 +675,9 @@ ieee80211_vap_detach(struct ieee80211vap *vap)
        ieee80211_draintask(ic, &vap->iv_nstate_task);
        ieee80211_draintask(ic, &vap->iv_swbmiss_task);
 
+       /* XXX band-aid until ifnet handles this for us */
+       taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
+
        IEEE80211_LOCK(ic);
        KASSERT(vap->iv_state == IEEE80211_S_INIT , ("vap still running"));
        TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
@@ -614,8 +691,10 @@ ieee80211_vap_detach(struct ieee80211vap *vap)
        ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40);
        /* NB: this handles the bpfdetach done below */
        ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF);
-       ieee80211_syncifflag_locked(ic, IFF_PROMISC);
-       ieee80211_syncifflag_locked(ic, IFF_ALLMULTI);
+       if (vap->iv_ifflags & IFF_PROMISC)
+               ieee80211_promisc(vap, false);
+       if (vap->iv_ifflags & IFF_ALLMULTI)
+               ieee80211_allmulti(vap, false);
        IEEE80211_UNLOCK(ic);
 
        ifmedia_removeall(&vap->iv_media);
@@ -635,51 +714,51 @@ ieee80211_vap_detach(struct ieee80211vap *vap)
        ieee80211_sysctl_vdetach(vap);
 
        if_free(ifp);
+
+       CURVNET_RESTORE();
 }
 
 /*
- * Synchronize flag bit state in the parent ifnet structure
- * according to the state of all vap ifnet's.  This is used,
- * for example, to handle IFF_PROMISC and IFF_ALLMULTI.
+ * Count number of vaps in promisc, and issue promisc on
+ * parent respectively.
  */
 void
-ieee80211_syncifflag_locked(struct ieee80211com *ic, int flag)
+ieee80211_promisc(struct ieee80211vap *vap, bool on)
 {
-       struct ifnet *ifp = ic->ic_ifp;
-       struct ieee80211vap *vap;
-       int bit, oflags;
+       struct ieee80211com *ic = vap->iv_ic;
 
        IEEE80211_LOCK_ASSERT(ic);
 
-       bit = 0;
-       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
-               if (vap->iv_ifp->if_flags & flag) {
-                       /*
-                        * XXX the bridge sets PROMISC but we don't want to
-                        * enable it on the device, discard here so all the
-                        * drivers don't need to special-case it
-                        */
-                       if (flag == IFF_PROMISC &&
-                           !(vap->iv_opmode == IEEE80211_M_MONITOR ||
-                             (vap->iv_opmode == IEEE80211_M_AHDEMO &&
-                              (vap->iv_caps & IEEE80211_C_TDMA) == 0)))
-                               continue;
-                       bit = 1;
-                       break;
-               }
-       oflags = ifp->if_flags;
-       if (bit)
-               ifp->if_flags |= flag;
-       else
-               ifp->if_flags &= ~flag;
-       if ((ifp->if_flags ^ oflags) & flag) {
-               /* XXX should we return 1/0 and let caller do this? */
-               if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
-                       if (flag == IFF_PROMISC)
-                               ieee80211_runtask(ic, &ic->ic_promisc_task);
-                       else if (flag == IFF_ALLMULTI)
-                               ieee80211_runtask(ic, &ic->ic_mcast_task);
-               }
+       if (on) {
+               if (++ic->ic_promisc == 1)
+                       ieee80211_runtask(ic, &ic->ic_promisc_task);
+       } else {
+               KASSERT(ic->ic_promisc > 0, ("%s: ic %p not promisc",
+                   __func__, ic));
+               if (--ic->ic_promisc == 0)
+                       ieee80211_runtask(ic, &ic->ic_promisc_task);
+       }
+}
+
+/*
+ * Count number of vaps in allmulti, and issue allmulti on
+ * parent respectively.
+ */
+void
+ieee80211_allmulti(struct ieee80211vap *vap, bool on)
+{
+       struct ieee80211com *ic = vap->iv_ic;
+
+       IEEE80211_LOCK_ASSERT(ic);
+
+       if (on) {
+               if (++ic->ic_allmulti == 1)
+                       ieee80211_runtask(ic, &ic->ic_mcast_task);
+       } else {
+               KASSERT(ic->ic_allmulti > 0, ("%s: ic %p not allmulti",
+                   __func__, ic));
+               if (--ic->ic_allmulti == 0)
+                       ieee80211_runtask(ic, &ic->ic_mcast_task);
        }
 }
 
@@ -875,7 +954,7 @@ int
 ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
 {
        if (c == NULL) {
-               if_printf(ic->ic_ifp, "invalid channel (NULL)\n");
+               ic_printf(ic, "invalid channel (NULL)\n");
                return 0;               /* XXX */
        }
        return (c == IEEE80211_CHAN_ANYC ?  IEEE80211_CHAN_ANY : c->ic_ieee);
@@ -914,6 +993,261 @@ ieee80211_ieee2mhz(u_int chan, u_int flags)
        }
 }
 
+static __inline void
+set_extchan(struct ieee80211_channel *c)
+{
+
+       /*
+        * IEEE Std 802.11-2012, page 1738, subclause 20.3.15.4:
+        * "the secondary channel number shall be 'N + [1,-1] * 4'
+        */
+       if (c->ic_flags & IEEE80211_CHAN_HT40U)
+               c->ic_extieee = c->ic_ieee + 4;
+       else if (c->ic_flags & IEEE80211_CHAN_HT40D)
+               c->ic_extieee = c->ic_ieee - 4;
+       else
+               c->ic_extieee = 0;
+}
+
+static int
+addchan(struct ieee80211_channel chans[], int maxchans, int *nchans,
+    uint8_t ieee, uint16_t freq, int8_t maxregpower, uint32_t flags)
+{
+       struct ieee80211_channel *c;
+
+       if (*nchans >= maxchans)
+               return (ENOBUFS);
+
+       c = &chans[(*nchans)++];
+       c->ic_ieee = ieee;
+       c->ic_freq = freq != 0 ? freq : ieee80211_ieee2mhz(ieee, flags);
+       c->ic_maxregpower = maxregpower;
+       c->ic_maxpower = 2 * maxregpower;
+       c->ic_flags = flags;
+       set_extchan(c);
+
+       return (0);
+}
+
+static int
+copychan_prev(struct ieee80211_channel chans[], int maxchans, int *nchans,
+    uint32_t flags)
+{
+       struct ieee80211_channel *c;
+
+       KASSERT(*nchans > 0, ("channel list is empty\n"));
+
+       if (*nchans >= maxchans)
+               return (ENOBUFS);
+
+       c = &chans[(*nchans)++];
+       c[0] = c[-1];
+       c->ic_flags = flags;
+       set_extchan(c);
+
+       return (0);
+}
+
+static void
+getflags_2ghz(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+       int nmodes;
+
+       nmodes = 0;
+       if (isset(bands, IEEE80211_MODE_11B))
+               flags[nmodes++] = IEEE80211_CHAN_B;
+       if (isset(bands, IEEE80211_MODE_11G))
+               flags[nmodes++] = IEEE80211_CHAN_G;
+       if (isset(bands, IEEE80211_MODE_11NG))
+               flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT20;
+       if (ht40) {
+               flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U;
+               flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D;
+       }
+       flags[nmodes] = 0;
+}
+
+static void
+getflags_5ghz(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+       int nmodes;
+
+       nmodes = 0;
+       if (isset(bands, IEEE80211_MODE_11A))
+               flags[nmodes++] = IEEE80211_CHAN_A;
+       if (isset(bands, IEEE80211_MODE_11NA))
+               flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20;
+       if (ht40) {
+               flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U;
+               flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D;
+       }
+       flags[nmodes] = 0;
+}
+
+static void
+getflags(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+
+       flags[0] = 0;
+       if (isset(bands, IEEE80211_MODE_11A) ||
+           isset(bands, IEEE80211_MODE_11NA)) {
+               if (isset(bands, IEEE80211_MODE_11B) ||
+                   isset(bands, IEEE80211_MODE_11G) ||
+                   isset(bands, IEEE80211_MODE_11NG))
+                       return;
+
+               getflags_5ghz(bands, flags, ht40);
+       } else
+               getflags_2ghz(bands, flags, ht40);
+}
+
+/*
+ * Add one 20 MHz channel into specified channel list.
+ */
+int
+ieee80211_add_channel(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, uint8_t ieee, uint16_t freq, int8_t maxregpower,
+    uint32_t chan_flags, const uint8_t bands[])
+{
+       uint32_t flags[IEEE80211_MODE_MAX];
+       int i, error;
+
+       getflags(bands, flags, 0);
+       KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+       error = addchan(chans, maxchans, nchans, ieee, freq, maxregpower,
+           flags[0] | chan_flags);
+       for (i = 1; flags[i] != 0 && error == 0; i++) {
+               error = copychan_prev(chans, maxchans, nchans,
+                   flags[i] | chan_flags);
+       }
+
+       return (error);
+}
+
+static struct ieee80211_channel *
+findchannel(struct ieee80211_channel chans[], int nchans, uint16_t freq,
+    uint32_t flags)
+{
+       struct ieee80211_channel *c;
+       int i;
+
+       flags &= IEEE80211_CHAN_ALLTURBO;
+       /* brute force search */
+       for (i = 0; i < nchans; i++) {
+               c = &chans[i];
+               if (c->ic_freq == freq &&
+                   (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
+                       return c;
+       }
+       return NULL;
+}
+
+/*
+ * Add 40 MHz channel pair into specified channel list.
+ */
+int
+ieee80211_add_channel_ht40(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, uint8_t ieee, int8_t maxregpower, uint32_t flags)
+{
+       struct ieee80211_channel *cent, *extc;
+       uint16_t freq;
+       int error;
+
+       freq = ieee80211_ieee2mhz(ieee, flags);
+
+       /*
+        * Each entry defines an HT40 channel pair; find the
+        * center channel, then the extension channel above.
+        */
+       flags |= IEEE80211_CHAN_HT20;
+       cent = findchannel(chans, *nchans, freq, flags);
+       if (cent == NULL)
+               return (EINVAL);
+
+       extc = findchannel(chans, *nchans, freq + 20, flags);
+       if (extc == NULL)
+               return (ENOENT);
+
+       flags &= ~IEEE80211_CHAN_HT;
+       error = addchan(chans, maxchans, nchans, cent->ic_ieee, cent->ic_freq,
+           maxregpower, flags | IEEE80211_CHAN_HT40U);
+       if (error != 0)
+               return (error);
+
+       error = addchan(chans, maxchans, nchans, extc->ic_ieee, extc->ic_freq,
+           maxregpower, flags | IEEE80211_CHAN_HT40D);
+
+       return (error);
+}
+
+/*
+ * Adds channels into specified channel list (ieee[] array must be sorted).
+ * Channels are already sorted.
+ */
+static int
+add_chanlist(struct ieee80211_channel chans[], int maxchans, int *nchans,
+    const uint8_t ieee[], int nieee, uint32_t flags[])
+{
+       uint16_t freq;
+       int i, j, error;
+
+       for (i = 0; i < nieee; i++) {
+               freq = ieee80211_ieee2mhz(ieee[i], flags[0]);
+               for (j = 0; flags[j] != 0; j++) {
+                       if (flags[j] & IEEE80211_CHAN_HT40D)
+                               if (i == 0 || ieee[i] < ieee[0] + 4 ||
+                                   freq - 20 !=
+                                   ieee80211_ieee2mhz(ieee[i] - 4, flags[j]))
+                                       continue;
+                       if (flags[j] & IEEE80211_CHAN_HT40U)
+                               if (i == nieee - 1 ||
+                                   ieee[i] + 4 > ieee[nieee - 1] ||
+                                   freq + 20 !=
+                                   ieee80211_ieee2mhz(ieee[i] + 4, flags[j]))
+                                       continue;
+
+                       if (j == 0) {
+                               error = addchan(chans, maxchans, nchans,
+                                   ieee[i], freq, 0, flags[j]);
+                       } else {
+                               error = copychan_prev(chans, maxchans, nchans,
+                                   flags[j]);
+                       }
+                       if (error != 0)
+                               return (error);
+               }
+       }
+
+       return (0);
+}
+
+int
+ieee80211_add_channel_list_2ghz(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
+    int ht40)
+{
+       uint32_t flags[IEEE80211_MODE_MAX];
+
+       getflags_2ghz(bands, flags, ht40);
+       KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+       return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
+}
+
+int
+ieee80211_add_channel_list_5ghz(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
+    int ht40)
+{
+       uint32_t flags[IEEE80211_MODE_MAX];
+
+       getflags_5ghz(bands, flags, ht40);
+       KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+       return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
+}
+
 /*
  * Locate a channel given a frequency+flags.  We cache
  * the previous lookup to optimize switching between two
@@ -923,7 +1257,6 @@ struct ieee80211_channel *
 ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
 {
        struct ieee80211_channel *c;
-       int i;
 
        flags &= IEEE80211_CHAN_ALLTURBO;
        c = ic->ic_prevchan;
@@ -931,13 +1264,7 @@ ieee80211_find_channel(struct ieee80211com *ic, int freq, 
int flags)
            (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
                return c;
        /* brute force search */
-       for (i = 0; i < ic->ic_nchans; i++) {
-               c = &ic->ic_channels[i];
-               if (c->ic_freq == freq &&
-                   (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
-                       return c;
-       }
-       return NULL;
+       return (findchannel(ic->ic_channels, ic->ic_nchans, freq, flags));
 }
 
 /*
@@ -966,13 +1293,82 @@ ieee80211_find_channel_byieee(struct ieee80211com *ic, 
int ieee, int flags)
        return NULL;
 }
 
+/*
+ * Lookup a channel suitable for the given rx status.
+ *
+ * This is used to find a channel for a frame (eg beacon, probe
+ * response) based purely on the received PHY information.
+ *
+ * For now it tries to do it based on R_FREQ / R_IEEE.
+ * This is enough for 11bg and 11a (and thus 11ng/11na)
+ * but it will not be enough for GSM, PSB channels and the
+ * like.  It also doesn't know about legacy-turbog and
+ * legacy-turbo modes, which some offload NICs actually
+ * support in weird ways.
+ *
+ * Takes the ic and rxstatus; returns the channel or NULL
+ * if not found.
+ *
+ * XXX TODO: Add support for that when the need arises.
+ */
+struct ieee80211_channel *
+ieee80211_lookup_channel_rxstatus(struct ieee80211vap *vap,
+    const struct ieee80211_rx_stats *rxs)
+{
+       struct ieee80211com *ic = vap->iv_ic;
+       uint32_t flags;
+       struct ieee80211_channel *c;
+
+       if (rxs == NULL)
+               return (NULL);
+
+       /*
+        * Strictly speaking we only use freq for now,
+        * however later on we may wish to just store
+        * the ieee for verification.
+        */
+       if ((rxs->r_flags & IEEE80211_R_FREQ) == 0)
+               return (NULL);
+       if ((rxs->r_flags & IEEE80211_R_IEEE) == 0)
+               return (NULL);
+
+       /*
+        * If the rx status contains a valid ieee/freq, then
+        * ensure we populate the correct channel information
+        * in rxchan before passing it up to the scan infrastructure.
+        * Offload NICs will pass up beacons from all channels
+        * during background scans.
+        */
+
+       /* Determine a band */
+       /* XXX should be done by the driver? */
+       if (rxs->c_freq < 3000) {
+               flags = IEEE80211_CHAN_G;
+       } else {
+               flags = IEEE80211_CHAN_A;
+       }
+
+       /* Channel lookup */
+       c = ieee80211_find_channel(ic, rxs->c_freq, flags);
+
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_INPUT,
+           "%s: freq=%d, ieee=%d, flags=0x%08x; c=%p\n",
+           __func__,
+           (int) rxs->c_freq,
+           (int) rxs->c_ieee,
+           flags,
+           c);
+
+       return (c);
+}
+
 static void
 addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
 {
 #define        ADD(_ic, _s, _o) \
        ifmedia_add(media, \
                IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
-       static const u_int mopts[IEEE80211_MODE_MAX] = { 
+       static const u_int mopts[IEEE80211_MODE_MAX] = {
            [IEEE80211_MODE_AUTO]       = IFM_AUTO,
            [IEEE80211_MODE_11A]        = IFM_IEEE80211_11A,
            [IEEE80211_MODE_11B]        = IFM_IEEE80211_11B,
@@ -1015,7 +1411,8 @@ ieee80211_media_setup(struct ieee80211com *ic,
        struct ifmedia *media, int caps, int addsta,
        ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
 {
-       int i, j, mode, rate, maxrate, mword, r;
+       int i, j, rate, maxrate, mword, r;
+       enum ieee80211_phymode mode;
        const struct ieee80211_rateset *rs;
        struct ieee80211_rateset allrates;
 
@@ -1099,39 +1496,6 @@ ieee80211_media_setup(struct ieee80211com *ic,
        return maxrate;
 }
 
-void
-ieee80211_media_init(struct ieee80211com *ic)
-{
-       struct ifnet *ifp = ic->ic_ifp;
-       int maxrate;
-
-       /* NB: this works because the structure is initialized to zero */
-       if (!LIST_EMPTY(&ic->ic_media.ifm_list)) {
-               /*
-                * We are re-initializing the channel list; clear
-                * the existing media state as the media routines
-                * don't suppress duplicates.
-                */
-               ifmedia_removeall(&ic->ic_media);
-       }
-       ieee80211_chan_init(ic);
-
-       /*
-        * Recalculate media settings in case new channel list changes
-        * the set of available modes.
-        */
-       maxrate = ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, 1,
-               ieee80211com_media_change, ieee80211com_media_status);
-       /* NB: strip explicit mode; we're actually in autoselect */
-       ifmedia_set(&ic->ic_media,
-           media_status(ic->ic_opmode, ic->ic_curchan) &~
-               (IFM_MMASK | IFM_IEEE80211_TURBO));
-       if (maxrate)
-               ifp->if_baudrate = IF_Mbps(maxrate);
-
-       /* XXX need to propagate new media settings to vap's */
-}
-
 /* XXX inline or eliminate? */
 const struct ieee80211_rateset *
 ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel 
*c)
@@ -1143,15 +1507,15 @@ ieee80211_get_suprates(struct ieee80211com *ic, const 
struct ieee80211_channel *
 void
 ieee80211_announce(struct ieee80211com *ic)
 {
-       struct ifnet *ifp = ic->ic_ifp;
-       int i, mode, rate, mword;
+       int i, rate, mword;
+       enum ieee80211_phymode mode;
        const struct ieee80211_rateset *rs;
 
        /* NB: skip AUTO since it has no rates */
        for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) {
                if (isclr(ic->ic_modecaps, mode))
                        continue;
-               if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
+               ic_printf(ic, "%s rates: ", ieee80211_phymode_name[mode]);
                rs = &ic->ic_sup_rates[mode];
                for (i = 0; i < rs->rs_nrates; i++) {
                        mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode);
@@ -1260,15 +1624,6 @@ media2mode(const struct ifmedia_entry *ime, uint32_t 
flags, uint16_t *mode)
 }
 
 /*
- * Handle a media change request on the underlying interface.
- */
-int
-ieee80211com_media_change(struct ifnet *ifp)
-{
-       return EINVAL;
-}
-
-/*
  * Handle a media change request on the vap interface.
  */
 int
@@ -1345,23 +1700,6 @@ media_status(enum ieee80211_opmode opmode, const struct 
ieee80211_channel *chan)
        return status;
 }
 
-static void
-ieee80211com_media_status(struct ifnet *ifp, struct ifmediareq *imr)
-{
-       struct ieee80211com *ic = ifp->if_l2com;
-       struct ieee80211vap *vap;
-
-       imr->ifm_status = IFM_AVALID;
-       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
-               if (vap->iv_ifp->if_flags & IFF_UP) {
-                       imr->ifm_status |= IFM_ACTIVE;
-                       break;
-               }
-       imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan);
-       if (imr->ifm_status & IFM_ACTIVE)
-               imr->ifm_current = imr->ifm_active;
-}
-
 void
 ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
 {
@@ -1375,7 +1713,8 @@ ieee80211_media_status(struct ifnet *ifp, struct 
ifmediareq *imr)
         * rate only when running; otherwise we may have a mismatch
         * in which case the rate will not be convertible.
         */
-       if (vap->iv_state == IEEE80211_S_RUN) {
+       if (vap->iv_state == IEEE80211_S_RUN ||
+           vap->iv_state == IEEE80211_S_SLEEP) {
                imr->ifm_status |= IFM_ACTIVE;
                mode = ieee80211_chan2mode(ic->ic_curchan);
        } else
@@ -1486,7 +1825,6 @@ findmedia(const struct ratemedia rates[], int n, u_int 
match)
 int
 ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode 
mode)
 {
-#define        N(a)    (sizeof(a) / sizeof(a[0]))
        static const struct ratemedia rates[] = {
                {   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
                {   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
@@ -1518,7 +1856,7 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate, 
enum ieee80211_phymode m
                {   6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 },
                {   9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 },
                {  54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 },
-               /* NB: OFDM72 doesn't realy exist so we don't handle it */
+               /* NB: OFDM72 doesn't really exist so we don't handle it */
        };
        static const struct ratemedia htrates[] = {
                {   0, IFM_IEEE80211_MCS },
@@ -1607,7 +1945,7 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate, 
enum ieee80211_phymode m
        if (mode == IEEE80211_MODE_11NA) {
                if (rate & IEEE80211_RATE_MCS) {
                        rate &= ~IEEE80211_RATE_MCS;
-                       m = findmedia(htrates, N(htrates), rate);
+                       m = findmedia(htrates, nitems(htrates), rate);
                        if (m != IFM_AUTO)
                                return m | IFM_IEEE80211_11NA;
                }
@@ -1615,7 +1953,7 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate, 
enum ieee80211_phymode m
                /* NB: 12 is ambiguous, it will be treated as an MCS */
                if (rate & IEEE80211_RATE_MCS) {
                        rate &= ~IEEE80211_RATE_MCS;
-                       m = findmedia(htrates, N(htrates), rate);
+                       m = findmedia(htrates, nitems(htrates), rate);
                        if (m != IFM_AUTO)
                                return m | IFM_IEEE80211_11NG;
                }
@@ -1628,31 +1966,32 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate, 
enum ieee80211_phymode m
        case IEEE80211_MODE_11NA:
        case IEEE80211_MODE_TURBO_A:
        case IEEE80211_MODE_STURBO_A:
-               return findmedia(rates, N(rates), rate | IFM_IEEE80211_11A);
+               return findmedia(rates, nitems(rates),
+                   rate | IFM_IEEE80211_11A);
        case IEEE80211_MODE_11B:
-               return findmedia(rates, N(rates), rate | IFM_IEEE80211_11B);
+               return findmedia(rates, nitems(rates),
+                   rate | IFM_IEEE80211_11B);
        case IEEE80211_MODE_FH:
-               return findmedia(rates, N(rates), rate | IFM_IEEE80211_FH);
+               return findmedia(rates, nitems(rates),
+                   rate | IFM_IEEE80211_FH);
        case IEEE80211_MODE_AUTO:
                /* NB: ic may be NULL for some drivers */
                if (ic != NULL && ic->ic_phytype == IEEE80211_T_FH)
-                       return findmedia(rates, N(rates),
+                       return findmedia(rates, nitems(rates),
                            rate | IFM_IEEE80211_FH);
                /* NB: hack, 11g matches both 11b+11a rates */
                /* fall thru... */
        case IEEE80211_MODE_11G:
        case IEEE80211_MODE_11NG:
        case IEEE80211_MODE_TURBO_G:
-               return findmedia(rates, N(rates), rate | IFM_IEEE80211_11G);
+               return findmedia(rates, nitems(rates), rate | 
IFM_IEEE80211_11G);
        }
        return IFM_AUTO;
-#undef N
 }
 
 int
 ieee80211_media2rate(int mword)
 {
-#define        N(a)    (sizeof(a) / sizeof(a[0]))
        static const int ieeerates[] = {
                -1,             /* IFM_AUTO */
                0,              /* IFM_MANUAL */
@@ -1680,9 +2019,8 @@ ieee80211_media2rate(int mword)
                54,             /* IFM_IEEE80211_OFDM27 */
                -1,             /* IFM_IEEE80211_MCS */
        };
-       return IFM_SUBTYPE(mword) < N(ieeerates) ?
+       return IFM_SUBTYPE(mword) < nitems(ieeerates) ?
                ieeerates[IFM_SUBTYPE(mword)] : 0;
-#undef N
 }
 
 /*
@@ -1720,3 +2058,23 @@ ieee80211_mac_hash(const struct ieee80211com *ic,
        return c;
 }
 #undef mix
+
+char
+ieee80211_channel_type_char(const struct ieee80211_channel *c)
+{
+       if (IEEE80211_IS_CHAN_ST(c))
+               return 'S';
+       if (IEEE80211_IS_CHAN_108A(c))
+               return 'T';
+       if (IEEE80211_IS_CHAN_108G(c))
+               return 'G';
+       if (IEEE80211_IS_CHAN_HT(c))
+               return 'n';
+       if (IEEE80211_IS_CHAN_A(c))
+               return 'a';
+       if (IEEE80211_IS_CHAN_ANYG(c))
+               return 'g';
+       if (IEEE80211_IS_CHAN_B(c))
+               return 'b';
+       return 'f';
+}
diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211.h 
b/src/libs/compat/freebsd_wlan/net80211/ieee80211.h
index 49716b3..15e6a32 100644
--- a/src/libs/compat/freebsd_wlan/net80211/ieee80211.h
+++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211.h
@@ -25,8 +25,8 @@
  *
  * $FreeBSD$
  */
-#ifndef _FBSD_COMPAT_NET80211_IEEE80211_H_
-#define _FBSD_COMPAT_NET80211_IEEE80211_H_
+#ifndef _NET80211_IEEE80211_H_
+#define _NET80211_IEEE80211_H_
 
 /*
  * 802.11 protocol definitions.
@@ -36,6 +36,10 @@
 /* is 802.11 address multicast/broadcast? */
 #define        IEEE80211_IS_MULTICAST(_a)      (*(_a) & 0x01)
 
+#ifdef _KERNEL
+extern const uint8_t ieee80211broadcastaddr[];
+#endif
+
 typedef uint16_t ieee80211_seq;
 
 /* IEEE 802.11 PLCP header */
@@ -47,7 +51,7 @@ struct ieee80211_plcp_hdr {
        uint16_t        i_crc;
 } __packed;
 
-#define IEEE80211_PLCP_SFD      0xF3A0 
+#define IEEE80211_PLCP_SFD      0xF3A0
 #define IEEE80211_PLCP_SERVICE  0x00
 #define IEEE80211_PLCP_SERVICE_LOCKED  0x04
 #define IEEE80211_PLCL_SERVICE_PBCC    0x08
@@ -125,6 +129,7 @@ struct ieee80211_qosframe_addr4 {
 #define        IEEE80211_FC0_SUBTYPE_REASSOC_RESP      0x30
 #define        IEEE80211_FC0_SUBTYPE_PROBE_REQ         0x40
 #define        IEEE80211_FC0_SUBTYPE_PROBE_RESP        0x50
+#define        IEEE80211_FC0_SUBTYPE_TIMING_ADV        0x60
 #define        IEEE80211_FC0_SUBTYPE_BEACON            0x80
 #define        IEEE80211_FC0_SUBTYPE_ATIM              0x90
 #define        IEEE80211_FC0_SUBTYPE_DISASSOC          0xa0
@@ -133,6 +138,7 @@ struct ieee80211_qosframe_addr4 {
 #define        IEEE80211_FC0_SUBTYPE_ACTION            0xd0
 #define        IEEE80211_FC0_SUBTYPE_ACTION_NOACK      0xe0
 /* for TYPE_CTL */
+#define        IEEE80211_FC0_SUBTYPE_CONTROL_WRAP      0x70
 #define        IEEE80211_FC0_SUBTYPE_BAR               0x80
 #define        IEEE80211_FC0_SUBTYPE_BA                0x90
 #define        IEEE80211_FC0_SUBTYPE_PS_POLL           0xa0
@@ -166,9 +172,14 @@ struct ieee80211_qosframe_addr4 {
 #define        IEEE80211_FC1_RETRY                     0x08
 #define        IEEE80211_FC1_PWR_MGT                   0x10
 #define        IEEE80211_FC1_MORE_DATA                 0x20
-#define        IEEE80211_FC1_WEP                       0x40
+#define        IEEE80211_FC1_PROTECTED                 0x40
 #define        IEEE80211_FC1_ORDER                     0x80
 
+#define IEEE80211_HAS_SEQ(type, subtype) \
+       ((type) != IEEE80211_FC0_TYPE_CTL && \
+       !((type) == IEEE80211_FC0_TYPE_DATA && \

[ *** diff truncated: 21010 lines dropped *** ]


############################################################################

Commit:      d1413aa07636d1d602d65bf6cdfdaaaa9e39be4a
Author:      Augustin Cavalier <waddlesplash@xxxxxxxxx>
Date:        Mon Nov 13 21:35:19 2017 UTC

drivers/network/wlan: Import idualwifi3160 ('iwm' from FreeBSD 11.)

This is the driver for the chipset in my laptop (Intel Dual Band Wireless-AC 
7265)
as well as most other chipsets in the "Intel Dual Band" series. Hopefully
I've followed our naming convention correctly in calling it "idualwifi3160".

I don't have any way to test it (as the preceding commit is unfinished),
so I didn't attempt to locate the proper firmware that goes with it,
but I did at least clean up the C99isms in it so that it compiles with GCC2.

----------------------------------------------------------------------------


Other related posts:

  • » [haiku-commits] BRANCH waddlesplash-github.freebsd11 [d1413aa07636] in src: add-ons/kernel/drivers/network/wlan/idualwifi3160/dev/iwm libs/compat/freebsd_wlan/net80211 - waddlesplash-github . freebsd11