diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 105 |
1 files changed, 91 insertions, 14 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9ef8e287d61..beac296b1fd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -564,6 +564,88 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
564 | return 0; | 564 | return 0; |
565 | } | 565 | } |
566 | 566 | ||
567 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) | ||
568 | { | ||
569 | struct nlattr *nl_modes = nla_nest_start(msg, attr); | ||
570 | int i; | ||
571 | |||
572 | if (!nl_modes) | ||
573 | goto nla_put_failure; | ||
574 | |||
575 | i = 0; | ||
576 | while (ifmodes) { | ||
577 | if (ifmodes & 1) | ||
578 | NLA_PUT_FLAG(msg, i); | ||
579 | ifmodes >>= 1; | ||
580 | i++; | ||
581 | } | ||
582 | |||
583 | nla_nest_end(msg, nl_modes); | ||
584 | return 0; | ||
585 | |||
586 | nla_put_failure: | ||
587 | return -ENOBUFS; | ||
588 | } | ||
589 | |||
590 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, | ||
591 | struct sk_buff *msg) | ||
592 | { | ||
593 | struct nlattr *nl_combis; | ||
594 | int i, j; | ||
595 | |||
596 | nl_combis = nla_nest_start(msg, | ||
597 | NL80211_ATTR_INTERFACE_COMBINATIONS); | ||
598 | if (!nl_combis) | ||
599 | goto nla_put_failure; | ||
600 | |||
601 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
602 | const struct ieee80211_iface_combination *c; | ||
603 | struct nlattr *nl_combi, *nl_limits; | ||
604 | |||
605 | c = &wiphy->iface_combinations[i]; | ||
606 | |||
607 | nl_combi = nla_nest_start(msg, i + 1); | ||
608 | if (!nl_combi) | ||
609 | goto nla_put_failure; | ||
610 | |||
611 | nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS); | ||
612 | if (!nl_limits) | ||
613 | goto nla_put_failure; | ||
614 | |||
615 | for (j = 0; j < c->n_limits; j++) { | ||
616 | struct nlattr *nl_limit; | ||
617 | |||
618 | nl_limit = nla_nest_start(msg, j + 1); | ||
619 | if (!nl_limit) | ||
620 | goto nla_put_failure; | ||
621 | NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX, | ||
622 | c->limits[j].max); | ||
623 | if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, | ||
624 | c->limits[j].types)) | ||
625 | goto nla_put_failure; | ||
626 | nla_nest_end(msg, nl_limit); | ||
627 | } | ||
628 | |||
629 | nla_nest_end(msg, nl_limits); | ||
630 | |||
631 | if (c->beacon_int_infra_match) | ||
632 | NLA_PUT_FLAG(msg, | ||
633 | NL80211_IFACE_COMB_STA_AP_BI_MATCH); | ||
634 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, | ||
635 | c->num_different_channels); | ||
636 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM, | ||
637 | c->max_interfaces); | ||
638 | |||
639 | nla_nest_end(msg, nl_combi); | ||
640 | } | ||
641 | |||
642 | nla_nest_end(msg, nl_combis); | ||
643 | |||
644 | return 0; | ||
645 | nla_put_failure: | ||
646 | return -ENOBUFS; | ||
647 | } | ||
648 | |||
567 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 649 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
568 | struct cfg80211_registered_device *dev) | 650 | struct cfg80211_registered_device *dev) |
569 | { | 651 | { |
@@ -571,13 +653,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
571 | struct nlattr *nl_bands, *nl_band; | 653 | struct nlattr *nl_bands, *nl_band; |
572 | struct nlattr *nl_freqs, *nl_freq; | 654 | struct nlattr *nl_freqs, *nl_freq; |
573 | struct nlattr *nl_rates, *nl_rate; | 655 | struct nlattr *nl_rates, *nl_rate; |
574 | struct nlattr *nl_modes; | ||
575 | struct nlattr *nl_cmds; | 656 | struct nlattr *nl_cmds; |
576 | enum ieee80211_band band; | 657 | enum ieee80211_band band; |
577 | struct ieee80211_channel *chan; | 658 | struct ieee80211_channel *chan; |
578 | struct ieee80211_rate *rate; | 659 | struct ieee80211_rate *rate; |
579 | int i; | 660 | int i; |
580 | u16 ifmodes = dev->wiphy.interface_modes; | ||
581 | const struct ieee80211_txrx_stypes *mgmt_stypes = | 661 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
582 | dev->wiphy.mgmt_stypes; | 662 | dev->wiphy.mgmt_stypes; |
583 | 663 | ||
@@ -637,20 +717,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
637 | } | 717 | } |
638 | } | 718 | } |
639 | 719 | ||
640 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 720 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
641 | if (!nl_modes) | 721 | dev->wiphy.interface_modes)) |
642 | goto nla_put_failure; | 722 | goto nla_put_failure; |
643 | 723 | ||
644 | i = 0; | ||
645 | while (ifmodes) { | ||
646 | if (ifmodes & 1) | ||
647 | NLA_PUT_FLAG(msg, i); | ||
648 | ifmodes >>= 1; | ||
649 | i++; | ||
650 | } | ||
651 | |||
652 | nla_nest_end(msg, nl_modes); | ||
653 | |||
654 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 724 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
655 | if (!nl_bands) | 725 | if (!nl_bands) |
656 | goto nla_put_failure; | 726 | goto nla_put_failure; |
@@ -865,6 +935,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
865 | nla_nest_end(msg, nl_wowlan); | 935 | nla_nest_end(msg, nl_wowlan); |
866 | } | 936 | } |
867 | 937 | ||
938 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | ||
939 | dev->wiphy.software_iftypes)) | ||
940 | goto nla_put_failure; | ||
941 | |||
942 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | ||
943 | goto nla_put_failure; | ||
944 | |||
868 | return genlmsg_end(msg, hdr); | 945 | return genlmsg_end(msg, hdr); |
869 | 946 | ||
870 | nla_put_failure: | 947 | nla_put_failure: |