summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/bpf.c31
-rw-r--r--sys/net80211/ieee80211.c5
-rw-r--r--sys/net80211/ieee80211_freebsd.h33
-rw-r--r--sys/net80211/ieee80211_output.c124
-rw-r--r--sys/net80211/ieee80211_proto.c1
-rw-r--r--sys/net80211/ieee80211_proto.h5
-rw-r--r--sys/net80211/ieee80211_var.h3
-rw-r--r--sys/sys/socket.h3
8 files changed, 204 insertions, 1 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index f06ef76..9a2f104 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -75,6 +75,8 @@
#include <sys/kernel.h>
#include <sys/sysctl.h>
+#include <net80211/ieee80211_freebsd.h>
+
static MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
#if defined(DEV_BPF) || defined(NETGRAPH_BPF)
@@ -159,6 +161,7 @@ static int
bpf_movein(struct uio *uio, int linktype, int mtu, struct mbuf **mp,
struct sockaddr *sockp, struct bpf_insn *wfilter)
{
+ const struct ieee80211_bpf_params *p;
struct mbuf *m;
int error;
int len;
@@ -221,6 +224,17 @@ bpf_movein(struct uio *uio, int linktype, int mtu, struct mbuf **mp,
hlen = 4; /* This should match PPP_HDRLEN */
break;
+ case DLT_IEEE802_11: /* IEEE 802.11 wireless */
+ sockp->sa_family = AF_IEEE80211;
+ hlen = 0;
+ break;
+
+ case DLT_IEEE802_11_RADIO: /* IEEE 802.11 wireless w/ phy params */
+ sockp->sa_family = AF_IEEE80211;
+ sockp->sa_len = 12; /* XXX != 0 */
+ hlen = sizeof(struct ieee80211_bpf_params);
+ break;
+
default:
return (EIO);
}
@@ -263,6 +277,23 @@ bpf_movein(struct uio *uio, int linktype, int mtu, struct mbuf **mp,
* Make room for link header, and copy it to sockaddr
*/
if (hlen != 0) {
+ if (sockp->sa_family == AF_IEEE80211) {
+ /*
+ * Collect true length from the parameter header
+ * NB: sockp is known to be zero'd so if we do a
+ * short copy unspecified parameters will be
+ * zero.
+ * NB: packet may not be aligned after stripping
+ * bpf params
+ * XXX check ibp_vers
+ */
+ p = mtod(m, const struct ieee80211_bpf_params *);
+ hlen = p->ibp_len;
+ if (hlen > sizeof(sockp->sa_data)) {
+ error = EINVAL;
+ goto bad;
+ }
+ }
bcopy(m->m_data, sockp->sa_data, hlen);
m->m_pkthdr.len -= hlen;
m->m_len -= hlen;
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index 33cea93..ebce2c6 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -126,6 +126,8 @@ ieee80211_ifattach(struct ieee80211com *ic)
int i;
ether_ifattach(ifp, ic->ic_myaddr);
+ ifp->if_output = ieee80211_output;
+
bpfattach2(ifp, DLT_IEEE802_11,
sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
@@ -209,6 +211,9 @@ ieee80211_ifattach(struct ieee80211com *ic)
*/
if (ic->ic_reset == NULL)
ic->ic_reset = ieee80211_default_reset;
+
+ KASSERT(ifp->if_spare2 == NULL, ("oops, hosed"));
+ ifp->if_spare2 = ic; /* XXX temp backpointer */
}
void
diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h
index 70a40c1..9fc23e5 100644
--- a/sys/net80211/ieee80211_freebsd.h
+++ b/sys/net80211/ieee80211_freebsd.h
@@ -225,4 +225,37 @@ struct ieee80211_michael_event {
#define RTM_IEEE80211_MICHAEL 107 /* Michael MIC failure detected */
#define RTM_IEEE80211_REJOIN 108 /* station re-associate (ap mode) */
+/*
+ * Structure prepended to raw packets sent through the bpf
+ * interface when set to DLT_IEEE802_11_RADIO. This allows
+ * user applications to specify pretty much everything in
+ * an Atheros tx descriptor. XXX need to generalize.
+ *
+ * XXX cannot be more than 14 bytes as it is copied to a sockaddr's
+ * XXX sa_data area.
+ */
+struct ieee80211_bpf_params {
+ uint8_t ibp_vers; /* version */
+#define IEEE80211_BPF_VERSION 0
+ uint8_t ibp_len; /* header length in bytes */
+ uint8_t ibp_flags;
+#define IEEE80211_BPF_SHORTPRE 0x01 /* tx with short preamble */
+#define IEEE80211_BPF_NOACK 0x02 /* tx with no ack */
+#define IEEE80211_BPF_CRYPTO 0x04 /* tx with h/w encryption */
+#define IEEE80211_BPF_FCS 0x10 /* frame incldues FCS */
+#define IEEE80211_BPF_DATAPAD 0x20 /* frame includes data padding */
+#define IEEE80211_BPF_RTS 0x40 /* tx with RTS/CTS */
+#define IEEE80211_BPF_CTS 0x80 /* tx with CTS only */
+ uint8_t ibp_pri; /* WME/WMM AC+tx antenna */
+ uint8_t ibp_try0; /* series 1 try count */
+ uint8_t ibp_rate0; /* series 1 IEEE tx rate */
+ uint8_t ibp_power; /* tx power (device units) */
+ uint8_t ibp_ctsrate; /* IEEE tx rate for CTS */
+ uint8_t ibp_try1; /* series 2 try count */
+ uint8_t ibp_rate1; /* series 2 IEEE tx rate */
+ uint8_t ibp_try2; /* series 3 try count */
+ uint8_t ibp_rate2; /* series 3 IEEE tx rate */
+ uint8_t ibp_try3; /* series 4 try count */
+ uint8_t ibp_rate3; /* series 4 IEEE tx rate */
+};
#endif /* _NET80211_IEEE80211_FREEBSD_H_ */
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 9dfbb8d..c91e389 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -204,6 +204,130 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni,
}
/*
+ * Raw packet transmit stub for legacy drivers.
+ * Send the packet through the mgt q so we bypass
+ * the normal encapsulation work.
+ */
+int
+ieee80211_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+
+ m->m_pkthdr.rcvif = (void *) ni;
+ IF_ENQUEUE(&ic->ic_mgtq, m);
+ if_start(ifp);
+ ifp->if_opackets++;
+
+ return 0;
+}
+
+/*
+ * 802.11 output routine. This is (currently) used only to
+ * connect bpf write calls to the 802.11 layer for injecting
+ * raw 802.11 frames. Note we locate the ieee80211com from
+ * the ifnet using a spare field setup at attach time. This
+ * will go away when the virtual ap support comes in.
+ */
+int
+ieee80211_output(struct ifnet *ifp, struct mbuf *m,
+ struct sockaddr *dst, struct rtentry *rt0)
+{
+#define senderr(e) do { error = (e); goto bad;} while (0)
+ struct ieee80211com *ic = ifp->if_spare2; /* XXX */
+ struct ieee80211_node *ni = NULL;
+ struct ieee80211_frame *wh;
+ int error;
+
+ /*
+ * Hand to the 802.3 code if not tagged as
+ * a raw 802.11 frame.
+ */
+ if (dst->sa_family != AF_IEEE80211)
+ return ether_output(ifp, m, dst, rt0);
+#ifdef MAC
+ error = mac_check_ifnet_transmit(ifp, m);
+ if (error)
+ senderr(error);
+#endif
+ if (ifp->if_flags & IFF_MONITOR)
+ senderr(ENETDOWN);
+ if ((ifp->if_flags & IFF_UP) == 0)
+ senderr(ENETDOWN);
+
+ /* XXX bypass bridge, pfil, carp, etc. */
+
+ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack))
+ senderr(EIO); /* XXX */
+ wh = mtod(m, struct ieee80211_frame *);
+ if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
+ IEEE80211_FC0_VERSION_0)
+ senderr(EIO); /* XXX */
+
+ /* locate destination node */
+ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
+ case IEEE80211_FC1_DIR_NODS:
+ case IEEE80211_FC1_DIR_FROMDS:
+ ni = ieee80211_find_txnode(ic, wh->i_addr1);
+ break;
+ case IEEE80211_FC1_DIR_TODS:
+ case IEEE80211_FC1_DIR_DSTODS:
+ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame))
+ senderr(EIO); /* XXX */
+ ni = ieee80211_find_txnode(ic, wh->i_addr3);
+ break;
+ default:
+ senderr(EIO); /* XXX */
+ }
+ if (ni == NULL) {
+ /*
+ * Permit packets w/ bpf params through regardless
+ * (see below about sa_len).
+ */
+ if (dst->sa_len == 0)
+ senderr(EHOSTUNREACH);
+ ni = ieee80211_ref_node(ic->ic_bss);
+ }
+
+ /* XXX ctrl frames should go through */
+ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
+ (m->m_flags & M_PWR_SAV) == 0) {
+ /*
+ * Station in power save mode; pass the frame
+ * to the 802.11 layer and continue. We'll get
+ * the frame back when the time is right.
+ */
+ ieee80211_pwrsave(ic, ni, m);
+ error = 0;
+ goto reclaim;
+ }
+
+ /* calculate priority so drivers can find the tx queue */
+ /* XXX assumes an 802.3 frame */
+ if (ieee80211_classify(ic, m, ni))
+ senderr(EIO); /* XXX */
+
+ BPF_MTAP(ifp, m);
+ /*
+ * NB: DLT_IEEE802_11_RADIO identifies the parameters are
+ * present by setting the sa_len field of the sockaddr (yes,
+ * this is a hack).
+ * NB: we assume sa_data is suitably aligned to cast.
+ */
+ return ic->ic_raw_xmit(ni, m, (const struct ieee80211_bpf_params *)
+ (dst->sa_len ? dst->sa_data : NULL));
+bad:
+ if (m != NULL)
+ m_freem(m);
+reclaim:
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ return error;
+#undef senderr
+}
+
+/*
* Send a null data frame to the specified node.
*
* NB: the caller is assumed to have setup a node reference
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index 16d22d3..e7441ef 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -114,6 +114,7 @@ ieee80211_proto_attach(struct ieee80211com *ic)
/* initialize management frame handlers */
ic->ic_recv_mgmt = ieee80211_recv_mgmt;
ic->ic_send_mgmt = ieee80211_send_mgmt;
+ ic->ic_raw_xmit = ieee80211_raw_xmit;
}
void
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 4b8f6b4..397da44 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -64,6 +64,11 @@ int ieee80211_setup_rates(struct ieee80211_node *ni,
void ieee80211_saveie(u_int8_t **, const u_int8_t *);
void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, int, u_int32_t);
+struct ieee80211_bpf_params;
+int ieee80211_raw_xmit(struct ieee80211_node *, struct mbuf *,
+ const struct ieee80211_bpf_params *);
+int ieee80211_output(struct ifnet *, struct mbuf *,
+ struct sockaddr *, struct rtentry *);
int ieee80211_send_nulldata(struct ieee80211_node *);
int ieee80211_send_probereq(struct ieee80211_node *ni,
const u_int8_t sa[IEEE80211_ADDR_LEN],
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 927d143..40f2fde 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -103,6 +103,9 @@ struct ieee80211com {
void (*ic_newassoc)(struct ieee80211_node *, int);
void (*ic_updateslot)(struct ifnet *);
void (*ic_set_tim)(struct ieee80211_node *, int);
+ int (*ic_raw_xmit)(struct ieee80211_node *,
+ struct mbuf *,
+ const struct ieee80211_bpf_params *);
u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index bb00346..598008f 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -208,7 +208,8 @@ struct accept_filter_arg {
#define AF_SCLUSTER 34 /* Sitara cluster protocol */
#define AF_ARP 35
#define AF_BLUETOOTH 36 /* Bluetooth sockets */
-#define AF_MAX 37
+#define AF_IEEE80211 37 /* IEEE 802.11 protocol */
+#define AF_MAX 38
#endif
/*
OpenPOWER on IntegriCloud