diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-01-22 06:34:29 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-01-31 08:00:21 -0500 |
commit | cd8f7cb4e6dfa4ea08fc250a814240b883ef7911 (patch) | |
tree | 2bcb8f04f01ee9768e5524799b0d429e51fb583d | |
parent | 3b144658bc7be5f7fa68d13ba24afb4c24489965 (diff) |
cfg80211/mac80211: support reporting wakeup reason
When waking up from WoWLAN, it is useful to know
what triggered the wakeup. Support reporting the
wakeup reason(s) in cfg80211 (and a pass-through
in mac80211) to allow userspace to know.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/cfg80211.h | 41 | ||||
-rw-r--r-- | include/net/mac80211.h | 12 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 31 | ||||
-rw-r--r-- | net/mac80211/pm.c | 10 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 97 | ||||
-rw-r--r-- | net/wireless/trace.h | 35 |
6 files changed, 226 insertions, 0 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 36e076e374d2..48add7e3ba1d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1597,6 +1597,32 @@ struct cfg80211_wowlan { | |||
1597 | }; | 1597 | }; |
1598 | 1598 | ||
1599 | /** | 1599 | /** |
1600 | * struct cfg80211_wowlan_wakeup - wakeup report | ||
1601 | * @disconnect: woke up by getting disconnected | ||
1602 | * @magic_pkt: woke up by receiving magic packet | ||
1603 | * @gtk_rekey_failure: woke up by GTK rekey failure | ||
1604 | * @eap_identity_req: woke up by EAP identity request packet | ||
1605 | * @four_way_handshake: woke up by 4-way handshake | ||
1606 | * @rfkill_release: woke up by rfkill being released | ||
1607 | * @pattern_idx: pattern that caused wakeup, -1 if not due to pattern | ||
1608 | * @packet_present_len: copied wakeup packet data | ||
1609 | * @packet_len: original wakeup packet length | ||
1610 | * @packet: The packet causing the wakeup, if any. | ||
1611 | * @packet_80211: For pattern match, magic packet and other data | ||
1612 | * frame triggers an 802.3 frame should be reported, for | ||
1613 | * disconnect due to deauth 802.11 frame. This indicates which | ||
1614 | * it is. | ||
1615 | */ | ||
1616 | struct cfg80211_wowlan_wakeup { | ||
1617 | bool disconnect, magic_pkt, gtk_rekey_failure, | ||
1618 | eap_identity_req, four_way_handshake, | ||
1619 | rfkill_release, packet_80211; | ||
1620 | s32 pattern_idx; | ||
1621 | u32 packet_present_len, packet_len; | ||
1622 | const void *packet; | ||
1623 | }; | ||
1624 | |||
1625 | /** | ||
1600 | * struct cfg80211_gtk_rekey_data - rekey data | 1626 | * struct cfg80211_gtk_rekey_data - rekey data |
1601 | * @kek: key encryption key | 1627 | * @kek: key encryption key |
1602 | * @kck: key confirmation key | 1628 | * @kck: key confirmation key |
@@ -3852,6 +3878,21 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | |||
3852 | enum ieee80211_p2p_attr_id attr, | 3878 | enum ieee80211_p2p_attr_id attr, |
3853 | u8 *buf, unsigned int bufsize); | 3879 | u8 *buf, unsigned int bufsize); |
3854 | 3880 | ||
3881 | /** | ||
3882 | * cfg80211_report_wowlan_wakeup - report wakeup from WoWLAN | ||
3883 | * @wdev: the wireless device reporting the wakeup | ||
3884 | * @wakeup: the wakeup report | ||
3885 | * @gfp: allocation flags | ||
3886 | * | ||
3887 | * This function reports that the given device woke up. If it | ||
3888 | * caused the wakeup, report the reason(s), otherwise you may | ||
3889 | * pass %NULL as the @wakeup parameter to advertise that something | ||
3890 | * else caused the wakeup. | ||
3891 | */ | ||
3892 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | ||
3893 | struct cfg80211_wowlan_wakeup *wakeup, | ||
3894 | gfp_t gfp); | ||
3895 | |||
3855 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 3896 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
3856 | 3897 | ||
3857 | /* wiphy_printk helpers, similar to dev_printk */ | 3898 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 21831ee57e3c..7a27e00c513a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -4206,4 +4206,16 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); | |||
4206 | */ | 4206 | */ |
4207 | int ieee80211_ave_rssi(struct ieee80211_vif *vif); | 4207 | int ieee80211_ave_rssi(struct ieee80211_vif *vif); |
4208 | 4208 | ||
4209 | /** | ||
4210 | * ieee80211_report_wowlan_wakeup - report WoWLAN wakeup | ||
4211 | * @vif: virtual interface | ||
4212 | * @wakeup: wakeup reason(s) | ||
4213 | * @gfp: allocation flags | ||
4214 | * | ||
4215 | * See cfg80211_report_wowlan_wakeup(). | ||
4216 | */ | ||
4217 | void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif, | ||
4218 | struct cfg80211_wowlan_wakeup *wakeup, | ||
4219 | gfp_t gfp); | ||
4220 | |||
4209 | #endif /* MAC80211_H */ | 4221 | #endif /* MAC80211_H */ |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5b7dbc1ea966..225a65e72219 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -513,6 +513,12 @@ | |||
513 | * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For | 513 | * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For |
514 | * more background information, see | 514 | * more background information, see |
515 | * http://wireless.kernel.org/en/users/Documentation/WoWLAN. | 515 | * http://wireless.kernel.org/en/users/Documentation/WoWLAN. |
516 | * The @NL80211_CMD_SET_WOWLAN command can also be used as a notification | ||
517 | * from the driver reporting the wakeup reason. In this case, the | ||
518 | * @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason | ||
519 | * for the wakeup, if it was caused by wireless. If it is not present | ||
520 | * in the wakeup notification, the wireless device didn't cause the | ||
521 | * wakeup but reports that it was woken up. | ||
516 | * | 522 | * |
517 | * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver | 523 | * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver |
518 | * the necessary information for supporting GTK rekey offload. This | 524 | * the necessary information for supporting GTK rekey offload. This |
@@ -2947,6 +2953,10 @@ struct nl80211_wowlan_pattern_support { | |||
2947 | * | 2953 | * |
2948 | * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute | 2954 | * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute |
2949 | * carrying a &struct nl80211_wowlan_pattern_support. | 2955 | * carrying a &struct nl80211_wowlan_pattern_support. |
2956 | * | ||
2957 | * When reporting wakeup. it is a u32 attribute containing the 0-based | ||
2958 | * index of the pattern that caused the wakeup, in the patterns passed | ||
2959 | * to the kernel when configuring. | ||
2950 | * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be | 2960 | * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be |
2951 | * used when setting, used only to indicate that GTK rekeying is supported | 2961 | * used when setting, used only to indicate that GTK rekeying is supported |
2952 | * by the device (flag) | 2962 | * by the device (flag) |
@@ -2957,8 +2967,25 @@ struct nl80211_wowlan_pattern_support { | |||
2957 | * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) | 2967 | * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) |
2958 | * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released | 2968 | * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released |
2959 | * (on devices that have rfkill in the device) (flag) | 2969 | * (on devices that have rfkill in the device) (flag) |
2970 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: For wakeup reporting only, contains | ||
2971 | * the 802.11 packet that caused the wakeup, e.g. a deauth frame. The frame | ||
2972 | * may be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN | ||
2973 | * attribute contains the original length. | ||
2974 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: Original length of the 802.11 | ||
2975 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211 | ||
2976 | * attribute if the packet was truncated somewhere. | ||
2977 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: For wakeup reporting only, contains the | ||
2978 | * 802.11 packet that caused the wakeup, e.g. a magic packet. The frame may | ||
2979 | * be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN attribute | ||
2980 | * contains the original length. | ||
2981 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3 | ||
2982 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 | ||
2983 | * attribute if the packet was truncated somewhere. | ||
2960 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers | 2984 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers |
2961 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number | 2985 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number |
2986 | * | ||
2987 | * These nested attributes are used to configure the wakeup triggers and | ||
2988 | * to report the wakeup reason(s). | ||
2962 | */ | 2989 | */ |
2963 | enum nl80211_wowlan_triggers { | 2990 | enum nl80211_wowlan_triggers { |
2964 | __NL80211_WOWLAN_TRIG_INVALID, | 2991 | __NL80211_WOWLAN_TRIG_INVALID, |
@@ -2971,6 +2998,10 @@ enum nl80211_wowlan_triggers { | |||
2971 | NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, | 2998 | NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, |
2972 | NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, | 2999 | NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, |
2973 | NL80211_WOWLAN_TRIG_RFKILL_RELEASE, | 3000 | NL80211_WOWLAN_TRIG_RFKILL_RELEASE, |
3001 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211, | ||
3002 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN, | ||
3003 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023, | ||
3004 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN, | ||
2974 | 3005 | ||
2975 | /* keep last */ | 3006 | /* keep last */ |
2976 | NUM_NL80211_WOWLAN_TRIG, | 3007 | NUM_NL80211_WOWLAN_TRIG, |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e45b83610e85..53801d20176d 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -228,3 +228,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
228 | * ieee80211_reconfig(), which is also needed for hardware | 228 | * ieee80211_reconfig(), which is also needed for hardware |
229 | * hang/firmware failure/etc. recovery. | 229 | * hang/firmware failure/etc. recovery. |
230 | */ | 230 | */ |
231 | |||
232 | void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif, | ||
233 | struct cfg80211_wowlan_wakeup *wakeup, | ||
234 | gfp_t gfp) | ||
235 | { | ||
236 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
237 | |||
238 | cfg80211_report_wowlan_wakeup(&sdata->wdev, wakeup, gfp); | ||
239 | } | ||
240 | EXPORT_SYMBOL(ieee80211_report_wowlan_wakeup); | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b5978ab4ad7a..d359734b6972 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -9323,6 +9323,103 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, | |||
9323 | } | 9323 | } |
9324 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | 9324 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); |
9325 | 9325 | ||
9326 | #ifdef CONFIG_PM | ||
9327 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | ||
9328 | struct cfg80211_wowlan_wakeup *wakeup, | ||
9329 | gfp_t gfp) | ||
9330 | { | ||
9331 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
9332 | struct sk_buff *msg; | ||
9333 | void *hdr; | ||
9334 | int err, size = 200; | ||
9335 | |||
9336 | trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup); | ||
9337 | |||
9338 | if (wakeup) | ||
9339 | size += wakeup->packet_present_len; | ||
9340 | |||
9341 | msg = nlmsg_new(size, gfp); | ||
9342 | if (!msg) | ||
9343 | return; | ||
9344 | |||
9345 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN); | ||
9346 | if (!hdr) | ||
9347 | goto free_msg; | ||
9348 | |||
9349 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
9350 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
9351 | goto free_msg; | ||
9352 | |||
9353 | if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, | ||
9354 | wdev->netdev->ifindex)) | ||
9355 | goto free_msg; | ||
9356 | |||
9357 | if (wakeup) { | ||
9358 | struct nlattr *reasons; | ||
9359 | |||
9360 | reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); | ||
9361 | |||
9362 | if (wakeup->disconnect && | ||
9363 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) | ||
9364 | goto free_msg; | ||
9365 | if (wakeup->magic_pkt && | ||
9366 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) | ||
9367 | goto free_msg; | ||
9368 | if (wakeup->gtk_rekey_failure && | ||
9369 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) | ||
9370 | goto free_msg; | ||
9371 | if (wakeup->eap_identity_req && | ||
9372 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) | ||
9373 | goto free_msg; | ||
9374 | if (wakeup->four_way_handshake && | ||
9375 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) | ||
9376 | goto free_msg; | ||
9377 | if (wakeup->rfkill_release && | ||
9378 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)) | ||
9379 | goto free_msg; | ||
9380 | |||
9381 | if (wakeup->pattern_idx >= 0 && | ||
9382 | nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
9383 | wakeup->pattern_idx)) | ||
9384 | goto free_msg; | ||
9385 | |||
9386 | if (wakeup->packet) { | ||
9387 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; | ||
9388 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; | ||
9389 | |||
9390 | if (!wakeup->packet_80211) { | ||
9391 | pkt_attr = | ||
9392 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023; | ||
9393 | len_attr = | ||
9394 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN; | ||
9395 | } | ||
9396 | |||
9397 | if (wakeup->packet_len && | ||
9398 | nla_put_u32(msg, len_attr, wakeup->packet_len)) | ||
9399 | goto free_msg; | ||
9400 | |||
9401 | if (nla_put(msg, pkt_attr, wakeup->packet_present_len, | ||
9402 | wakeup->packet)) | ||
9403 | goto free_msg; | ||
9404 | } | ||
9405 | |||
9406 | nla_nest_end(msg, reasons); | ||
9407 | } | ||
9408 | |||
9409 | err = genlmsg_end(msg, hdr); | ||
9410 | if (err < 0) | ||
9411 | goto free_msg; | ||
9412 | |||
9413 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
9414 | nl80211_mlme_mcgrp.id, gfp); | ||
9415 | return; | ||
9416 | |||
9417 | free_msg: | ||
9418 | nlmsg_free(msg); | ||
9419 | } | ||
9420 | EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup); | ||
9421 | #endif | ||
9422 | |||
9326 | void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, | 9423 | void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, |
9327 | enum nl80211_tdls_operation oper, | 9424 | enum nl80211_tdls_operation oper, |
9328 | u16 reason_code, gfp_t gfp) | 9425 | u16 reason_code, gfp_t gfp) |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 8bc553199686..c9cafb0ea95f 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -2333,6 +2333,41 @@ TRACE_EVENT(cfg80211_return_u32, | |||
2333 | TP_printk("ret: %u", __entry->ret) | 2333 | TP_printk("ret: %u", __entry->ret) |
2334 | ); | 2334 | ); |
2335 | 2335 | ||
2336 | TRACE_EVENT(cfg80211_report_wowlan_wakeup, | ||
2337 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
2338 | struct cfg80211_wowlan_wakeup *wakeup), | ||
2339 | TP_ARGS(wiphy, wdev, wakeup), | ||
2340 | TP_STRUCT__entry( | ||
2341 | WIPHY_ENTRY | ||
2342 | WDEV_ENTRY | ||
2343 | __field(bool, disconnect) | ||
2344 | __field(bool, magic_pkt) | ||
2345 | __field(bool, gtk_rekey_failure) | ||
2346 | __field(bool, eap_identity_req) | ||
2347 | __field(bool, four_way_handshake) | ||
2348 | __field(bool, rfkill_release) | ||
2349 | __field(s32, pattern_idx) | ||
2350 | __field(u32, packet_len) | ||
2351 | __dynamic_array(u8, packet, wakeup->packet_present_len) | ||
2352 | ), | ||
2353 | TP_fast_assign( | ||
2354 | WIPHY_ASSIGN; | ||
2355 | WDEV_ASSIGN; | ||
2356 | __entry->disconnect = wakeup->disconnect; | ||
2357 | __entry->magic_pkt = wakeup->magic_pkt; | ||
2358 | __entry->gtk_rekey_failure = wakeup->gtk_rekey_failure; | ||
2359 | __entry->eap_identity_req = wakeup->eap_identity_req; | ||
2360 | __entry->four_way_handshake = wakeup->four_way_handshake; | ||
2361 | __entry->rfkill_release = wakeup->rfkill_release; | ||
2362 | __entry->pattern_idx = wakeup->pattern_idx; | ||
2363 | __entry->packet_len = wakeup->packet_len; | ||
2364 | if (wakeup->packet && wakeup->packet_present_len) | ||
2365 | memcpy(__get_dynamic_array(packet), wakeup->packet, | ||
2366 | wakeup->packet_present_len); | ||
2367 | ), | ||
2368 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | ||
2369 | ); | ||
2370 | |||
2336 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 2371 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
2337 | 2372 | ||
2338 | #undef TRACE_INCLUDE_PATH | 2373 | #undef TRACE_INCLUDE_PATH |