add support for 802.11 packet injection via bpf

Together with:	Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Reviewed by:	arch@
MFC after:	1 month
This commit is contained in:
Sam Leffler 2006-07-26 03:15:16 +00:00
parent cbd038e738
commit 246b546762
8 changed files with 204 additions and 1 deletions

View File

@ -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;

View File

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

View File

@ -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_ */

View File

@ -203,6 +203,130 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni,
return 0;
}
/*
* 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.
*

View File

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

View File

@ -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],

View File

@ -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];

View File

@ -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
/*