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/kernel.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <net80211/ieee80211_freebsd.h>
|
||||||
|
|
||||||
static MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
|
static MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
|
||||||
|
|
||||||
#if defined(DEV_BPF) || defined(NETGRAPH_BPF)
|
#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,
|
bpf_movein(struct uio *uio, int linktype, int mtu, struct mbuf **mp,
|
||||||
struct sockaddr *sockp, struct bpf_insn *wfilter)
|
struct sockaddr *sockp, struct bpf_insn *wfilter)
|
||||||
{
|
{
|
||||||
|
const struct ieee80211_bpf_params *p;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
int error;
|
int error;
|
||||||
int len;
|
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 */
|
hlen = 4; /* This should match PPP_HDRLEN */
|
||||||
break;
|
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:
|
default:
|
||||||
return (EIO);
|
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
|
* Make room for link header, and copy it to sockaddr
|
||||||
*/
|
*/
|
||||||
if (hlen != 0) {
|
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);
|
bcopy(m->m_data, sockp->sa_data, hlen);
|
||||||
m->m_pkthdr.len -= hlen;
|
m->m_pkthdr.len -= hlen;
|
||||||
m->m_len -= hlen;
|
m->m_len -= hlen;
|
||||||
|
@ -126,6 +126,8 @@ ieee80211_ifattach(struct ieee80211com *ic)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
ether_ifattach(ifp, ic->ic_myaddr);
|
ether_ifattach(ifp, ic->ic_myaddr);
|
||||||
|
ifp->if_output = ieee80211_output;
|
||||||
|
|
||||||
bpfattach2(ifp, DLT_IEEE802_11,
|
bpfattach2(ifp, DLT_IEEE802_11,
|
||||||
sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
|
sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
|
||||||
|
|
||||||
@ -209,6 +211,9 @@ ieee80211_ifattach(struct ieee80211com *ic)
|
|||||||
*/
|
*/
|
||||||
if (ic->ic_reset == NULL)
|
if (ic->ic_reset == NULL)
|
||||||
ic->ic_reset = ieee80211_default_reset;
|
ic->ic_reset = ieee80211_default_reset;
|
||||||
|
|
||||||
|
KASSERT(ifp->if_spare2 == NULL, ("oops, hosed"));
|
||||||
|
ifp->if_spare2 = ic; /* XXX temp backpointer */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -225,4 +225,37 @@ struct ieee80211_michael_event {
|
|||||||
#define RTM_IEEE80211_MICHAEL 107 /* Michael MIC failure detected */
|
#define RTM_IEEE80211_MICHAEL 107 /* Michael MIC failure detected */
|
||||||
#define RTM_IEEE80211_REJOIN 108 /* station re-associate (ap mode) */
|
#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_ */
|
#endif /* _NET80211_IEEE80211_FREEBSD_H_ */
|
||||||
|
@ -203,6 +203,130 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni,
|
|||||||
return 0;
|
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.
|
* Send a null data frame to the specified node.
|
||||||
*
|
*
|
||||||
|
@ -114,6 +114,7 @@ ieee80211_proto_attach(struct ieee80211com *ic)
|
|||||||
/* initialize management frame handlers */
|
/* initialize management frame handlers */
|
||||||
ic->ic_recv_mgmt = ieee80211_recv_mgmt;
|
ic->ic_recv_mgmt = ieee80211_recv_mgmt;
|
||||||
ic->ic_send_mgmt = ieee80211_send_mgmt;
|
ic->ic_send_mgmt = ieee80211_send_mgmt;
|
||||||
|
ic->ic_raw_xmit = ieee80211_raw_xmit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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_saveie(u_int8_t **, const u_int8_t *);
|
||||||
void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
|
void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
|
||||||
struct ieee80211_node *, int, int, u_int32_t);
|
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_nulldata(struct ieee80211_node *);
|
||||||
int ieee80211_send_probereq(struct ieee80211_node *ni,
|
int ieee80211_send_probereq(struct ieee80211_node *ni,
|
||||||
const u_int8_t sa[IEEE80211_ADDR_LEN],
|
const u_int8_t sa[IEEE80211_ADDR_LEN],
|
||||||
|
@ -103,6 +103,9 @@ struct ieee80211com {
|
|||||||
void (*ic_newassoc)(struct ieee80211_node *, int);
|
void (*ic_newassoc)(struct ieee80211_node *, int);
|
||||||
void (*ic_updateslot)(struct ifnet *);
|
void (*ic_updateslot)(struct ifnet *);
|
||||||
void (*ic_set_tim)(struct ieee80211_node *, int);
|
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];
|
u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
|
||||||
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
|
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
|
||||||
struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];
|
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_SCLUSTER 34 /* Sitara cluster protocol */
|
||||||
#define AF_ARP 35
|
#define AF_ARP 35
|
||||||
#define AF_BLUETOOTH 36 /* Bluetooth sockets */
|
#define AF_BLUETOOTH 36 /* Bluetooth sockets */
|
||||||
#define AF_MAX 37
|
#define AF_IEEE80211 37 /* IEEE 802.11 protocol */
|
||||||
|
#define AF_MAX 38
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user