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.
----------------------------------------------------------------------------