diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 216 |
1 files changed, 105 insertions, 111 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3f47276caeb8..52928ad90570 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -74,19 +74,14 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | |||
74 | return 0; | 74 | return 0; |
75 | } | 75 | } |
76 | 76 | ||
77 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | 77 | static int ieee80211_change_iface(struct wiphy *wiphy, |
78 | struct net_device *dev, | ||
78 | enum nl80211_iftype type, u32 *flags, | 79 | enum nl80211_iftype type, u32 *flags, |
79 | struct vif_params *params) | 80 | struct vif_params *params) |
80 | { | 81 | { |
81 | struct net_device *dev; | ||
82 | struct ieee80211_sub_if_data *sdata; | 82 | struct ieee80211_sub_if_data *sdata; |
83 | int ret; | 83 | int ret; |
84 | 84 | ||
85 | /* we're under RTNL */ | ||
86 | dev = __dev_get_by_index(&init_net, ifindex); | ||
87 | if (!dev) | ||
88 | return -ENODEV; | ||
89 | |||
90 | if (!nl80211_type_check(type)) | 85 | if (!nl80211_type_check(type)) |
91 | return -EINVAL; | 86 | return -EINVAL; |
92 | 87 | ||
@@ -1177,123 +1172,29 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1177 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | 1172 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, |
1178 | struct cfg80211_auth_request *req) | 1173 | struct cfg80211_auth_request *req) |
1179 | { | 1174 | { |
1180 | struct ieee80211_sub_if_data *sdata; | 1175 | return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req); |
1181 | |||
1182 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1183 | |||
1184 | switch (req->auth_type) { | ||
1185 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
1186 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN; | ||
1187 | break; | ||
1188 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
1189 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY; | ||
1190 | break; | ||
1191 | case NL80211_AUTHTYPE_FT: | ||
1192 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT; | ||
1193 | break; | ||
1194 | case NL80211_AUTHTYPE_NETWORK_EAP: | ||
1195 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP; | ||
1196 | break; | ||
1197 | default: | ||
1198 | return -EOPNOTSUPP; | ||
1199 | } | ||
1200 | |||
1201 | memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); | ||
1202 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | ||
1203 | sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; | ||
1204 | |||
1205 | /* TODO: req->chan */ | ||
1206 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; | ||
1207 | |||
1208 | if (req->ssid) { | ||
1209 | sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; | ||
1210 | memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); | ||
1211 | sdata->u.mgd.ssid_len = req->ssid_len; | ||
1212 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | ||
1213 | } | ||
1214 | |||
1215 | kfree(sdata->u.mgd.sme_auth_ie); | ||
1216 | sdata->u.mgd.sme_auth_ie = NULL; | ||
1217 | sdata->u.mgd.sme_auth_ie_len = 0; | ||
1218 | if (req->ie) { | ||
1219 | sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL); | ||
1220 | if (sdata->u.mgd.sme_auth_ie == NULL) | ||
1221 | return -ENOMEM; | ||
1222 | memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len); | ||
1223 | sdata->u.mgd.sme_auth_ie_len = req->ie_len; | ||
1224 | } | ||
1225 | |||
1226 | sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; | ||
1227 | sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
1228 | ieee80211_sta_req_auth(sdata); | ||
1229 | return 0; | ||
1230 | } | 1176 | } |
1231 | 1177 | ||
1232 | static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | 1178 | static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, |
1233 | struct cfg80211_assoc_request *req) | 1179 | struct cfg80211_assoc_request *req) |
1234 | { | 1180 | { |
1235 | struct ieee80211_sub_if_data *sdata; | 1181 | return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); |
1236 | int ret; | ||
1237 | |||
1238 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1239 | |||
1240 | if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 || | ||
1241 | !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) | ||
1242 | return -ENOLINK; /* not authenticated */ | ||
1243 | |||
1244 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | ||
1245 | sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; | ||
1246 | |||
1247 | /* TODO: req->chan */ | ||
1248 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; | ||
1249 | |||
1250 | if (req->ssid) { | ||
1251 | sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; | ||
1252 | memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); | ||
1253 | sdata->u.mgd.ssid_len = req->ssid_len; | ||
1254 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | ||
1255 | } else | ||
1256 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; | ||
1257 | |||
1258 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); | ||
1259 | if (ret && ret != -EALREADY) | ||
1260 | return ret; | ||
1261 | |||
1262 | if (req->use_mfp) { | ||
1263 | sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; | ||
1264 | sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; | ||
1265 | } else { | ||
1266 | sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; | ||
1267 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; | ||
1268 | } | ||
1269 | |||
1270 | if (req->control_port) | ||
1271 | sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; | ||
1272 | else | ||
1273 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; | ||
1274 | |||
1275 | sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; | ||
1276 | sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; | ||
1277 | ieee80211_sta_req_auth(sdata); | ||
1278 | return 0; | ||
1279 | } | 1182 | } |
1280 | 1183 | ||
1281 | static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, | 1184 | static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, |
1282 | struct cfg80211_deauth_request *req) | 1185 | struct cfg80211_deauth_request *req, |
1186 | void *cookie) | ||
1283 | { | 1187 | { |
1284 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1188 | return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), |
1285 | 1189 | req, cookie); | |
1286 | /* TODO: req->ie, req->peer_addr */ | ||
1287 | return ieee80211_sta_deauthenticate(sdata, req->reason_code); | ||
1288 | } | 1190 | } |
1289 | 1191 | ||
1290 | static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, | 1192 | static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, |
1291 | struct cfg80211_disassoc_request *req) | 1193 | struct cfg80211_disassoc_request *req, |
1194 | void *cookie) | ||
1292 | { | 1195 | { |
1293 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1196 | return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), |
1294 | 1197 | req, cookie); | |
1295 | /* TODO: req->ie, req->peer_addr */ | ||
1296 | return ieee80211_sta_disassociate(sdata, req->reason_code); | ||
1297 | } | 1198 | } |
1298 | 1199 | ||
1299 | static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | 1200 | static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, |
@@ -1374,6 +1275,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) | |||
1374 | return 0; | 1275 | return 0; |
1375 | } | 1276 | } |
1376 | 1277 | ||
1278 | static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, | ||
1279 | u8 *addr) | ||
1280 | { | ||
1281 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1282 | |||
1283 | memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN); | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1377 | static void ieee80211_rfkill_poll(struct wiphy *wiphy) | 1288 | static void ieee80211_rfkill_poll(struct wiphy *wiphy) |
1378 | { | 1289 | { |
1379 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1290 | struct ieee80211_local *local = wiphy_priv(wiphy); |
@@ -1381,6 +1292,85 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy) | |||
1381 | drv_rfkill_poll(local); | 1292 | drv_rfkill_poll(local); |
1382 | } | 1293 | } |
1383 | 1294 | ||
1295 | #ifdef CONFIG_NL80211_TESTMODE | ||
1296 | static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) | ||
1297 | { | ||
1298 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1299 | |||
1300 | if (!local->ops->testmode_cmd) | ||
1301 | return -EOPNOTSUPP; | ||
1302 | |||
1303 | return local->ops->testmode_cmd(&local->hw, data, len); | ||
1304 | } | ||
1305 | #endif | ||
1306 | |||
1307 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||
1308 | bool enabled, int timeout) | ||
1309 | { | ||
1310 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1311 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1312 | struct ieee80211_conf *conf = &local->hw.conf; | ||
1313 | |||
1314 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
1315 | return -EOPNOTSUPP; | ||
1316 | |||
1317 | if (enabled == sdata->u.mgd.powersave && | ||
1318 | timeout == conf->dynamic_ps_timeout) | ||
1319 | return 0; | ||
1320 | |||
1321 | sdata->u.mgd.powersave = enabled; | ||
1322 | conf->dynamic_ps_timeout = timeout; | ||
1323 | |||
1324 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
1325 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
1326 | |||
1327 | ieee80211_recalc_ps(local, -1); | ||
1328 | |||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | ||
1333 | struct net_device *dev, | ||
1334 | const u8 *addr, | ||
1335 | const struct cfg80211_bitrate_mask *mask) | ||
1336 | { | ||
1337 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1338 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1339 | int i, err = -EINVAL; | ||
1340 | u32 target_rate; | ||
1341 | struct ieee80211_supported_band *sband; | ||
1342 | |||
1343 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1344 | |||
1345 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
1346 | * target_rate = X, rate->fixed = 1 means only rate X | ||
1347 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | ||
1348 | sdata->max_ratectrl_rateidx = -1; | ||
1349 | sdata->force_unicast_rateidx = -1; | ||
1350 | |||
1351 | if (mask->fixed) | ||
1352 | target_rate = mask->fixed / 100; | ||
1353 | else if (mask->maxrate) | ||
1354 | target_rate = mask->maxrate / 100; | ||
1355 | else | ||
1356 | return 0; | ||
1357 | |||
1358 | for (i=0; i< sband->n_bitrates; i++) { | ||
1359 | struct ieee80211_rate *brate = &sband->bitrates[i]; | ||
1360 | int this_rate = brate->bitrate; | ||
1361 | |||
1362 | if (target_rate == this_rate) { | ||
1363 | sdata->max_ratectrl_rateidx = i; | ||
1364 | if (mask->fixed) | ||
1365 | sdata->force_unicast_rateidx = i; | ||
1366 | err = 0; | ||
1367 | break; | ||
1368 | } | ||
1369 | } | ||
1370 | |||
1371 | return err; | ||
1372 | } | ||
1373 | |||
1384 | struct cfg80211_ops mac80211_config_ops = { | 1374 | struct cfg80211_ops mac80211_config_ops = { |
1385 | .add_virtual_intf = ieee80211_add_iface, | 1375 | .add_virtual_intf = ieee80211_add_iface, |
1386 | .del_virtual_intf = ieee80211_del_iface, | 1376 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1422,5 +1412,9 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1422 | .set_wiphy_params = ieee80211_set_wiphy_params, | 1412 | .set_wiphy_params = ieee80211_set_wiphy_params, |
1423 | .set_tx_power = ieee80211_set_tx_power, | 1413 | .set_tx_power = ieee80211_set_tx_power, |
1424 | .get_tx_power = ieee80211_get_tx_power, | 1414 | .get_tx_power = ieee80211_get_tx_power, |
1415 | .set_wds_peer = ieee80211_set_wds_peer, | ||
1425 | .rfkill_poll = ieee80211_rfkill_poll, | 1416 | .rfkill_poll = ieee80211_rfkill_poll, |
1417 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) | ||
1418 | .set_power_mgmt = ieee80211_set_power_mgmt, | ||
1419 | .set_bitrate_mask = ieee80211_set_bitrate_mask, | ||
1426 | }; | 1420 | }; |