aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c208
1 files changed, 161 insertions, 47 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8ed62b6c172b..37264d56bace 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -138,6 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
138 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, 138 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
139 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, 139 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
140 [NL80211_ATTR_PID] = { .type = NLA_U32 }, 140 [NL80211_ATTR_PID] = { .type = NLA_U32 },
141 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
141}; 142};
142 143
143/* policy for the attributes */ 144/* policy for the attributes */
@@ -151,6 +152,26 @@ nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
151 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, 152 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
152}; 153};
153 154
155/* ifidx get helper */
156static int nl80211_get_ifidx(struct netlink_callback *cb)
157{
158 int res;
159
160 res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
161 nl80211_fam.attrbuf, nl80211_fam.maxattr,
162 nl80211_policy);
163 if (res)
164 return res;
165
166 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
167 return -EINVAL;
168
169 res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
170 if (!res)
171 return -EINVAL;
172 return res;
173}
174
154/* IE validation */ 175/* IE validation */
155static bool is_valid_ie_attr(const struct nlattr *attr) 176static bool is_valid_ie_attr(const struct nlattr *attr)
156{ 177{
@@ -987,6 +1008,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
987 change = true; 1008 change = true;
988 } 1009 }
989 1010
1011 if (info->attrs[NL80211_ATTR_4ADDR]) {
1012 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1013 change = true;
1014 } else {
1015 params.use_4addr = -1;
1016 }
1017
990 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { 1018 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
991 if (ntype != NL80211_IFTYPE_MONITOR) { 1019 if (ntype != NL80211_IFTYPE_MONITOR) {
992 err = -EINVAL; 1020 err = -EINVAL;
@@ -1053,6 +1081,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1053 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 1081 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1054 } 1082 }
1055 1083
1084 if (info->attrs[NL80211_ATTR_4ADDR])
1085 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1086
1056 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 1087 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
1057 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 1088 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
1058 &flags); 1089 &flags);
@@ -1682,20 +1713,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
1682 int sta_idx = cb->args[1]; 1713 int sta_idx = cb->args[1];
1683 int err; 1714 int err;
1684 1715
1685 if (!ifidx) { 1716 if (!ifidx)
1686 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 1717 ifidx = nl80211_get_ifidx(cb);
1687 nl80211_fam.attrbuf, nl80211_fam.maxattr, 1718 if (ifidx < 0)
1688 nl80211_policy); 1719 return ifidx;
1689 if (err)
1690 return err;
1691
1692 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
1693 return -EINVAL;
1694
1695 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
1696 if (!ifidx)
1697 return -EINVAL;
1698 }
1699 1720
1700 rtnl_lock(); 1721 rtnl_lock();
1701 1722
@@ -1800,7 +1821,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
1800} 1821}
1801 1822
1802/* 1823/*
1803 * Get vlan interface making sure it is on the right wiphy. 1824 * Get vlan interface making sure it is running and on the right wiphy.
1804 */ 1825 */
1805static int get_vlan(struct genl_info *info, 1826static int get_vlan(struct genl_info *info,
1806 struct cfg80211_registered_device *rdev, 1827 struct cfg80211_registered_device *rdev,
@@ -1818,6 +1839,8 @@ static int get_vlan(struct genl_info *info,
1818 return -EINVAL; 1839 return -EINVAL;
1819 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) 1840 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
1820 return -EINVAL; 1841 return -EINVAL;
1842 if (!netif_running(*vlan))
1843 return -ENETDOWN;
1821 } 1844 }
1822 return 0; 1845 return 0;
1823} 1846}
@@ -2105,9 +2128,9 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
2105 if (pinfo->filled & MPATH_INFO_FRAME_QLEN) 2128 if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
2106 NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, 2129 NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
2107 pinfo->frame_qlen); 2130 pinfo->frame_qlen);
2108 if (pinfo->filled & MPATH_INFO_DSN) 2131 if (pinfo->filled & MPATH_INFO_SN)
2109 NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, 2132 NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN,
2110 pinfo->dsn); 2133 pinfo->sn);
2111 if (pinfo->filled & MPATH_INFO_METRIC) 2134 if (pinfo->filled & MPATH_INFO_METRIC)
2112 NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, 2135 NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
2113 pinfo->metric); 2136 pinfo->metric);
@@ -2145,20 +2168,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
2145 int path_idx = cb->args[1]; 2168 int path_idx = cb->args[1];
2146 int err; 2169 int err;
2147 2170
2148 if (!ifidx) { 2171 if (!ifidx)
2149 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 2172 ifidx = nl80211_get_ifidx(cb);
2150 nl80211_fam.attrbuf, nl80211_fam.maxattr, 2173 if (ifidx < 0)
2151 nl80211_policy); 2174 return ifidx;
2152 if (err)
2153 return err;
2154
2155 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
2156 return -EINVAL;
2157
2158 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
2159 if (!ifidx)
2160 return -EINVAL;
2161 }
2162 2175
2163 rtnl_lock(); 2176 rtnl_lock();
2164 2177
@@ -2605,6 +2618,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
2605 cur_params.dot11MeshHWMPpreqMinInterval); 2618 cur_params.dot11MeshHWMPpreqMinInterval);
2606 NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, 2619 NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
2607 cur_params.dot11MeshHWMPnetDiameterTraversalTime); 2620 cur_params.dot11MeshHWMPnetDiameterTraversalTime);
2621 NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
2622 cur_params.dot11MeshHWMPRootMode);
2608 nla_nest_end(msg, pinfoattr); 2623 nla_nest_end(msg, pinfoattr);
2609 genlmsg_end(msg, hdr); 2624 genlmsg_end(msg, hdr);
2610 err = genlmsg_reply(msg, info); 2625 err = genlmsg_reply(msg, info);
@@ -2715,6 +2730,10 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
2715 dot11MeshHWMPnetDiameterTraversalTime, 2730 dot11MeshHWMPnetDiameterTraversalTime,
2716 mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, 2731 mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
2717 nla_get_u16); 2732 nla_get_u16);
2733 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
2734 dot11MeshHWMPRootMode, mask,
2735 NL80211_MESHCONF_HWMP_ROOTMODE,
2736 nla_get_u8);
2718 2737
2719 /* Apply changes */ 2738 /* Apply changes */
2720 err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); 2739 err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
@@ -3181,21 +3200,11 @@ static int nl80211_dump_scan(struct sk_buff *skb,
3181 int start = cb->args[1], idx = 0; 3200 int start = cb->args[1], idx = 0;
3182 int err; 3201 int err;
3183 3202
3184 if (!ifidx) { 3203 if (!ifidx)
3185 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 3204 ifidx = nl80211_get_ifidx(cb);
3186 nl80211_fam.attrbuf, nl80211_fam.maxattr, 3205 if (ifidx < 0)
3187 nl80211_policy); 3206 return ifidx;
3188 if (err) 3207 cb->args[0] = ifidx;
3189 return err;
3190
3191 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
3192 return -EINVAL;
3193
3194 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
3195 if (!ifidx)
3196 return -EINVAL;
3197 cb->args[0] = ifidx;
3198 }
3199 3208
3200 dev = dev_get_by_index(sock_net(skb->sk), ifidx); 3209 dev = dev_get_by_index(sock_net(skb->sk), ifidx);
3201 if (!dev) 3210 if (!dev)
@@ -3238,6 +3247,106 @@ static int nl80211_dump_scan(struct sk_buff *skb,
3238 return err; 3247 return err;
3239} 3248}
3240 3249
3250static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
3251 int flags, struct net_device *dev,
3252 struct survey_info *survey)
3253{
3254 void *hdr;
3255 struct nlattr *infoattr;
3256
3257 /* Survey without a channel doesn't make sense */
3258 if (!survey->channel)
3259 return -EINVAL;
3260
3261 hdr = nl80211hdr_put(msg, pid, seq, flags,
3262 NL80211_CMD_NEW_SURVEY_RESULTS);
3263 if (!hdr)
3264 return -ENOMEM;
3265
3266 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
3267
3268 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
3269 if (!infoattr)
3270 goto nla_put_failure;
3271
3272 NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY,
3273 survey->channel->center_freq);
3274 if (survey->filled & SURVEY_INFO_NOISE_DBM)
3275 NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
3276 survey->noise);
3277
3278 nla_nest_end(msg, infoattr);
3279
3280 return genlmsg_end(msg, hdr);
3281
3282 nla_put_failure:
3283 genlmsg_cancel(msg, hdr);
3284 return -EMSGSIZE;
3285}
3286
3287static int nl80211_dump_survey(struct sk_buff *skb,
3288 struct netlink_callback *cb)
3289{
3290 struct survey_info survey;
3291 struct cfg80211_registered_device *dev;
3292 struct net_device *netdev;
3293 int ifidx = cb->args[0];
3294 int survey_idx = cb->args[1];
3295 int res;
3296
3297 if (!ifidx)
3298 ifidx = nl80211_get_ifidx(cb);
3299 if (ifidx < 0)
3300 return ifidx;
3301 cb->args[0] = ifidx;
3302
3303 rtnl_lock();
3304
3305 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
3306 if (!netdev) {
3307 res = -ENODEV;
3308 goto out_rtnl;
3309 }
3310
3311 dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
3312 if (IS_ERR(dev)) {
3313 res = PTR_ERR(dev);
3314 goto out_rtnl;
3315 }
3316
3317 if (!dev->ops->dump_survey) {
3318 res = -EOPNOTSUPP;
3319 goto out_err;
3320 }
3321
3322 while (1) {
3323 res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
3324 &survey);
3325 if (res == -ENOENT)
3326 break;
3327 if (res)
3328 goto out_err;
3329
3330 if (nl80211_send_survey(skb,
3331 NETLINK_CB(cb->skb).pid,
3332 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3333 netdev,
3334 &survey) < 0)
3335 goto out;
3336 survey_idx++;
3337 }
3338
3339 out:
3340 cb->args[1] = survey_idx;
3341 res = skb->len;
3342 out_err:
3343 cfg80211_unlock_rdev(dev);
3344 out_rtnl:
3345 rtnl_unlock();
3346
3347 return res;
3348}
3349
3241static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) 3350static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
3242{ 3351{
3243 return auth_type <= NL80211_AUTHTYPE_MAX; 3352 return auth_type <= NL80211_AUTHTYPE_MAX;
@@ -4315,6 +4424,11 @@ static struct genl_ops nl80211_ops[] = {
4315 .policy = nl80211_policy, 4424 .policy = nl80211_policy,
4316 .flags = GENL_ADMIN_PERM, 4425 .flags = GENL_ADMIN_PERM,
4317 }, 4426 },
4427 {
4428 .cmd = NL80211_CMD_GET_SURVEY,
4429 .policy = nl80211_policy,
4430 .dumpit = nl80211_dump_survey,
4431 },
4318}; 4432};
4319static struct genl_multicast_group nl80211_mlme_mcgrp = { 4433static struct genl_multicast_group nl80211_mlme_mcgrp = {
4320 .name = "mlme", 4434 .name = "mlme",