diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 670 |
1 files changed, 456 insertions, 214 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7ca4b5133123..c5661c5ad8f3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -59,13 +59,13 @@ enum nl80211_multicast_groups { | |||
59 | }; | 59 | }; |
60 | 60 | ||
61 | static const struct genl_multicast_group nl80211_mcgrps[] = { | 61 | static const struct genl_multicast_group nl80211_mcgrps[] = { |
62 | [NL80211_MCGRP_CONFIG] = { .name = "config", }, | 62 | [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG }, |
63 | [NL80211_MCGRP_SCAN] = { .name = "scan", }, | 63 | [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN }, |
64 | [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, | 64 | [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG }, |
65 | [NL80211_MCGRP_MLME] = { .name = "mlme", }, | 65 | [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME }, |
66 | [NL80211_MCGRP_VENDOR] = { .name = "vendor", }, | 66 | [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR }, |
67 | #ifdef CONFIG_NL80211_TESTMODE | 67 | #ifdef CONFIG_NL80211_TESTMODE |
68 | [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } | 68 | [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE } |
69 | #endif | 69 | #endif |
70 | }; | 70 | }; |
71 | 71 | ||
@@ -396,6 +396,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, | 396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, |
397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, | 397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, |
398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, | 398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, |
399 | [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, | ||
399 | }; | 400 | }; |
400 | 401 | ||
401 | /* policy for the key attributes */ | 402 | /* policy for the key attributes */ |
@@ -1087,6 +1088,11 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
1087 | return -ENOBUFS; | 1088 | return -ENOBUFS; |
1088 | } | 1089 | } |
1089 | 1090 | ||
1091 | if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) && | ||
1092 | nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT, | ||
1093 | rdev->wiphy.wowlan->max_nd_match_sets)) | ||
1094 | return -ENOBUFS; | ||
1095 | |||
1090 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) | 1096 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) |
1091 | return -ENOBUFS; | 1097 | return -ENOBUFS; |
1092 | 1098 | ||
@@ -1701,6 +1707,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1701 | rdev->wiphy.max_num_csa_counters)) | 1707 | rdev->wiphy.max_num_csa_counters)) |
1702 | goto nla_put_failure; | 1708 | goto nla_put_failure; |
1703 | 1709 | ||
1710 | if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
1711 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
1712 | goto nla_put_failure; | ||
1713 | |||
1714 | if (nla_put(msg, NL80211_ATTR_EXT_FEATURES, | ||
1715 | sizeof(rdev->wiphy.ext_features), | ||
1716 | rdev->wiphy.ext_features)) | ||
1717 | goto nla_put_failure; | ||
1718 | |||
1704 | /* done */ | 1719 | /* done */ |
1705 | state->split_start = 0; | 1720 | state->split_start = 0; |
1706 | break; | 1721 | break; |
@@ -3563,6 +3578,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
3563 | struct nlattr *rate; | 3578 | struct nlattr *rate; |
3564 | u32 bitrate; | 3579 | u32 bitrate; |
3565 | u16 bitrate_compat; | 3580 | u16 bitrate_compat; |
3581 | enum nl80211_attrs rate_flg; | ||
3566 | 3582 | ||
3567 | rate = nla_nest_start(msg, attr); | 3583 | rate = nla_nest_start(msg, attr); |
3568 | if (!rate) | 3584 | if (!rate) |
@@ -3579,12 +3595,36 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
3579 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) | 3595 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) |
3580 | return false; | 3596 | return false; |
3581 | 3597 | ||
3598 | switch (info->bw) { | ||
3599 | case RATE_INFO_BW_5: | ||
3600 | rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH; | ||
3601 | break; | ||
3602 | case RATE_INFO_BW_10: | ||
3603 | rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH; | ||
3604 | break; | ||
3605 | default: | ||
3606 | WARN_ON(1); | ||
3607 | /* fall through */ | ||
3608 | case RATE_INFO_BW_20: | ||
3609 | rate_flg = 0; | ||
3610 | break; | ||
3611 | case RATE_INFO_BW_40: | ||
3612 | rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH; | ||
3613 | break; | ||
3614 | case RATE_INFO_BW_80: | ||
3615 | rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH; | ||
3616 | break; | ||
3617 | case RATE_INFO_BW_160: | ||
3618 | rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH; | ||
3619 | break; | ||
3620 | } | ||
3621 | |||
3622 | if (rate_flg && nla_put_flag(msg, rate_flg)) | ||
3623 | return false; | ||
3624 | |||
3582 | if (info->flags & RATE_INFO_FLAGS_MCS) { | 3625 | if (info->flags & RATE_INFO_FLAGS_MCS) { |
3583 | if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) | 3626 | if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) |
3584 | return false; | 3627 | return false; |
3585 | if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && | ||
3586 | nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) | ||
3587 | return false; | ||
3588 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && | 3628 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && |
3589 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) | 3629 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) |
3590 | return false; | 3630 | return false; |
@@ -3593,18 +3633,6 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
3593 | return false; | 3633 | return false; |
3594 | if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss)) | 3634 | if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss)) |
3595 | return false; | 3635 | return false; |
3596 | if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && | ||
3597 | nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) | ||
3598 | return false; | ||
3599 | if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH && | ||
3600 | nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH)) | ||
3601 | return false; | ||
3602 | if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH && | ||
3603 | nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH)) | ||
3604 | return false; | ||
3605 | if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH && | ||
3606 | nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH)) | ||
3607 | return false; | ||
3608 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && | 3636 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && |
3609 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) | 3637 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) |
3610 | return false; | 3638 | return false; |
@@ -3640,8 +3668,8 @@ static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal, | |||
3640 | return true; | 3668 | return true; |
3641 | } | 3669 | } |
3642 | 3670 | ||
3643 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | 3671 | static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, |
3644 | int flags, | 3672 | u32 seq, int flags, |
3645 | struct cfg80211_registered_device *rdev, | 3673 | struct cfg80211_registered_device *rdev, |
3646 | struct net_device *dev, | 3674 | struct net_device *dev, |
3647 | const u8 *mac_addr, struct station_info *sinfo) | 3675 | const u8 *mac_addr, struct station_info *sinfo) |
@@ -3649,7 +3677,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3649 | void *hdr; | 3677 | void *hdr; |
3650 | struct nlattr *sinfoattr, *bss_param; | 3678 | struct nlattr *sinfoattr, *bss_param; |
3651 | 3679 | ||
3652 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION); | 3680 | hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); |
3653 | if (!hdr) | 3681 | if (!hdr) |
3654 | return -1; | 3682 | return -1; |
3655 | 3683 | ||
@@ -3661,115 +3689,77 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3661 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 3689 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
3662 | if (!sinfoattr) | 3690 | if (!sinfoattr) |
3663 | goto nla_put_failure; | 3691 | goto nla_put_failure; |
3664 | if ((sinfo->filled & STATION_INFO_CONNECTED_TIME) && | 3692 | |
3665 | nla_put_u32(msg, NL80211_STA_INFO_CONNECTED_TIME, | 3693 | #define PUT_SINFO(attr, memb, type) do { \ |
3666 | sinfo->connected_time)) | 3694 | if (sinfo->filled & BIT(NL80211_STA_INFO_ ## attr) && \ |
3667 | goto nla_put_failure; | 3695 | nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \ |
3668 | if ((sinfo->filled & STATION_INFO_INACTIVE_TIME) && | 3696 | sinfo->memb)) \ |
3669 | nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME, | 3697 | goto nla_put_failure; \ |
3670 | sinfo->inactive_time)) | 3698 | } while (0) |
3671 | goto nla_put_failure; | 3699 | |
3672 | if ((sinfo->filled & (STATION_INFO_RX_BYTES | | 3700 | PUT_SINFO(CONNECTED_TIME, connected_time, u32); |
3673 | STATION_INFO_RX_BYTES64)) && | 3701 | PUT_SINFO(INACTIVE_TIME, inactive_time, u32); |
3702 | |||
3703 | if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) | | ||
3704 | BIT(NL80211_STA_INFO_RX_BYTES64)) && | ||
3674 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, | 3705 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, |
3675 | (u32)sinfo->rx_bytes)) | 3706 | (u32)sinfo->rx_bytes)) |
3676 | goto nla_put_failure; | 3707 | goto nla_put_failure; |
3677 | if ((sinfo->filled & (STATION_INFO_TX_BYTES | | 3708 | |
3678 | STATION_INFO_TX_BYTES64)) && | 3709 | if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) | |
3710 | BIT(NL80211_STA_INFO_TX_BYTES64)) && | ||
3679 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, | 3711 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, |
3680 | (u32)sinfo->tx_bytes)) | 3712 | (u32)sinfo->tx_bytes)) |
3681 | goto nla_put_failure; | 3713 | goto nla_put_failure; |
3682 | if ((sinfo->filled & STATION_INFO_RX_BYTES64) && | 3714 | |
3683 | nla_put_u64(msg, NL80211_STA_INFO_RX_BYTES64, | 3715 | PUT_SINFO(RX_BYTES64, rx_bytes, u64); |
3684 | sinfo->rx_bytes)) | 3716 | PUT_SINFO(TX_BYTES64, tx_bytes, u64); |
3685 | goto nla_put_failure; | 3717 | PUT_SINFO(LLID, llid, u16); |
3686 | if ((sinfo->filled & STATION_INFO_TX_BYTES64) && | 3718 | PUT_SINFO(PLID, plid, u16); |
3687 | nla_put_u64(msg, NL80211_STA_INFO_TX_BYTES64, | 3719 | PUT_SINFO(PLINK_STATE, plink_state, u8); |
3688 | sinfo->tx_bytes)) | 3720 | |
3689 | goto nla_put_failure; | ||
3690 | if ((sinfo->filled & STATION_INFO_LLID) && | ||
3691 | nla_put_u16(msg, NL80211_STA_INFO_LLID, sinfo->llid)) | ||
3692 | goto nla_put_failure; | ||
3693 | if ((sinfo->filled & STATION_INFO_PLID) && | ||
3694 | nla_put_u16(msg, NL80211_STA_INFO_PLID, sinfo->plid)) | ||
3695 | goto nla_put_failure; | ||
3696 | if ((sinfo->filled & STATION_INFO_PLINK_STATE) && | ||
3697 | nla_put_u8(msg, NL80211_STA_INFO_PLINK_STATE, | ||
3698 | sinfo->plink_state)) | ||
3699 | goto nla_put_failure; | ||
3700 | switch (rdev->wiphy.signal_type) { | 3721 | switch (rdev->wiphy.signal_type) { |
3701 | case CFG80211_SIGNAL_TYPE_MBM: | 3722 | case CFG80211_SIGNAL_TYPE_MBM: |
3702 | if ((sinfo->filled & STATION_INFO_SIGNAL) && | 3723 | PUT_SINFO(SIGNAL, signal, u8); |
3703 | nla_put_u8(msg, NL80211_STA_INFO_SIGNAL, | 3724 | PUT_SINFO(SIGNAL_AVG, signal_avg, u8); |
3704 | sinfo->signal)) | ||
3705 | goto nla_put_failure; | ||
3706 | if ((sinfo->filled & STATION_INFO_SIGNAL_AVG) && | ||
3707 | nla_put_u8(msg, NL80211_STA_INFO_SIGNAL_AVG, | ||
3708 | sinfo->signal_avg)) | ||
3709 | goto nla_put_failure; | ||
3710 | break; | 3725 | break; |
3711 | default: | 3726 | default: |
3712 | break; | 3727 | break; |
3713 | } | 3728 | } |
3714 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) { | 3729 | if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) { |
3715 | if (!nl80211_put_signal(msg, sinfo->chains, | 3730 | if (!nl80211_put_signal(msg, sinfo->chains, |
3716 | sinfo->chain_signal, | 3731 | sinfo->chain_signal, |
3717 | NL80211_STA_INFO_CHAIN_SIGNAL)) | 3732 | NL80211_STA_INFO_CHAIN_SIGNAL)) |
3718 | goto nla_put_failure; | 3733 | goto nla_put_failure; |
3719 | } | 3734 | } |
3720 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) { | 3735 | if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) { |
3721 | if (!nl80211_put_signal(msg, sinfo->chains, | 3736 | if (!nl80211_put_signal(msg, sinfo->chains, |
3722 | sinfo->chain_signal_avg, | 3737 | sinfo->chain_signal_avg, |
3723 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) | 3738 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) |
3724 | goto nla_put_failure; | 3739 | goto nla_put_failure; |
3725 | } | 3740 | } |
3726 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 3741 | if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) { |
3727 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, | 3742 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, |
3728 | NL80211_STA_INFO_TX_BITRATE)) | 3743 | NL80211_STA_INFO_TX_BITRATE)) |
3729 | goto nla_put_failure; | 3744 | goto nla_put_failure; |
3730 | } | 3745 | } |
3731 | if (sinfo->filled & STATION_INFO_RX_BITRATE) { | 3746 | if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) { |
3732 | if (!nl80211_put_sta_rate(msg, &sinfo->rxrate, | 3747 | if (!nl80211_put_sta_rate(msg, &sinfo->rxrate, |
3733 | NL80211_STA_INFO_RX_BITRATE)) | 3748 | NL80211_STA_INFO_RX_BITRATE)) |
3734 | goto nla_put_failure; | 3749 | goto nla_put_failure; |
3735 | } | 3750 | } |
3736 | if ((sinfo->filled & STATION_INFO_RX_PACKETS) && | 3751 | |
3737 | nla_put_u32(msg, NL80211_STA_INFO_RX_PACKETS, | 3752 | PUT_SINFO(RX_PACKETS, rx_packets, u32); |
3738 | sinfo->rx_packets)) | 3753 | PUT_SINFO(TX_PACKETS, tx_packets, u32); |
3739 | goto nla_put_failure; | 3754 | PUT_SINFO(TX_RETRIES, tx_retries, u32); |
3740 | if ((sinfo->filled & STATION_INFO_TX_PACKETS) && | 3755 | PUT_SINFO(TX_FAILED, tx_failed, u32); |
3741 | nla_put_u32(msg, NL80211_STA_INFO_TX_PACKETS, | 3756 | PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32); |
3742 | sinfo->tx_packets)) | 3757 | PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32); |
3743 | goto nla_put_failure; | 3758 | PUT_SINFO(LOCAL_PM, local_pm, u32); |
3744 | if ((sinfo->filled & STATION_INFO_TX_RETRIES) && | 3759 | PUT_SINFO(PEER_PM, peer_pm, u32); |
3745 | nla_put_u32(msg, NL80211_STA_INFO_TX_RETRIES, | 3760 | PUT_SINFO(NONPEER_PM, nonpeer_pm, u32); |
3746 | sinfo->tx_retries)) | 3761 | |
3747 | goto nla_put_failure; | 3762 | if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) { |
3748 | if ((sinfo->filled & STATION_INFO_TX_FAILED) && | ||
3749 | nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED, | ||
3750 | sinfo->tx_failed)) | ||
3751 | goto nla_put_failure; | ||
3752 | if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) && | ||
3753 | nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT, | ||
3754 | sinfo->expected_throughput)) | ||
3755 | goto nla_put_failure; | ||
3756 | if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) && | ||
3757 | nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS, | ||
3758 | sinfo->beacon_loss_count)) | ||
3759 | goto nla_put_failure; | ||
3760 | if ((sinfo->filled & STATION_INFO_LOCAL_PM) && | ||
3761 | nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM, | ||
3762 | sinfo->local_pm)) | ||
3763 | goto nla_put_failure; | ||
3764 | if ((sinfo->filled & STATION_INFO_PEER_PM) && | ||
3765 | nla_put_u32(msg, NL80211_STA_INFO_PEER_PM, | ||
3766 | sinfo->peer_pm)) | ||
3767 | goto nla_put_failure; | ||
3768 | if ((sinfo->filled & STATION_INFO_NONPEER_PM) && | ||
3769 | nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM, | ||
3770 | sinfo->nonpeer_pm)) | ||
3771 | goto nla_put_failure; | ||
3772 | if (sinfo->filled & STATION_INFO_BSS_PARAM) { | ||
3773 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); | 3763 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); |
3774 | if (!bss_param) | 3764 | if (!bss_param) |
3775 | goto nla_put_failure; | 3765 | goto nla_put_failure; |
@@ -3788,18 +3778,62 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3788 | 3778 | ||
3789 | nla_nest_end(msg, bss_param); | 3779 | nla_nest_end(msg, bss_param); |
3790 | } | 3780 | } |
3791 | if ((sinfo->filled & STATION_INFO_STA_FLAGS) && | 3781 | if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) && |
3792 | nla_put(msg, NL80211_STA_INFO_STA_FLAGS, | 3782 | nla_put(msg, NL80211_STA_INFO_STA_FLAGS, |
3793 | sizeof(struct nl80211_sta_flag_update), | 3783 | sizeof(struct nl80211_sta_flag_update), |
3794 | &sinfo->sta_flags)) | 3784 | &sinfo->sta_flags)) |
3795 | goto nla_put_failure; | 3785 | goto nla_put_failure; |
3796 | if ((sinfo->filled & STATION_INFO_T_OFFSET) && | 3786 | |
3797 | nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET, | 3787 | PUT_SINFO(T_OFFSET, t_offset, u64); |
3798 | sinfo->t_offset)) | 3788 | PUT_SINFO(RX_DROP_MISC, rx_dropped_misc, u64); |
3799 | goto nla_put_failure; | 3789 | PUT_SINFO(BEACON_RX, rx_beacon, u64); |
3790 | PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8); | ||
3791 | |||
3792 | #undef PUT_SINFO | ||
3793 | |||
3794 | if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) { | ||
3795 | struct nlattr *tidsattr; | ||
3796 | int tid; | ||
3797 | |||
3798 | tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS); | ||
3799 | if (!tidsattr) | ||
3800 | goto nla_put_failure; | ||
3801 | |||
3802 | for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) { | ||
3803 | struct cfg80211_tid_stats *tidstats; | ||
3804 | struct nlattr *tidattr; | ||
3805 | |||
3806 | tidstats = &sinfo->pertid[tid]; | ||
3807 | |||
3808 | if (!tidstats->filled) | ||
3809 | continue; | ||
3810 | |||
3811 | tidattr = nla_nest_start(msg, tid + 1); | ||
3812 | if (!tidattr) | ||
3813 | goto nla_put_failure; | ||
3814 | |||
3815 | #define PUT_TIDVAL(attr, memb, type) do { \ | ||
3816 | if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \ | ||
3817 | nla_put_ ## type(msg, NL80211_TID_STATS_ ## attr, \ | ||
3818 | tidstats->memb)) \ | ||
3819 | goto nla_put_failure; \ | ||
3820 | } while (0) | ||
3821 | |||
3822 | PUT_TIDVAL(RX_MSDU, rx_msdu, u64); | ||
3823 | PUT_TIDVAL(TX_MSDU, tx_msdu, u64); | ||
3824 | PUT_TIDVAL(TX_MSDU_RETRIES, tx_msdu_retries, u64); | ||
3825 | PUT_TIDVAL(TX_MSDU_FAILED, tx_msdu_failed, u64); | ||
3826 | |||
3827 | #undef PUT_TIDVAL | ||
3828 | nla_nest_end(msg, tidattr); | ||
3829 | } | ||
3830 | |||
3831 | nla_nest_end(msg, tidsattr); | ||
3832 | } | ||
3833 | |||
3800 | nla_nest_end(msg, sinfoattr); | 3834 | nla_nest_end(msg, sinfoattr); |
3801 | 3835 | ||
3802 | if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) && | 3836 | if (sinfo->assoc_req_ies_len && |
3803 | nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, | 3837 | nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, |
3804 | sinfo->assoc_req_ies)) | 3838 | sinfo->assoc_req_ies)) |
3805 | goto nla_put_failure; | 3839 | goto nla_put_failure; |
@@ -3844,7 +3878,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
3844 | if (err) | 3878 | if (err) |
3845 | goto out_err; | 3879 | goto out_err; |
3846 | 3880 | ||
3847 | if (nl80211_send_station(skb, | 3881 | if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION, |
3848 | NETLINK_CB(cb->skb).portid, | 3882 | NETLINK_CB(cb->skb).portid, |
3849 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3883 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3850 | rdev, wdev->netdev, mac_addr, | 3884 | rdev, wdev->netdev, mac_addr, |
@@ -3891,7 +3925,8 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
3891 | if (!msg) | 3925 | if (!msg) |
3892 | return -ENOMEM; | 3926 | return -ENOMEM; |
3893 | 3927 | ||
3894 | if (nl80211_send_station(msg, info->snd_portid, info->snd_seq, 0, | 3928 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, |
3929 | info->snd_portid, info->snd_seq, 0, | ||
3895 | rdev, dev, mac_addr, &sinfo) < 0) { | 3930 | rdev, dev, mac_addr, &sinfo) < 0) { |
3896 | nlmsg_free(msg); | 3931 | nlmsg_free(msg); |
3897 | return -ENOBUFS; | 3932 | return -ENOBUFS; |
@@ -5327,42 +5362,20 @@ static int nl80211_update_mesh_config(struct sk_buff *skb, | |||
5327 | return err; | 5362 | return err; |
5328 | } | 5363 | } |
5329 | 5364 | ||
5330 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 5365 | static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom, |
5366 | struct sk_buff *msg) | ||
5331 | { | 5367 | { |
5332 | const struct ieee80211_regdomain *regdom; | ||
5333 | struct sk_buff *msg; | ||
5334 | void *hdr = NULL; | ||
5335 | struct nlattr *nl_reg_rules; | 5368 | struct nlattr *nl_reg_rules; |
5336 | unsigned int i; | 5369 | unsigned int i; |
5337 | 5370 | ||
5338 | if (!cfg80211_regdomain) | ||
5339 | return -EINVAL; | ||
5340 | |||
5341 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
5342 | if (!msg) | ||
5343 | return -ENOBUFS; | ||
5344 | |||
5345 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
5346 | NL80211_CMD_GET_REG); | ||
5347 | if (!hdr) | ||
5348 | goto put_failure; | ||
5349 | |||
5350 | if (reg_last_request_cell_base() && | ||
5351 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
5352 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
5353 | goto nla_put_failure; | ||
5354 | |||
5355 | rcu_read_lock(); | ||
5356 | regdom = rcu_dereference(cfg80211_regdomain); | ||
5357 | |||
5358 | if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) || | 5371 | if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) || |
5359 | (regdom->dfs_region && | 5372 | (regdom->dfs_region && |
5360 | nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region))) | 5373 | nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region))) |
5361 | goto nla_put_failure_rcu; | 5374 | goto nla_put_failure; |
5362 | 5375 | ||
5363 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 5376 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
5364 | if (!nl_reg_rules) | 5377 | if (!nl_reg_rules) |
5365 | goto nla_put_failure_rcu; | 5378 | goto nla_put_failure; |
5366 | 5379 | ||
5367 | for (i = 0; i < regdom->n_reg_rules; i++) { | 5380 | for (i = 0; i < regdom->n_reg_rules; i++) { |
5368 | struct nlattr *nl_reg_rule; | 5381 | struct nlattr *nl_reg_rule; |
@@ -5377,7 +5390,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5377 | 5390 | ||
5378 | nl_reg_rule = nla_nest_start(msg, i); | 5391 | nl_reg_rule = nla_nest_start(msg, i); |
5379 | if (!nl_reg_rule) | 5392 | if (!nl_reg_rule) |
5380 | goto nla_put_failure_rcu; | 5393 | goto nla_put_failure; |
5381 | 5394 | ||
5382 | max_bandwidth_khz = freq_range->max_bandwidth_khz; | 5395 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
5383 | if (!max_bandwidth_khz) | 5396 | if (!max_bandwidth_khz) |
@@ -5398,13 +5411,74 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5398 | power_rule->max_eirp) || | 5411 | power_rule->max_eirp) || |
5399 | nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, | 5412 | nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, |
5400 | reg_rule->dfs_cac_ms)) | 5413 | reg_rule->dfs_cac_ms)) |
5401 | goto nla_put_failure_rcu; | 5414 | goto nla_put_failure; |
5402 | 5415 | ||
5403 | nla_nest_end(msg, nl_reg_rule); | 5416 | nla_nest_end(msg, nl_reg_rule); |
5404 | } | 5417 | } |
5405 | rcu_read_unlock(); | ||
5406 | 5418 | ||
5407 | nla_nest_end(msg, nl_reg_rules); | 5419 | nla_nest_end(msg, nl_reg_rules); |
5420 | return 0; | ||
5421 | |||
5422 | nla_put_failure: | ||
5423 | return -EMSGSIZE; | ||
5424 | } | ||
5425 | |||
5426 | static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info) | ||
5427 | { | ||
5428 | const struct ieee80211_regdomain *regdom = NULL; | ||
5429 | struct cfg80211_registered_device *rdev; | ||
5430 | struct wiphy *wiphy = NULL; | ||
5431 | struct sk_buff *msg; | ||
5432 | void *hdr; | ||
5433 | |||
5434 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
5435 | if (!msg) | ||
5436 | return -ENOBUFS; | ||
5437 | |||
5438 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
5439 | NL80211_CMD_GET_REG); | ||
5440 | if (!hdr) | ||
5441 | goto put_failure; | ||
5442 | |||
5443 | if (info->attrs[NL80211_ATTR_WIPHY]) { | ||
5444 | bool self_managed; | ||
5445 | |||
5446 | rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); | ||
5447 | if (IS_ERR(rdev)) { | ||
5448 | nlmsg_free(msg); | ||
5449 | return PTR_ERR(rdev); | ||
5450 | } | ||
5451 | |||
5452 | wiphy = &rdev->wiphy; | ||
5453 | self_managed = wiphy->regulatory_flags & | ||
5454 | REGULATORY_WIPHY_SELF_MANAGED; | ||
5455 | regdom = get_wiphy_regdom(wiphy); | ||
5456 | |||
5457 | /* a self-managed-reg device must have a private regdom */ | ||
5458 | if (WARN_ON(!regdom && self_managed)) { | ||
5459 | nlmsg_free(msg); | ||
5460 | return -EINVAL; | ||
5461 | } | ||
5462 | |||
5463 | if (regdom && | ||
5464 | nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy))) | ||
5465 | goto nla_put_failure; | ||
5466 | } | ||
5467 | |||
5468 | if (!wiphy && reg_last_request_cell_base() && | ||
5469 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
5470 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
5471 | goto nla_put_failure; | ||
5472 | |||
5473 | rcu_read_lock(); | ||
5474 | |||
5475 | if (!regdom) | ||
5476 | regdom = rcu_dereference(cfg80211_regdomain); | ||
5477 | |||
5478 | if (nl80211_put_regdom(regdom, msg)) | ||
5479 | goto nla_put_failure_rcu; | ||
5480 | |||
5481 | rcu_read_unlock(); | ||
5408 | 5482 | ||
5409 | genlmsg_end(msg, hdr); | 5483 | genlmsg_end(msg, hdr); |
5410 | return genlmsg_reply(msg, info); | 5484 | return genlmsg_reply(msg, info); |
@@ -5418,6 +5492,83 @@ put_failure: | |||
5418 | return -EMSGSIZE; | 5492 | return -EMSGSIZE; |
5419 | } | 5493 | } |
5420 | 5494 | ||
5495 | static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb, | ||
5496 | u32 seq, int flags, struct wiphy *wiphy, | ||
5497 | const struct ieee80211_regdomain *regdom) | ||
5498 | { | ||
5499 | void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags, | ||
5500 | NL80211_CMD_GET_REG); | ||
5501 | |||
5502 | if (!hdr) | ||
5503 | return -1; | ||
5504 | |||
5505 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); | ||
5506 | |||
5507 | if (nl80211_put_regdom(regdom, msg)) | ||
5508 | goto nla_put_failure; | ||
5509 | |||
5510 | if (!wiphy && reg_last_request_cell_base() && | ||
5511 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
5512 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
5513 | goto nla_put_failure; | ||
5514 | |||
5515 | if (wiphy && | ||
5516 | nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy))) | ||
5517 | goto nla_put_failure; | ||
5518 | |||
5519 | if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
5520 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
5521 | goto nla_put_failure; | ||
5522 | |||
5523 | return genlmsg_end(msg, hdr); | ||
5524 | |||
5525 | nla_put_failure: | ||
5526 | genlmsg_cancel(msg, hdr); | ||
5527 | return -EMSGSIZE; | ||
5528 | } | ||
5529 | |||
5530 | static int nl80211_get_reg_dump(struct sk_buff *skb, | ||
5531 | struct netlink_callback *cb) | ||
5532 | { | ||
5533 | const struct ieee80211_regdomain *regdom = NULL; | ||
5534 | struct cfg80211_registered_device *rdev; | ||
5535 | int err, reg_idx, start = cb->args[2]; | ||
5536 | |||
5537 | rtnl_lock(); | ||
5538 | |||
5539 | if (cfg80211_regdomain && start == 0) { | ||
5540 | err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq, | ||
5541 | NLM_F_MULTI, NULL, | ||
5542 | rtnl_dereference(cfg80211_regdomain)); | ||
5543 | if (err < 0) | ||
5544 | goto out_err; | ||
5545 | } | ||
5546 | |||
5547 | /* the global regdom is idx 0 */ | ||
5548 | reg_idx = 1; | ||
5549 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
5550 | regdom = get_wiphy_regdom(&rdev->wiphy); | ||
5551 | if (!regdom) | ||
5552 | continue; | ||
5553 | |||
5554 | if (++reg_idx <= start) | ||
5555 | continue; | ||
5556 | |||
5557 | err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq, | ||
5558 | NLM_F_MULTI, &rdev->wiphy, regdom); | ||
5559 | if (err < 0) { | ||
5560 | reg_idx--; | ||
5561 | break; | ||
5562 | } | ||
5563 | } | ||
5564 | |||
5565 | cb->args[2] = reg_idx; | ||
5566 | err = skb->len; | ||
5567 | out_err: | ||
5568 | rtnl_unlock(); | ||
5569 | return err; | ||
5570 | } | ||
5571 | |||
5421 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 5572 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
5422 | { | 5573 | { |
5423 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; | 5574 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; |
@@ -6069,6 +6220,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
6069 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6220 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6070 | struct net_device *dev = info->user_ptr[1]; | 6221 | struct net_device *dev = info->user_ptr[1]; |
6071 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 6222 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
6223 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
6072 | int err; | 6224 | int err; |
6073 | 6225 | ||
6074 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 6226 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
@@ -6078,27 +6230,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
6078 | if (rdev->sched_scan_req) | 6230 | if (rdev->sched_scan_req) |
6079 | return -EINPROGRESS; | 6231 | return -EINPROGRESS; |
6080 | 6232 | ||
6081 | rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, | 6233 | sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, |
6082 | info->attrs); | 6234 | info->attrs); |
6083 | err = PTR_ERR_OR_ZERO(rdev->sched_scan_req); | 6235 | |
6236 | err = PTR_ERR_OR_ZERO(sched_scan_req); | ||
6084 | if (err) | 6237 | if (err) |
6085 | goto out_err; | 6238 | goto out_err; |
6086 | 6239 | ||
6087 | err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req); | 6240 | err = rdev_sched_scan_start(rdev, dev, sched_scan_req); |
6088 | if (err) | 6241 | if (err) |
6089 | goto out_free; | 6242 | goto out_free; |
6090 | 6243 | ||
6091 | rdev->sched_scan_req->dev = dev; | 6244 | sched_scan_req->dev = dev; |
6092 | rdev->sched_scan_req->wiphy = &rdev->wiphy; | 6245 | sched_scan_req->wiphy = &rdev->wiphy; |
6246 | |||
6247 | if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) | ||
6248 | sched_scan_req->owner_nlportid = info->snd_portid; | ||
6249 | |||
6250 | rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req); | ||
6093 | 6251 | ||
6094 | nl80211_send_sched_scan(rdev, dev, | 6252 | nl80211_send_sched_scan(rdev, dev, |
6095 | NL80211_CMD_START_SCHED_SCAN); | 6253 | NL80211_CMD_START_SCHED_SCAN); |
6096 | return 0; | 6254 | return 0; |
6097 | 6255 | ||
6098 | out_free: | 6256 | out_free: |
6099 | kfree(rdev->sched_scan_req); | 6257 | kfree(sched_scan_req); |
6100 | out_err: | 6258 | out_err: |
6101 | rdev->sched_scan_req = NULL; | ||
6102 | return err; | 6259 | return err; |
6103 | } | 6260 | } |
6104 | 6261 | ||
@@ -6481,12 +6638,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) | |||
6481 | } | 6638 | } |
6482 | 6639 | ||
6483 | static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | 6640 | static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, |
6484 | int flags, struct net_device *dev, | 6641 | int flags, struct net_device *dev, |
6485 | struct survey_info *survey) | 6642 | bool allow_radio_stats, |
6643 | struct survey_info *survey) | ||
6486 | { | 6644 | { |
6487 | void *hdr; | 6645 | void *hdr; |
6488 | struct nlattr *infoattr; | 6646 | struct nlattr *infoattr; |
6489 | 6647 | ||
6648 | /* skip radio stats if userspace didn't request them */ | ||
6649 | if (!survey->channel && !allow_radio_stats) | ||
6650 | return 0; | ||
6651 | |||
6490 | hdr = nl80211hdr_put(msg, portid, seq, flags, | 6652 | hdr = nl80211hdr_put(msg, portid, seq, flags, |
6491 | NL80211_CMD_NEW_SURVEY_RESULTS); | 6653 | NL80211_CMD_NEW_SURVEY_RESULTS); |
6492 | if (!hdr) | 6654 | if (!hdr) |
@@ -6499,7 +6661,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
6499 | if (!infoattr) | 6661 | if (!infoattr) |
6500 | goto nla_put_failure; | 6662 | goto nla_put_failure; |
6501 | 6663 | ||
6502 | if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, | 6664 | if (survey->channel && |
6665 | nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, | ||
6503 | survey->channel->center_freq)) | 6666 | survey->channel->center_freq)) |
6504 | goto nla_put_failure; | 6667 | goto nla_put_failure; |
6505 | 6668 | ||
@@ -6509,25 +6672,29 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
6509 | if ((survey->filled & SURVEY_INFO_IN_USE) && | 6672 | if ((survey->filled & SURVEY_INFO_IN_USE) && |
6510 | nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE)) | 6673 | nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE)) |
6511 | goto nla_put_failure; | 6674 | goto nla_put_failure; |
6512 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME) && | 6675 | if ((survey->filled & SURVEY_INFO_TIME) && |
6513 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME, | 6676 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME, |
6514 | survey->channel_time)) | 6677 | survey->time)) |
6678 | goto nla_put_failure; | ||
6679 | if ((survey->filled & SURVEY_INFO_TIME_BUSY) && | ||
6680 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_BUSY, | ||
6681 | survey->time_busy)) | ||
6515 | goto nla_put_failure; | 6682 | goto nla_put_failure; |
6516 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) && | 6683 | if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) && |
6517 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, | 6684 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY, |
6518 | survey->channel_time_busy)) | 6685 | survey->time_ext_busy)) |
6519 | goto nla_put_failure; | 6686 | goto nla_put_failure; |
6520 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) && | 6687 | if ((survey->filled & SURVEY_INFO_TIME_RX) && |
6521 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, | 6688 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_RX, |
6522 | survey->channel_time_ext_busy)) | 6689 | survey->time_rx)) |
6523 | goto nla_put_failure; | 6690 | goto nla_put_failure; |
6524 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) && | 6691 | if ((survey->filled & SURVEY_INFO_TIME_TX) && |
6525 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX, | 6692 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_TX, |
6526 | survey->channel_time_rx)) | 6693 | survey->time_tx)) |
6527 | goto nla_put_failure; | 6694 | goto nla_put_failure; |
6528 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) && | 6695 | if ((survey->filled & SURVEY_INFO_TIME_SCAN) && |
6529 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX, | 6696 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_SCAN, |
6530 | survey->channel_time_tx)) | 6697 | survey->time_scan)) |
6531 | goto nla_put_failure; | 6698 | goto nla_put_failure; |
6532 | 6699 | ||
6533 | nla_nest_end(msg, infoattr); | 6700 | nla_nest_end(msg, infoattr); |
@@ -6539,19 +6706,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
6539 | return -EMSGSIZE; | 6706 | return -EMSGSIZE; |
6540 | } | 6707 | } |
6541 | 6708 | ||
6542 | static int nl80211_dump_survey(struct sk_buff *skb, | 6709 | static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) |
6543 | struct netlink_callback *cb) | ||
6544 | { | 6710 | { |
6545 | struct survey_info survey; | 6711 | struct survey_info survey; |
6546 | struct cfg80211_registered_device *rdev; | 6712 | struct cfg80211_registered_device *rdev; |
6547 | struct wireless_dev *wdev; | 6713 | struct wireless_dev *wdev; |
6548 | int survey_idx = cb->args[2]; | 6714 | int survey_idx = cb->args[2]; |
6549 | int res; | 6715 | int res; |
6716 | bool radio_stats; | ||
6550 | 6717 | ||
6551 | res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); | 6718 | res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); |
6552 | if (res) | 6719 | if (res) |
6553 | return res; | 6720 | return res; |
6554 | 6721 | ||
6722 | /* prepare_wdev_dump parsed the attributes */ | ||
6723 | radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS]; | ||
6724 | |||
6555 | if (!wdev->netdev) { | 6725 | if (!wdev->netdev) { |
6556 | res = -EINVAL; | 6726 | res = -EINVAL; |
6557 | goto out_err; | 6727 | goto out_err; |
@@ -6569,13 +6739,9 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
6569 | if (res) | 6739 | if (res) |
6570 | goto out_err; | 6740 | goto out_err; |
6571 | 6741 | ||
6572 | /* Survey without a channel doesn't make sense */ | 6742 | /* don't send disabled channels, but do send non-channel data */ |
6573 | if (!survey.channel) { | 6743 | if (survey.channel && |
6574 | res = -EINVAL; | 6744 | survey.channel->flags & IEEE80211_CHAN_DISABLED) { |
6575 | goto out; | ||
6576 | } | ||
6577 | |||
6578 | if (survey.channel->flags & IEEE80211_CHAN_DISABLED) { | ||
6579 | survey_idx++; | 6745 | survey_idx++; |
6580 | continue; | 6746 | continue; |
6581 | } | 6747 | } |
@@ -6583,7 +6749,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
6583 | if (nl80211_send_survey(skb, | 6749 | if (nl80211_send_survey(skb, |
6584 | NETLINK_CB(cb->skb).portid, | 6750 | NETLINK_CB(cb->skb).portid, |
6585 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 6751 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
6586 | wdev->netdev, &survey) < 0) | 6752 | wdev->netdev, radio_stats, &survey) < 0) |
6587 | goto out; | 6753 | goto out; |
6588 | survey_idx++; | 6754 | survey_idx++; |
6589 | } | 6755 | } |
@@ -8599,6 +8765,48 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg, | |||
8599 | return 0; | 8765 | return 0; |
8600 | } | 8766 | } |
8601 | 8767 | ||
8768 | static int nl80211_send_wowlan_nd(struct sk_buff *msg, | ||
8769 | struct cfg80211_sched_scan_request *req) | ||
8770 | { | ||
8771 | struct nlattr *nd, *freqs, *matches, *match; | ||
8772 | int i; | ||
8773 | |||
8774 | if (!req) | ||
8775 | return 0; | ||
8776 | |||
8777 | nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT); | ||
8778 | if (!nd) | ||
8779 | return -ENOBUFS; | ||
8780 | |||
8781 | if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval)) | ||
8782 | return -ENOBUFS; | ||
8783 | |||
8784 | freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
8785 | if (!freqs) | ||
8786 | return -ENOBUFS; | ||
8787 | |||
8788 | for (i = 0; i < req->n_channels; i++) | ||
8789 | nla_put_u32(msg, i, req->channels[i]->center_freq); | ||
8790 | |||
8791 | nla_nest_end(msg, freqs); | ||
8792 | |||
8793 | if (req->n_match_sets) { | ||
8794 | matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); | ||
8795 | for (i = 0; i < req->n_match_sets; i++) { | ||
8796 | match = nla_nest_start(msg, i); | ||
8797 | nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID, | ||
8798 | req->match_sets[i].ssid.ssid_len, | ||
8799 | req->match_sets[i].ssid.ssid); | ||
8800 | nla_nest_end(msg, match); | ||
8801 | } | ||
8802 | nla_nest_end(msg, matches); | ||
8803 | } | ||
8804 | |||
8805 | nla_nest_end(msg, nd); | ||
8806 | |||
8807 | return 0; | ||
8808 | } | ||
8809 | |||
8602 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 8810 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
8603 | { | 8811 | { |
8604 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8812 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -8656,6 +8864,11 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
8656 | rdev->wiphy.wowlan_config->tcp)) | 8864 | rdev->wiphy.wowlan_config->tcp)) |
8657 | goto nla_put_failure; | 8865 | goto nla_put_failure; |
8658 | 8866 | ||
8867 | if (nl80211_send_wowlan_nd( | ||
8868 | msg, | ||
8869 | rdev->wiphy.wowlan_config->nd_config)) | ||
8870 | goto nla_put_failure; | ||
8871 | |||
8659 | nla_nest_end(msg, nl_wowlan); | 8872 | nla_nest_end(msg, nl_wowlan); |
8660 | } | 8873 | } |
8661 | 8874 | ||
@@ -10225,7 +10438,8 @@ static const struct genl_ops nl80211_ops[] = { | |||
10225 | }, | 10438 | }, |
10226 | { | 10439 | { |
10227 | .cmd = NL80211_CMD_GET_REG, | 10440 | .cmd = NL80211_CMD_GET_REG, |
10228 | .doit = nl80211_get_reg, | 10441 | .doit = nl80211_get_reg_do, |
10442 | .dumpit = nl80211_get_reg_dump, | ||
10229 | .policy = nl80211_policy, | 10443 | .policy = nl80211_policy, |
10230 | .internal_flags = NL80211_FLAG_NEED_RTNL, | 10444 | .internal_flags = NL80211_FLAG_NEED_RTNL, |
10231 | /* can be retrieved by unprivileged users */ | 10445 | /* can be retrieved by unprivileged users */ |
@@ -10939,25 +11153,9 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
10939 | NL80211_MCGRP_SCAN, GFP_KERNEL); | 11153 | NL80211_MCGRP_SCAN, GFP_KERNEL); |
10940 | } | 11154 | } |
10941 | 11155 | ||
10942 | /* | 11156 | static bool nl80211_reg_change_event_fill(struct sk_buff *msg, |
10943 | * This can happen on global regulatory changes or device specific settings | 11157 | struct regulatory_request *request) |
10944 | * based on custom world regulatory domains. | ||
10945 | */ | ||
10946 | void nl80211_send_reg_change_event(struct regulatory_request *request) | ||
10947 | { | 11158 | { |
10948 | struct sk_buff *msg; | ||
10949 | void *hdr; | ||
10950 | |||
10951 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
10952 | if (!msg) | ||
10953 | return; | ||
10954 | |||
10955 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE); | ||
10956 | if (!hdr) { | ||
10957 | nlmsg_free(msg); | ||
10958 | return; | ||
10959 | } | ||
10960 | |||
10961 | /* Userspace can always count this one always being set */ | 11159 | /* Userspace can always count this one always being set */ |
10962 | if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator)) | 11160 | if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator)) |
10963 | goto nla_put_failure; | 11161 | goto nla_put_failure; |
@@ -10983,8 +11181,46 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
10983 | goto nla_put_failure; | 11181 | goto nla_put_failure; |
10984 | } | 11182 | } |
10985 | 11183 | ||
10986 | if (request->wiphy_idx != WIPHY_IDX_INVALID && | 11184 | if (request->wiphy_idx != WIPHY_IDX_INVALID) { |
10987 | nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx)) | 11185 | struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx); |
11186 | |||
11187 | if (wiphy && | ||
11188 | nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx)) | ||
11189 | goto nla_put_failure; | ||
11190 | |||
11191 | if (wiphy && | ||
11192 | wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
11193 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
11194 | goto nla_put_failure; | ||
11195 | } | ||
11196 | |||
11197 | return true; | ||
11198 | |||
11199 | nla_put_failure: | ||
11200 | return false; | ||
11201 | } | ||
11202 | |||
11203 | /* | ||
11204 | * This can happen on global regulatory changes or device specific settings | ||
11205 | * based on custom regulatory domains. | ||
11206 | */ | ||
11207 | void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, | ||
11208 | struct regulatory_request *request) | ||
11209 | { | ||
11210 | struct sk_buff *msg; | ||
11211 | void *hdr; | ||
11212 | |||
11213 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
11214 | if (!msg) | ||
11215 | return; | ||
11216 | |||
11217 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id); | ||
11218 | if (!hdr) { | ||
11219 | nlmsg_free(msg); | ||
11220 | return; | ||
11221 | } | ||
11222 | |||
11223 | if (nl80211_reg_change_event_fill(msg, request) == false) | ||
10988 | goto nla_put_failure; | 11224 | goto nla_put_failure; |
10989 | 11225 | ||
10990 | genlmsg_end(msg, hdr); | 11226 | genlmsg_end(msg, hdr); |
@@ -11523,7 +11759,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
11523 | if (!msg) | 11759 | if (!msg) |
11524 | return; | 11760 | return; |
11525 | 11761 | ||
11526 | if (nl80211_send_station(msg, 0, 0, 0, | 11762 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0, |
11527 | rdev, dev, mac_addr, sinfo) < 0) { | 11763 | rdev, dev, mac_addr, sinfo) < 0) { |
11528 | nlmsg_free(msg); | 11764 | nlmsg_free(msg); |
11529 | return; | 11765 | return; |
@@ -11534,12 +11770,16 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
11534 | } | 11770 | } |
11535 | EXPORT_SYMBOL(cfg80211_new_sta); | 11771 | EXPORT_SYMBOL(cfg80211_new_sta); |
11536 | 11772 | ||
11537 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | 11773 | void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr, |
11774 | struct station_info *sinfo, gfp_t gfp) | ||
11538 | { | 11775 | { |
11539 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 11776 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; |
11540 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 11777 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
11541 | struct sk_buff *msg; | 11778 | struct sk_buff *msg; |
11542 | void *hdr; | 11779 | struct station_info empty_sinfo = {}; |
11780 | |||
11781 | if (!sinfo) | ||
11782 | sinfo = &empty_sinfo; | ||
11543 | 11783 | ||
11544 | trace_cfg80211_del_sta(dev, mac_addr); | 11784 | trace_cfg80211_del_sta(dev, mac_addr); |
11545 | 11785 | ||
@@ -11547,27 +11787,16 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | |||
11547 | if (!msg) | 11787 | if (!msg) |
11548 | return; | 11788 | return; |
11549 | 11789 | ||
11550 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); | 11790 | if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0, |
11551 | if (!hdr) { | 11791 | rdev, dev, mac_addr, sinfo) < 0) { |
11552 | nlmsg_free(msg); | 11792 | nlmsg_free(msg); |
11553 | return; | 11793 | return; |
11554 | } | 11794 | } |
11555 | 11795 | ||
11556 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
11557 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr)) | ||
11558 | goto nla_put_failure; | ||
11559 | |||
11560 | genlmsg_end(msg, hdr); | ||
11561 | |||
11562 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | 11796 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, |
11563 | NL80211_MCGRP_MLME, gfp); | 11797 | NL80211_MCGRP_MLME, gfp); |
11564 | return; | ||
11565 | |||
11566 | nla_put_failure: | ||
11567 | genlmsg_cancel(msg, hdr); | ||
11568 | nlmsg_free(msg); | ||
11569 | } | 11798 | } |
11570 | EXPORT_SYMBOL(cfg80211_del_sta); | 11799 | EXPORT_SYMBOL(cfg80211_del_sta_sinfo); |
11571 | 11800 | ||
11572 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | 11801 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, |
11573 | enum nl80211_connect_failed_reason reason, | 11802 | enum nl80211_connect_failed_reason reason, |
@@ -12471,6 +12700,13 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
12471 | 12700 | ||
12472 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 12701 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
12473 | bool schedule_destroy_work = false; | 12702 | bool schedule_destroy_work = false; |
12703 | bool schedule_scan_stop = false; | ||
12704 | struct cfg80211_sched_scan_request *sched_scan_req = | ||
12705 | rcu_dereference(rdev->sched_scan_req); | ||
12706 | |||
12707 | if (sched_scan_req && notify->portid && | ||
12708 | sched_scan_req->owner_nlportid == notify->portid) | ||
12709 | schedule_scan_stop = true; | ||
12474 | 12710 | ||
12475 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { | 12711 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { |
12476 | cfg80211_mlme_unregister_socket(wdev, notify->portid); | 12712 | cfg80211_mlme_unregister_socket(wdev, notify->portid); |
@@ -12501,6 +12737,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
12501 | spin_unlock(&rdev->destroy_list_lock); | 12737 | spin_unlock(&rdev->destroy_list_lock); |
12502 | schedule_work(&rdev->destroy_work); | 12738 | schedule_work(&rdev->destroy_work); |
12503 | } | 12739 | } |
12740 | } else if (schedule_scan_stop) { | ||
12741 | sched_scan_req->owner_nlportid = 0; | ||
12742 | |||
12743 | if (rdev->ops->sched_scan_stop && | ||
12744 | rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
12745 | schedule_work(&rdev->sched_scan_stop_wk); | ||
12504 | } | 12746 | } |
12505 | } | 12747 | } |
12506 | 12748 | ||