diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1e728fff474e..e69da8d20474 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -105,6 +105,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
105 | 105 | ||
106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
107 | .len = NL80211_HT_CAPABILITY_LEN }, | 107 | .len = NL80211_HT_CAPABILITY_LEN }, |
108 | |||
109 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | ||
110 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | ||
111 | .len = IEEE80211_MAX_DATA_LEN }, | ||
108 | }; | 112 | }; |
109 | 113 | ||
110 | /* message building helper */ | 114 | /* message building helper */ |
@@ -738,7 +742,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
738 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 742 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
739 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 743 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
740 | 744 | ||
741 | if (key_idx > 3) | 745 | if (key_idx > 5) |
742 | return -EINVAL; | 746 | return -EINVAL; |
743 | 747 | ||
744 | if (info->attrs[NL80211_ATTR_MAC]) | 748 | if (info->attrs[NL80211_ATTR_MAC]) |
@@ -804,30 +808,41 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
804 | int err; | 808 | int err; |
805 | struct net_device *dev; | 809 | struct net_device *dev; |
806 | u8 key_idx; | 810 | u8 key_idx; |
811 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | ||
812 | u8 key_index); | ||
807 | 813 | ||
808 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) | 814 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) |
809 | return -EINVAL; | 815 | return -EINVAL; |
810 | 816 | ||
811 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 817 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
812 | 818 | ||
813 | if (key_idx > 3) | 819 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) { |
820 | if (key_idx < 4 || key_idx > 5) | ||
821 | return -EINVAL; | ||
822 | } else if (key_idx > 3) | ||
814 | return -EINVAL; | 823 | return -EINVAL; |
815 | 824 | ||
816 | /* currently only support setting default key */ | 825 | /* currently only support setting default key */ |
817 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) | 826 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] && |
827 | !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) | ||
818 | return -EINVAL; | 828 | return -EINVAL; |
819 | 829 | ||
820 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 830 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
821 | if (err) | 831 | if (err) |
822 | return err; | 832 | return err; |
823 | 833 | ||
824 | if (!drv->ops->set_default_key) { | 834 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) |
835 | func = drv->ops->set_default_key; | ||
836 | else | ||
837 | func = drv->ops->set_default_mgmt_key; | ||
838 | |||
839 | if (!func) { | ||
825 | err = -EOPNOTSUPP; | 840 | err = -EOPNOTSUPP; |
826 | goto out; | 841 | goto out; |
827 | } | 842 | } |
828 | 843 | ||
829 | rtnl_lock(); | 844 | rtnl_lock(); |
830 | err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); | 845 | err = func(&drv->wiphy, dev, key_idx); |
831 | rtnl_unlock(); | 846 | rtnl_unlock(); |
832 | 847 | ||
833 | out: | 848 | out: |
@@ -863,7 +878,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
863 | if (info->attrs[NL80211_ATTR_MAC]) | 878 | if (info->attrs[NL80211_ATTR_MAC]) |
864 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 879 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
865 | 880 | ||
866 | if (key_idx > 3) | 881 | if (key_idx > 5) |
867 | return -EINVAL; | 882 | return -EINVAL; |
868 | 883 | ||
869 | /* | 884 | /* |
@@ -894,6 +909,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
894 | if (params.key_len != 13) | 909 | if (params.key_len != 13) |
895 | return -EINVAL; | 910 | return -EINVAL; |
896 | break; | 911 | break; |
912 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
913 | if (params.key_len != 16) | ||
914 | return -EINVAL; | ||
915 | break; | ||
897 | default: | 916 | default: |
898 | return -EINVAL; | 917 | return -EINVAL; |
899 | } | 918 | } |
@@ -928,7 +947,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
928 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 947 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
929 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 948 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
930 | 949 | ||
931 | if (key_idx > 3) | 950 | if (key_idx > 5) |
932 | return -EINVAL; | 951 | return -EINVAL; |
933 | 952 | ||
934 | if (info->attrs[NL80211_ATTR_MAC]) | 953 | if (info->attrs[NL80211_ATTR_MAC]) |
@@ -1889,6 +1908,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
1889 | mutex_lock(&cfg80211_drv_mutex); | 1908 | mutex_lock(&cfg80211_drv_mutex); |
1890 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); | 1909 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); |
1891 | mutex_unlock(&cfg80211_drv_mutex); | 1910 | mutex_unlock(&cfg80211_drv_mutex); |
1911 | /* This means the regulatory domain was already set, however | ||
1912 | * we don't want to confuse userspace with a "successful error" | ||
1913 | * message so lets just treat it as a success */ | ||
1914 | if (r == -EALREADY) | ||
1915 | r = 0; | ||
1892 | return r; | 1916 | return r; |
1893 | } | 1917 | } |
1894 | 1918 | ||
@@ -2134,6 +2158,43 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2134 | return -EINVAL; | 2158 | return -EINVAL; |
2135 | } | 2159 | } |
2136 | 2160 | ||
2161 | static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb, | ||
2162 | struct genl_info *info) | ||
2163 | { | ||
2164 | struct cfg80211_registered_device *drv; | ||
2165 | int err; | ||
2166 | struct net_device *dev; | ||
2167 | struct mgmt_extra_ie_params params; | ||
2168 | |||
2169 | memset(¶ms, 0, sizeof(params)); | ||
2170 | |||
2171 | if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) | ||
2172 | return -EINVAL; | ||
2173 | params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); | ||
2174 | if (params.subtype > 15) | ||
2175 | return -EINVAL; /* FC Subtype field is 4 bits (0..15) */ | ||
2176 | |||
2177 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2178 | params.ies = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2179 | params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2180 | } | ||
2181 | |||
2182 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2183 | if (err) | ||
2184 | return err; | ||
2185 | |||
2186 | if (drv->ops->set_mgmt_extra_ie) { | ||
2187 | rtnl_lock(); | ||
2188 | err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, ¶ms); | ||
2189 | rtnl_unlock(); | ||
2190 | } else | ||
2191 | err = -EOPNOTSUPP; | ||
2192 | |||
2193 | cfg80211_put_dev(drv); | ||
2194 | dev_put(dev); | ||
2195 | return err; | ||
2196 | } | ||
2197 | |||
2137 | static struct genl_ops nl80211_ops[] = { | 2198 | static struct genl_ops nl80211_ops[] = { |
2138 | { | 2199 | { |
2139 | .cmd = NL80211_CMD_GET_WIPHY, | 2200 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -2295,6 +2356,12 @@ static struct genl_ops nl80211_ops[] = { | |||
2295 | .policy = nl80211_policy, | 2356 | .policy = nl80211_policy, |
2296 | .flags = GENL_ADMIN_PERM, | 2357 | .flags = GENL_ADMIN_PERM, |
2297 | }, | 2358 | }, |
2359 | { | ||
2360 | .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE, | ||
2361 | .doit = nl80211_set_mgmt_extra_ie, | ||
2362 | .policy = nl80211_policy, | ||
2363 | .flags = GENL_ADMIN_PERM, | ||
2364 | }, | ||
2298 | }; | 2365 | }; |
2299 | 2366 | ||
2300 | /* multicast groups */ | 2367 | /* multicast groups */ |