summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2005-04-20 19:52:44 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2005-04-20 19:52:44 +0000
commit472569caed823134f3cdf4b7b1f19c50910c3879 (patch)
tree47f7fc8ecb225ce29c9fcd2defd292b2af4f2512
parentf89146cba13d07521aafe77f436a3255fb95e64c (diff)
send raw 802.11 frames with bpf(4) using the IEEE802_11 or
IEEE802_11_RADIO data link types. ok canacar@ damien@
-rw-r--r--sys/net/bpf.c18
-rw-r--r--sys/net80211/ieee80211.c5
-rw-r--r--sys/net80211/ieee80211_output.c111
-rw-r--r--sys/net80211/ieee80211_proto.h4
4 files changed, 134 insertions, 4 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 8588e507fa8..980066a9490 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bpf.c,v 1.57 2005/04/20 17:03:22 reyk Exp $ */
+/* $OpenBSD: bpf.c,v 1.58 2005/04/20 19:52:42 reyk Exp $ */
/* $NetBSD: bpf.c,v 1.33 1997/02/21 23:59:35 thorpej Exp $ */
/*
@@ -107,6 +107,7 @@ bpf_movein(struct uio *uio, u_int linktype, struct mbuf **mp,
struct sockaddr *sockp, struct bpf_insn *filter)
{
struct mbuf *m;
+ struct m_tag *mtag;
int error;
u_int hlen;
u_int len;
@@ -150,6 +151,12 @@ bpf_movein(struct uio *uio, u_int linktype, struct mbuf **mp,
hlen = 24;
break;
+ case DLT_IEEE802_11:
+ case DLT_IEEE802_11_RADIO:
+ sockp->sa_family = AF_UNSPEC;
+ hlen = 0;
+ break;
+
case DLT_RAW:
case DLT_NULL:
sockp->sa_family = AF_UNSPEC;
@@ -211,6 +218,15 @@ bpf_movein(struct uio *uio, u_int linktype, struct mbuf **mp,
m->m_data += hlen; /* XXX */
}
+ /*
+ * Prepend the data link type as a mbuf tag
+ */
+ mtag = m_tag_get(PACKET_TAG_DLT, sizeof(u_int), M_NOWAIT);
+ if (mtag == NULL)
+ return (ENOMEM);
+ *(u_int *)(mtag + 1) = linktype;
+ m_tag_prepend(m, mtag);
+
return (0);
bad:
m_freem(m);
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index 20af2f2d2ea..ab2c5a3b9bd 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211.c,v 1.4 2005/02/17 18:28:05 reyk Exp $ */
+/* $OpenBSD: ieee80211.c,v 1.5 2005/04/20 19:52:43 reyk Exp $ */
/* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */
/*-
@@ -155,6 +155,9 @@ ieee80211_ifattach(struct ifnet *ifp)
#else
ether_ifattach(ifp, ic->ic_myaddr);
#endif
+
+ ifp->if_output = ieee80211_output;
+
#if NBPFILTER > 0
BPF_ATTACH(ifp, DLT_IEEE802_11,
sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 8818c0db755..c104fe472b0 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_output.c,v 1.8 2005/03/11 23:20:26 jsg Exp $ */
+/* $OpenBSD: ieee80211_output.c,v 1.9 2005/04/20 19:52:43 reyk Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
/*-
@@ -92,6 +92,67 @@ __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung
#include <net80211/ieee80211_compat.h>
/*
+ * IEEE 802.11 output routine. Normally this will directly call the
+ * Ethernet output routine because 802.11 encapsulation is called
+ * later by the driver. This function could be used to send raw frames
+ * if the mbuf has been tagged with a 802.11 data link type.
+ */
+int
+ieee80211_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+ struct rtentry *rt)
+{
+ u_int dlt = 0;
+ int s, error = 0;
+ struct m_tag *mtag;
+
+ /* Interface has to be up and running */
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
+ (IFF_UP | IFF_RUNNING)) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /* Try to get the DLT from a mbuf tag */
+ if ((mtag = m_tag_find(m, PACKET_TAG_DLT, NULL)) != NULL) {
+ dlt = *(u_int *)(mtag + 1);
+
+ /* Fallback to ethernet for non-802.11 linktypes */
+ if (!(dlt == DLT_IEEE802_11 || dlt == DLT_IEEE802_11_RADIO))
+ goto fallback;
+
+ /*
+ * Queue message on interface without adding any
+ * further headers, and start output if interface not
+ * yet active.
+ */
+ s = splimp();
+ IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
+ if (error) {
+ /* mbuf is already freed */
+ splx(s);
+ if_printf(ifp, "failed to queue raw tx frame\n");
+ return (error);
+ }
+ ifp->if_obytes += m->m_pkthdr.len;
+ if (m->m_flags & M_MCAST)
+ ifp->if_omcasts++;
+ if ((ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
+ splx(s);
+
+ return (error);
+ }
+
+ fallback:
+ return (ether_output(ifp, m, dst, rt));
+
+ bad:
+ if (m)
+ m_freem(m);
+ return (error);
+}
+
+/*
* Send a management frame to the specified node. The node pointer
* must have a reference as the pointer will be passed to the driver
* and potentially held for a long time. If the frame is successfully
@@ -185,7 +246,55 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
struct ieee80211_frame *wh;
struct ieee80211_node *ni = NULL;
struct llc *llc;
+ struct m_tag *mtag;
+ u_int8_t *addr;
+ u_int dlt;
+
+ /* Handle raw frames if mbuf is tagged as 802.11 */
+ if ((mtag = m_tag_find(m, PACKET_TAG_DLT, NULL)) != NULL) {
+ dlt = *(u_int *)(mtag + 1);
+
+ if (!(dlt == DLT_IEEE802_11 || dlt == DLT_IEEE802_11_RADIO))
+ goto fallback;
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min))
+ goto bad;
+
+ if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
+ IEEE80211_FC0_VERSION_0)
+ goto bad;
+
+ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
+ case IEEE80211_FC1_DIR_NODS:
+ case IEEE80211_FC1_DIR_FROMDS:
+ addr = wh->i_addr1;
+ break;
+ case IEEE80211_FC1_DIR_DSTODS:
+ case IEEE80211_FC1_DIR_TODS:
+ addr = wh->i_addr3;
+ break;
+ default:
+ goto bad;
+ }
+
+ ni = ieee80211_find_txnode(ic, addr);
+ if (ni == NULL)
+ ni = ieee80211_ref_node(ic->ic_bss);
+ if (ni == NULL) {
+ if_printf(ifp, "no node for dst %s, "
+ "discard raw tx frame\n", ether_sprintf(addr));
+ ic->ic_stats.is_tx_nonode++;
+ goto bad;
+ }
+ ni->ni_inact = 0;
+
+ *pni = ni;
+ return (m);
+ }
+ fallback:
if (m->m_len < sizeof(struct ether_header)) {
m = m_pullup(m, sizeof(struct ether_header));
if (m == NULL) {
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 0a59806594e..670d8019f38 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.h,v 1.6 2005/03/03 14:36:41 damien Exp $ */
+/* $OpenBSD: ieee80211_proto.h,v 1.7 2005/04/20 19:52:43 reyk Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */
/*-
@@ -61,6 +61,8 @@ extern void ieee80211_proto_detach(struct ifnet *);
struct ieee80211_node;
extern void ieee80211_input(struct ifnet *, struct mbuf *,
struct ieee80211_node *, int, u_int32_t);
+extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *);
extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, int, u_int32_t);
extern int ieee80211_send_mgmt(struct ieee80211com *, struct ieee80211_node *,