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:
parent
cbd038e738
commit
246b546762
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user