aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-02-13 09:17:18 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-02-22 14:51:18 -0500
commit8860020e0be1f03d83dc9e9e93e18a4ddbe01038 (patch)
tree09fa9089770e8a42e913f6c11abbba04bec20fad /net/wireless/nl80211.c
parent4e3bc141d480661634d0fadad7dbb1ddde70b4d4 (diff)
cfg80211: restructure AP/GO mode API
The AP/GO mode API isn't very clearly defined, it has "set beacon" and "new beacon" etc. Modify the API to the following: * start AP -- all settings * change beacon -- new beacon data * stop AP -- stop AP mode operation This also reflects in the nl80211 API, rename the commands there correspondingly (but keep the old names for compatibility.) Overall, this makes it much clearer what's going on in the API. Kalle developed the ath6kl changes, I created the rest of the patch. Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c255
1 files changed, 142 insertions, 113 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fe2747653564..1998c3682774 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -871,7 +871,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
871 CMD(add_virtual_intf, NEW_INTERFACE); 871 CMD(add_virtual_intf, NEW_INTERFACE);
872 CMD(change_virtual_intf, SET_INTERFACE); 872 CMD(change_virtual_intf, SET_INTERFACE);
873 CMD(add_key, NEW_KEY); 873 CMD(add_key, NEW_KEY);
874 CMD(add_beacon, NEW_BEACON); 874 CMD(start_ap, START_AP);
875 CMD(add_station, NEW_STATION); 875 CMD(add_station, NEW_STATION);
876 CMD(add_mpath, NEW_MPATH); 876 CMD(add_mpath, NEW_MPATH);
877 CMD(update_mesh_config, SET_MESH_CONFIG); 877 CMD(update_mesh_config, SET_MESH_CONFIG);
@@ -2075,15 +2075,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
2075 return err; 2075 return err;
2076} 2076}
2077 2077
2078static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) 2078static int nl80211_parse_beacon(struct genl_info *info,
2079 struct cfg80211_beacon_data *bcn)
2079{ 2080{
2080 int (*call)(struct wiphy *wiphy, struct net_device *dev, 2081 bool haveinfo = false;
2081 struct beacon_parameters *info);
2082 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2083 struct net_device *dev = info->user_ptr[1];
2084 struct wireless_dev *wdev = dev->ieee80211_ptr;
2085 struct beacon_parameters params;
2086 int haveinfo = 0, err;
2087 2082
2088 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) || 2083 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
2089 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) || 2084 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
@@ -2091,149 +2086,183 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
2091 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP])) 2086 !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
2092 return -EINVAL; 2087 return -EINVAL;
2093 2088
2094 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2089 memset(bcn, 0, sizeof(*bcn));
2095 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2096 return -EOPNOTSUPP;
2097
2098 memset(&params, 0, sizeof(params));
2099
2100 switch (info->genlhdr->cmd) {
2101 case NL80211_CMD_NEW_BEACON:
2102 /* these are required for NEW_BEACON */
2103 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
2104 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
2105 !info->attrs[NL80211_ATTR_BEACON_HEAD])
2106 return -EINVAL;
2107
2108 params.interval =
2109 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
2110 params.dtim_period =
2111 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
2112
2113 err = cfg80211_validate_beacon_int(rdev, params.interval);
2114 if (err)
2115 return err;
2116
2117 /*
2118 * In theory, some of these attributes could be required for
2119 * NEW_BEACON, but since they were not used when the command was
2120 * originally added, keep them optional for old user space
2121 * programs to work with drivers that do not need the additional
2122 * information.
2123 */
2124 if (info->attrs[NL80211_ATTR_SSID]) {
2125 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2126 params.ssid_len =
2127 nla_len(info->attrs[NL80211_ATTR_SSID]);
2128 if (params.ssid_len == 0 ||
2129 params.ssid_len > IEEE80211_MAX_SSID_LEN)
2130 return -EINVAL;
2131 }
2132
2133 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
2134 params.hidden_ssid = nla_get_u32(
2135 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
2136 if (params.hidden_ssid !=
2137 NL80211_HIDDEN_SSID_NOT_IN_USE &&
2138 params.hidden_ssid !=
2139 NL80211_HIDDEN_SSID_ZERO_LEN &&
2140 params.hidden_ssid !=
2141 NL80211_HIDDEN_SSID_ZERO_CONTENTS)
2142 return -EINVAL;
2143 }
2144
2145 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
2146
2147 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
2148 params.auth_type = nla_get_u32(
2149 info->attrs[NL80211_ATTR_AUTH_TYPE]);
2150 if (!nl80211_valid_auth_type(params.auth_type))
2151 return -EINVAL;
2152 } else
2153 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
2154
2155 err = nl80211_crypto_settings(rdev, info, &params.crypto,
2156 NL80211_MAX_NR_CIPHER_SUITES);
2157 if (err)
2158 return err;
2159
2160 call = rdev->ops->add_beacon;
2161 break;
2162 case NL80211_CMD_SET_BEACON:
2163 call = rdev->ops->set_beacon;
2164 break;
2165 default:
2166 WARN_ON(1);
2167 return -EOPNOTSUPP;
2168 }
2169
2170 if (!call)
2171 return -EOPNOTSUPP;
2172 2090
2173 if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { 2091 if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
2174 params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); 2092 bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
2175 params.head_len = 2093 bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
2176 nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); 2094 if (!bcn->head_len)
2177 haveinfo = 1; 2095 return -EINVAL;
2096 haveinfo = true;
2178 } 2097 }
2179 2098
2180 if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { 2099 if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
2181 params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); 2100 bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
2182 params.tail_len = 2101 bcn->tail_len =
2183 nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); 2102 nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
2184 haveinfo = 1; 2103 haveinfo = true;
2185 } 2104 }
2186 2105
2187 if (!haveinfo) 2106 if (!haveinfo)
2188 return -EINVAL; 2107 return -EINVAL;
2189 2108
2190 if (info->attrs[NL80211_ATTR_IE]) { 2109 if (info->attrs[NL80211_ATTR_IE]) {
2191 params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); 2110 bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
2192 params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); 2111 bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2193 } 2112 }
2194 2113
2195 if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) { 2114 if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
2196 params.proberesp_ies = 2115 bcn->proberesp_ies =
2197 nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); 2116 nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
2198 params.proberesp_ies_len = 2117 bcn->proberesp_ies_len =
2199 nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); 2118 nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
2200 } 2119 }
2201 2120
2202 if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) { 2121 if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
2203 params.assocresp_ies = 2122 bcn->assocresp_ies =
2204 nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); 2123 nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
2205 params.assocresp_ies_len = 2124 bcn->assocresp_ies_len =
2206 nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); 2125 nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
2207 } 2126 }
2208 2127
2209 if (info->attrs[NL80211_ATTR_PROBE_RESP]) { 2128 if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
2210 params.probe_resp = 2129 bcn->probe_resp =
2211 nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); 2130 nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
2212 params.probe_resp_len = 2131 bcn->probe_resp_len =
2213 nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); 2132 nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
2214 } 2133 }
2215 2134
2216 err = call(&rdev->wiphy, dev, &params); 2135 return 0;
2217 if (!err && params.interval) 2136}
2218 wdev->beacon_interval = params.interval; 2137
2138static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2139{
2140 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2141 struct net_device *dev = info->user_ptr[1];
2142 struct wireless_dev *wdev = dev->ieee80211_ptr;
2143 struct cfg80211_ap_settings params;
2144 int err;
2145
2146 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2147 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2148 return -EOPNOTSUPP;
2149
2150 if (!rdev->ops->start_ap)
2151 return -EOPNOTSUPP;
2152
2153 if (wdev->beacon_interval)
2154 return -EALREADY;
2155
2156 memset(&params, 0, sizeof(params));
2157
2158 /* these are required for START_AP */
2159 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
2160 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
2161 !info->attrs[NL80211_ATTR_BEACON_HEAD])
2162 return -EINVAL;
2163
2164 err = nl80211_parse_beacon(info, &params.beacon);
2165 if (err)
2166 return err;
2167
2168 params.beacon_interval =
2169 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
2170 params.dtim_period =
2171 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
2172
2173 err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
2174 if (err)
2175 return err;
2176
2177 /*
2178 * In theory, some of these attributes should be required here
2179 * but since they were not used when the command was originally
2180 * added, keep them optional for old user space programs to let
2181 * them continue to work with drivers that do not need the
2182 * additional information -- drivers must check!
2183 */
2184 if (info->attrs[NL80211_ATTR_SSID]) {
2185 params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2186 params.ssid_len =
2187 nla_len(info->attrs[NL80211_ATTR_SSID]);
2188 if (params.ssid_len == 0 ||
2189 params.ssid_len > IEEE80211_MAX_SSID_LEN)
2190 return -EINVAL;
2191 }
2192
2193 if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
2194 params.hidden_ssid = nla_get_u32(
2195 info->attrs[NL80211_ATTR_HIDDEN_SSID]);
2196 if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
2197 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
2198 params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
2199 return -EINVAL;
2200 }
2201
2202 params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
2203
2204 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
2205 params.auth_type = nla_get_u32(
2206 info->attrs[NL80211_ATTR_AUTH_TYPE]);
2207 if (!nl80211_valid_auth_type(params.auth_type))
2208 return -EINVAL;
2209 } else
2210 params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
2211
2212 err = nl80211_crypto_settings(rdev, info, &params.crypto,
2213 NL80211_MAX_NR_CIPHER_SUITES);
2214 if (err)
2215 return err;
2216
2217 err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
2218 if (!err)
2219 wdev->beacon_interval = params.beacon_interval;
2219 return err; 2220 return err;
2220} 2221}
2221 2222
2222static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) 2223static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
2224{
2225 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2226 struct net_device *dev = info->user_ptr[1];
2227 struct wireless_dev *wdev = dev->ieee80211_ptr;
2228 struct cfg80211_beacon_data params;
2229 int err;
2230
2231 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2232 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2233 return -EOPNOTSUPP;
2234
2235 if (!rdev->ops->change_beacon)
2236 return -EOPNOTSUPP;
2237
2238 if (!wdev->beacon_interval)
2239 return -EINVAL;
2240
2241 err = nl80211_parse_beacon(info, &params);
2242 if (err)
2243 return err;
2244
2245 return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
2246}
2247
2248static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
2223{ 2249{
2224 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 2250 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2225 struct net_device *dev = info->user_ptr[1]; 2251 struct net_device *dev = info->user_ptr[1];
2226 struct wireless_dev *wdev = dev->ieee80211_ptr; 2252 struct wireless_dev *wdev = dev->ieee80211_ptr;
2227 int err; 2253 int err;
2228 2254
2229 if (!rdev->ops->del_beacon) 2255 if (!rdev->ops->stop_ap)
2230 return -EOPNOTSUPP; 2256 return -EOPNOTSUPP;
2231 2257
2232 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2258 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2233 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) 2259 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2234 return -EOPNOTSUPP; 2260 return -EOPNOTSUPP;
2235 2261
2236 err = rdev->ops->del_beacon(&rdev->wiphy, dev); 2262 if (!wdev->beacon_interval)
2263 return -ENOENT;
2264
2265 err = rdev->ops->stop_ap(&rdev->wiphy, dev);
2237 if (!err) 2266 if (!err)
2238 wdev->beacon_interval = 0; 2267 wdev->beacon_interval = 0;
2239 return err; 2268 return err;
@@ -6357,23 +6386,23 @@ static struct genl_ops nl80211_ops[] = {
6357 .cmd = NL80211_CMD_SET_BEACON, 6386 .cmd = NL80211_CMD_SET_BEACON,
6358 .policy = nl80211_policy, 6387 .policy = nl80211_policy,
6359 .flags = GENL_ADMIN_PERM, 6388 .flags = GENL_ADMIN_PERM,
6360 .doit = nl80211_addset_beacon, 6389 .doit = nl80211_set_beacon,
6361 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6390 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6362 NL80211_FLAG_NEED_RTNL, 6391 NL80211_FLAG_NEED_RTNL,
6363 }, 6392 },
6364 { 6393 {
6365 .cmd = NL80211_CMD_NEW_BEACON, 6394 .cmd = NL80211_CMD_START_AP,
6366 .policy = nl80211_policy, 6395 .policy = nl80211_policy,
6367 .flags = GENL_ADMIN_PERM, 6396 .flags = GENL_ADMIN_PERM,
6368 .doit = nl80211_addset_beacon, 6397 .doit = nl80211_start_ap,
6369 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6398 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6370 NL80211_FLAG_NEED_RTNL, 6399 NL80211_FLAG_NEED_RTNL,
6371 }, 6400 },
6372 { 6401 {
6373 .cmd = NL80211_CMD_DEL_BEACON, 6402 .cmd = NL80211_CMD_STOP_AP,
6374 .policy = nl80211_policy, 6403 .policy = nl80211_policy,
6375 .flags = GENL_ADMIN_PERM, 6404 .flags = GENL_ADMIN_PERM,
6376 .doit = nl80211_del_beacon, 6405 .doit = nl80211_stop_ap,
6377 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6406 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6378 NL80211_FLAG_NEED_RTNL, 6407 NL80211_FLAG_NEED_RTNL,
6379 }, 6408 },