diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -2732,3 +2732,40 @@ */ return (!ieee80211_is_key_global(vap, key)); } + +/** + * Determine whether the given control frame is from a known node + * and destined to us. + * + * In some instances a control frame won't have a TA (eg ACKs), so + * we should only verify the RA for those. + * + * @param ni ieee80211_node representing the sender, or BSS node + * @param m0 mbuf representing the 802.11 frame. + * @returns true if the frame is not a CTL frame (but with a warning + * logged); + * true if the frame is from a known sender / valid recipient, + * false otherwise. + */ +bool +ieee80211_is_ctl_frame_for_vap(struct ieee80211_node *ni, const struct mbuf *m0) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ifnet *ifp = vap->iv_ifp; + const struct ieee80211_frame *wh; + + wh = mtod(m0, const struct ieee80211_frame *); + + /* Verify it's a ctl frame. */ + if (!IEEE80211_IS_CTL(wh)) { + if_printf(vap->iv_ifp, + "%s: not a control frame (fc[0]=0x%04x)\n", + __func__, (wh)->i_fc[0]); + return (true); + } + + /* TODO: verify the TA if the frame format has a TA */ + + /* Verify the RA */ + return (IEEE80211_ADDR_EQ(wh->i_addr1, IF_LLADDR(ifp))); +} diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c --- a/sys/net80211/ieee80211_adhoc.c +++ b/sys/net80211/ieee80211_adhoc.c @@ -1047,6 +1047,16 @@ static void adhoc_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + struct ieee80211vap *vap = ni->ni_vap; + const struct ieee80211_frame *wh; + + wh = mtod(m, const struct ieee80211_frame *); + if (! ieee80211_is_ctl_frame_for_vap(ni, m)) { + ic_printf(vap->iv_ic, + "%s: ignoring CTL frame (%d) not meant for us (%6D->%6D)\n", + __func__, subtype, wh->i_addr2, ":", wh->i_addr1, ":"); + return; + } switch (subtype) { case IEEE80211_FC0_SUBTYPE_BAR: diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -2418,6 +2418,17 @@ static void hostap_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + struct ieee80211vap *vap = ni->ni_vap; + const struct ieee80211_frame *wh; + + wh = mtod(m, const struct ieee80211_frame *); + if (! ieee80211_is_ctl_frame_for_vap(ni, m)) { + ic_printf(vap->iv_ic, + "%s: ignoring CTL frame (%d) not meant for us (%6D->%6D)\n", + __func__, subtype, wh->i_addr2, ":", wh->i_addr1, ":"); + return; + } + switch (subtype) { case IEEE80211_FC0_SUBTYPE_PS_POLL: ni->ni_vap->iv_recv_pspoll(ni, m); diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c --- a/sys/net80211/ieee80211_mesh.c +++ b/sys/net80211/ieee80211_mesh.c @@ -2089,6 +2089,17 @@ static void mesh_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + struct ieee80211vap *vap = ni->ni_vap; + const struct ieee80211_frame *wh; + + wh = mtod(m, const struct ieee80211_frame *); + if (! ieee80211_is_ctl_frame_for_vap(ni, m)) { + ic_printf(vap->iv_ic, + "%s: ignoring CTL frame (%d) not meant for us (%6D->%6D)\n", + __func__, subtype, wh->i_addr2, ":", wh->i_addr1, ":"); + return; + } + switch (subtype) { case IEEE80211_FC0_SUBTYPE_BAR: diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c --- a/sys/net80211/ieee80211_sta.c +++ b/sys/net80211/ieee80211_sta.c @@ -2054,6 +2054,17 @@ static void sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + struct ieee80211vap *vap = ni->ni_vap; + const struct ieee80211_frame *wh; + + wh = mtod(m, const struct ieee80211_frame *); + if (! ieee80211_is_ctl_frame_for_vap(ni, m)) { + ic_printf(vap->iv_ic, + "%s: ignoring CTL frame (%d) not meant for us (%6D->%6D)\n", + __func__, subtype, wh->i_addr2, ":", wh->i_addr1, ":"); + return; + } + switch (subtype) { case IEEE80211_FC0_SUBTYPE_BAR: ieee80211_recv_bar(ni, m); diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -842,6 +842,9 @@ bool ieee80211_is_key_unicast(const struct ieee80211vap *vap, const struct ieee80211_key *key); +bool ieee80211_is_ctl_frame_for_vap(struct ieee80211_node *, + const struct mbuf *); + void ieee80211_radiotap_attach(struct ieee80211com *, struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,