Commit a3b8b056 authored by Jouni Malinen's avatar Jouni Malinen Committed by John W. Linville

nl80211: Add Michael MIC failure event

Define a new nl80211 event, NL80211_CMD_MICHAEL_MIC_FAILURE, to be
used to notify user space about locally detected Michael MIC failures.
This matches with the MLME-MICHAELMICFAILURE.indication() primitive.

Since we do not actually have TSC in the skb anymore when
mac80211_ev_michael_mic_failure() is called, that function is changed
to take in the TSC as an optional parameter instead of as a
requirement to include the TSC after the hdr field (which we did not
really follow). For now, TSC is not included in the events from
mac80211, but it could be added at some point.
Signed-off-by: default avatarJouni Malinen <j@w1.fi>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 53b46b84
...@@ -199,6 +199,14 @@ ...@@ -199,6 +199,14 @@
* NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
* MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives). * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
* *
* @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
* MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
* event includes %NL80211_ATTR_MAC to describe the source MAC address of
* the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
* type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
* %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
* event matches with MLME-MICHAELMICFAILURE.indication() primitive
*
* @NL80211_CMD_MAX: highest used command number * @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
...@@ -260,6 +268,8 @@ enum nl80211_commands { ...@@ -260,6 +268,8 @@ enum nl80211_commands {
NL80211_CMD_DEAUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
NL80211_CMD_DISASSOCIATE, NL80211_CMD_DISASSOCIATE,
NL80211_CMD_MICHAEL_MIC_FAILURE,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
...@@ -408,6 +418,9 @@ enum nl80211_commands { ...@@ -408,6 +418,9 @@ enum nl80211_commands {
* @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
* %NL80211_CMD_DISASSOCIATE, u16 * %NL80211_CMD_DISASSOCIATE, u16
* *
* @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
* a u32
*
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
...@@ -492,6 +505,8 @@ enum nl80211_attrs { ...@@ -492,6 +505,8 @@ enum nl80211_attrs {
NL80211_ATTR_AUTH_TYPE, NL80211_ATTR_AUTH_TYPE,
NL80211_ATTR_REASON_CODE, NL80211_ATTR_REASON_CODE,
NL80211_ATTR_KEY_TYPE,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
...@@ -1062,4 +1077,17 @@ enum nl80211_auth_type { ...@@ -1062,4 +1077,17 @@ enum nl80211_auth_type {
NL80211_AUTHTYPE_FT, NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP, NL80211_AUTHTYPE_NETWORK_EAP,
}; };
/**
* enum nl80211_key_type - Key Type
* @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
* @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
* @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
*/
enum nl80211_key_type {
NL80211_KEYTYPE_GROUP,
NL80211_KEYTYPE_PAIRWISE,
NL80211_KEYTYPE_PEERKEY,
};
#endif /* __LINUX_NL80211_H */ #endif /* __LINUX_NL80211_H */
...@@ -957,4 +957,20 @@ void cfg80211_hold_bss(struct cfg80211_bss *bss); ...@@ -957,4 +957,20 @@ void cfg80211_hold_bss(struct cfg80211_bss *bss);
*/ */
void cfg80211_unhold_bss(struct cfg80211_bss *bss); void cfg80211_unhold_bss(struct cfg80211_bss *bss);
/**
* cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
* @dev: network device
* @addr: The source MAC address of the frame
* @key_type: The key type that the received frame used
* @key_id: Key identifier (0..3)
* @tsc: The TSC value of the frame that generated the MIC failure (6 octets)
*
* This function is called whenever the local MAC detects a MIC failure in a
* received frame. This matches with MLME-MICHAELMICFAILURE.indication()
* primitive.
*/
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
const u8 *tsc);
#endif /* __NET_CFG80211_H */ #endif /* __NET_CFG80211_H */
...@@ -12,12 +12,12 @@ ...@@ -12,12 +12,12 @@
#include "ieee80211_i.h" #include "ieee80211_i.h"
/* /*
* indicate a failed Michael MIC to userspace; the passed packet * Indicate a failed Michael MIC to userspace. If the caller knows the TSC of
* (in the variable hdr) must be long enough to extract the TKIP * the frame that generated the MIC failure (i.e., if it was provided by the
* fields like TSC * driver or is still in the frame), it should provide that information.
*/ */
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
struct ieee80211_hdr *hdr) struct ieee80211_hdr *hdr, const u8 *tsc)
{ {
union iwreq_data wrqu; union iwreq_data wrqu;
char *buf = kmalloc(128, GFP_ATOMIC); char *buf = kmalloc(128, GFP_ATOMIC);
...@@ -34,8 +34,9 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke ...@@ -34,8 +34,9 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
kfree(buf); kfree(buf);
} }
/* cfg80211_michael_mic_failure(sdata->dev, hdr->addr2,
* TODO: re-add support for sending MIC failure indication (hdr->addr1[0] & 0x01) ?
* with all info via nl80211 NL80211_KEYTYPE_GROUP :
*/ NL80211_KEYTYPE_PAIRWISE,
keyidx, tsc);
} }
...@@ -1060,7 +1060,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, ...@@ -1060,7 +1060,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
int rate, int erp, int short_preamble); int rate, int erp, int short_preamble);
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
struct ieee80211_hdr *hdr); struct ieee80211_hdr *hdr, const u8 *tsc);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
int encrypt); int encrypt);
......
...@@ -1932,7 +1932,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, ...@@ -1932,7 +1932,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
!ieee80211_is_auth(hdr->frame_control)) !ieee80211_is_auth(hdr->frame_control))
goto ignore; goto ignore;
mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr); mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL);
ignore: ignore:
dev_kfree_skb(rx->skb); dev_kfree_skb(rx->skb);
rx->skb = NULL; rx->skb = NULL;
......
...@@ -122,7 +122,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) ...@@ -122,7 +122,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE; return RX_DROP_UNUSABLE;
mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
(void *) skb->data); (void *) skb->data, NULL);
return RX_DROP_UNUSABLE; return RX_DROP_UNUSABLE;
} }
......
...@@ -43,3 +43,13 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) ...@@ -43,3 +43,13 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
nl80211_send_disassoc(rdev, dev, buf, len); nl80211_send_disassoc(rdev, dev, buf, len);
} }
EXPORT_SYMBOL(cfg80211_send_disassoc); EXPORT_SYMBOL(cfg80211_send_disassoc);
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
const u8 *tsc)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc);
}
EXPORT_SYMBOL(cfg80211_michael_mic_failure);
...@@ -3430,6 +3430,46 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, ...@@ -3430,6 +3430,46 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
NL80211_CMD_DISASSOCIATE); NL80211_CMD_DISASSOCIATE);
} }
void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
const u8 *tsc)
{
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
if (!hdr) {
nlmsg_free(msg);
return;
}
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
if (addr)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type);
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id);
if (tsc)
NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
if (genlmsg_end(msg, hdr) < 0) {
nlmsg_free(msg);
return;
}
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
return;
nla_put_failure:
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
/* initialisation/exit functions */ /* initialisation/exit functions */
int nl80211_init(void) int nl80211_init(void)
......
...@@ -23,5 +23,10 @@ extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev, ...@@ -23,5 +23,10 @@ extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, struct net_device *netdev,
const u8 *buf, size_t len); const u8 *buf, size_t len);
extern void
nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
enum nl80211_key_type key_type,
int key_id, const u8 *tsc);
#endif /* __NET_WIRELESS_NL80211_H */ #endif /* __NET_WIRELESS_NL80211_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment