diff options
| -rw-r--r-- | include/linux/nl80211.h | 93 | ||||
| -rw-r--r-- | include/net/cfg80211.h | 56 | ||||
| -rw-r--r-- | net/mac80211/cfg.c | 12 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 6 | ||||
| -rw-r--r-- | net/mac80211/main.c | 37 | ||||
| -rw-r--r-- | net/mac80211/rx.c | 137 | ||||
| -rw-r--r-- | net/mac80211/status.c | 2 | ||||
| -rw-r--r-- | net/mac80211/util.c | 6 | ||||
| -rw-r--r-- | net/wireless/core.c | 8 | ||||
| -rw-r--r-- | net/wireless/core.h | 21 | ||||
| -rw-r--r-- | net/wireless/mlme.c | 144 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 108 | ||||
| -rw-r--r-- | net/wireless/nl80211.h | 14 | ||||
| -rw-r--r-- | net/wireless/util.c | 2 |
15 files changed, 452 insertions, 195 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2c8701687336..8af1e66c3cf9 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
| @@ -40,6 +40,43 @@ | |||
| 40 | */ | 40 | */ |
| 41 | 41 | ||
| 42 | /** | 42 | /** |
| 43 | * DOC: Frame transmission/registration support | ||
| 44 | * | ||
| 45 | * Frame transmission and registration support exists to allow userspace | ||
| 46 | * management entities such as wpa_supplicant react to management frames | ||
| 47 | * that are not being handled by the kernel. This includes, for example, | ||
| 48 | * certain classes of action frames that cannot be handled in the kernel | ||
| 49 | * for various reasons. | ||
| 50 | * | ||
| 51 | * Frame registration is done on a per-interface basis and registrations | ||
| 52 | * cannot be removed other than by closing the socket. It is possible to | ||
| 53 | * specify a registration filter to register, for example, only for a | ||
| 54 | * certain type of action frame. In particular with action frames, those | ||
| 55 | * that userspace registers for will not be returned as unhandled by the | ||
| 56 | * driver, so that the registered application has to take responsibility | ||
| 57 | * for doing that. | ||
| 58 | * | ||
| 59 | * The type of frame that can be registered for is also dependent on the | ||
| 60 | * driver and interface type. The frame types are advertised in wiphy | ||
| 61 | * attributes so applications know what to expect. | ||
| 62 | * | ||
| 63 | * NOTE: When an interface changes type while registrations are active, | ||
| 64 | * these registrations are ignored until the interface type is | ||
| 65 | * changed again. This means that changing the interface type can | ||
| 66 | * lead to a situation that couldn't otherwise be produced, but | ||
| 67 | * any such registrations will be dormant in the sense that they | ||
| 68 | * will not be serviced, i.e. they will not receive any frames. | ||
| 69 | * | ||
| 70 | * Frame transmission allows userspace to send for example the required | ||
| 71 | * responses to action frames. It is subject to some sanity checking, | ||
| 72 | * but many frames can be transmitted. When a frame was transmitted, its | ||
| 73 | * status is indicated to the sending socket. | ||
| 74 | * | ||
| 75 | * For more technical details, see the corresponding command descriptions | ||
| 76 | * below. | ||
| 77 | */ | ||
| 78 | |||
| 79 | /** | ||
| 43 | * enum nl80211_commands - supported nl80211 commands | 80 | * enum nl80211_commands - supported nl80211 commands |
| 44 | * | 81 | * |
| 45 | * @NL80211_CMD_UNSPEC: unspecified command to catch errors | 82 | * @NL80211_CMD_UNSPEC: unspecified command to catch errors |
| @@ -301,16 +338,18 @@ | |||
| 301 | * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface | 338 | * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface |
| 302 | * and @NL80211_ATTR_TX_RATES the set of allowed rates. | 339 | * and @NL80211_ATTR_TX_RATES the set of allowed rates. |
| 303 | * | 340 | * |
| 304 | * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames | 341 | * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames |
| 305 | * (via @NL80211_CMD_ACTION) for processing in userspace. This command | 342 | * (via @NL80211_CMD_FRAME) for processing in userspace. This command |
| 306 | * requires an interface index and a match attribute containing the first | 343 | * requires an interface index, a frame type attribute (optional for |
| 307 | * few bytes of the frame that should match, e.g. a single byte for only | 344 | * backward compatibility reasons, if not given assumes action frames) |
| 308 | * a category match or four bytes for vendor frames including the OUI. | 345 | * and a match attribute containing the first few bytes of the frame |
| 309 | * The registration cannot be dropped, but is removed automatically | 346 | * that should match, e.g. a single byte for only a category match or |
| 310 | * when the netlink socket is closed. Multiple registrations can be made. | 347 | * four bytes for vendor frames including the OUI. The registration |
| 311 | * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This | 348 | * cannot be dropped, but is removed automatically when the netlink |
| 312 | * command is used both as a request to transmit an Action frame and as an | 349 | * socket is closed. Multiple registrations can be made. |
| 313 | * event indicating reception of an Action frame that was not processed in | 350 | * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This |
| 351 | * command is used both as a request to transmit a management frame and | ||
| 352 | * as an event indicating reception of a frame that was not processed in | ||
| 314 | * kernel code, but is for us (i.e., which may need to be processed in a | 353 | * kernel code, but is for us (i.e., which may need to be processed in a |
| 315 | * user space application). %NL80211_ATTR_FRAME is used to specify the | 354 | * user space application). %NL80211_ATTR_FRAME is used to specify the |
| 316 | * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and | 355 | * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and |
| @@ -320,8 +359,8 @@ | |||
| 320 | * operational channel). When called, this operation returns a cookie | 359 | * operational channel). When called, this operation returns a cookie |
| 321 | * (%NL80211_ATTR_COOKIE) that will be included with the TX status event | 360 | * (%NL80211_ATTR_COOKIE) that will be included with the TX status event |
| 322 | * pertaining to the TX request. | 361 | * pertaining to the TX request. |
| 323 | * @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame | 362 | * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame |
| 324 | * transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies | 363 | * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies |
| 325 | * the TX command and %NL80211_ATTR_FRAME includes the contents of the | 364 | * the TX command and %NL80211_ATTR_FRAME includes the contents of the |
| 326 | * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged | 365 | * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged |
| 327 | * the frame. | 366 | * the frame. |
| @@ -429,9 +468,12 @@ enum nl80211_commands { | |||
| 429 | 468 | ||
| 430 | NL80211_CMD_SET_TX_BITRATE_MASK, | 469 | NL80211_CMD_SET_TX_BITRATE_MASK, |
| 431 | 470 | ||
| 432 | NL80211_CMD_REGISTER_ACTION, | 471 | NL80211_CMD_REGISTER_FRAME, |
| 433 | NL80211_CMD_ACTION, | 472 | NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME, |
| 434 | NL80211_CMD_ACTION_TX_STATUS, | 473 | NL80211_CMD_FRAME, |
| 474 | NL80211_CMD_ACTION = NL80211_CMD_FRAME, | ||
| 475 | NL80211_CMD_FRAME_TX_STATUS, | ||
| 476 | NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS, | ||
| 435 | 477 | ||
| 436 | NL80211_CMD_SET_POWER_SAVE, | 478 | NL80211_CMD_SET_POWER_SAVE, |
| 437 | NL80211_CMD_GET_POWER_SAVE, | 479 | NL80211_CMD_GET_POWER_SAVE, |
| @@ -708,7 +750,16 @@ enum nl80211_commands { | |||
| 708 | * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. | 750 | * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. |
| 709 | * | 751 | * |
| 710 | * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain | 752 | * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain |
| 711 | * at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION. | 753 | * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. |
| 754 | * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the | ||
| 755 | * @NL80211_CMD_REGISTER_FRAME command. | ||
| 756 | * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a | ||
| 757 | * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing | ||
| 758 | * information about which frame types can be transmitted with | ||
| 759 | * %NL80211_CMD_FRAME. | ||
| 760 | * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a | ||
| 761 | * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing | ||
| 762 | * information about which frame types can be registered for RX. | ||
| 712 | * | 763 | * |
| 713 | * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was | 764 | * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was |
| 714 | * acknowledged by the recipient. | 765 | * acknowledged by the recipient. |
| @@ -891,6 +942,10 @@ enum nl80211_attrs { | |||
| 891 | NL80211_ATTR_WIPHY_TX_POWER_SETTING, | 942 | NL80211_ATTR_WIPHY_TX_POWER_SETTING, |
| 892 | NL80211_ATTR_WIPHY_TX_POWER_LEVEL, | 943 | NL80211_ATTR_WIPHY_TX_POWER_LEVEL, |
| 893 | 944 | ||
| 945 | NL80211_ATTR_TX_FRAME_TYPES, | ||
| 946 | NL80211_ATTR_RX_FRAME_TYPES, | ||
| 947 | NL80211_ATTR_FRAME_TYPE, | ||
| 948 | |||
| 894 | /* add attributes here, update the policy in nl80211.c */ | 949 | /* add attributes here, update the policy in nl80211.c */ |
| 895 | 950 | ||
| 896 | __NL80211_ATTR_AFTER_LAST, | 951 | __NL80211_ATTR_AFTER_LAST, |
| @@ -947,7 +1002,7 @@ enum nl80211_attrs { | |||
| 947 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames | 1002 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames |
| 948 | * @NL80211_IFTYPE_MESH_POINT: mesh point | 1003 | * @NL80211_IFTYPE_MESH_POINT: mesh point |
| 949 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 1004 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
| 950 | * @__NL80211_IFTYPE_AFTER_LAST: internal use | 1005 | * @NUM_NL80211_IFTYPES: number of defined interface types |
| 951 | * | 1006 | * |
| 952 | * These values are used with the %NL80211_ATTR_IFTYPE | 1007 | * These values are used with the %NL80211_ATTR_IFTYPE |
| 953 | * to set the type of an interface. | 1008 | * to set the type of an interface. |
| @@ -964,8 +1019,8 @@ enum nl80211_iftype { | |||
| 964 | NL80211_IFTYPE_MESH_POINT, | 1019 | NL80211_IFTYPE_MESH_POINT, |
| 965 | 1020 | ||
| 966 | /* keep last */ | 1021 | /* keep last */ |
| 967 | __NL80211_IFTYPE_AFTER_LAST, | 1022 | NUM_NL80211_IFTYPES, |
| 968 | NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 | 1023 | NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1 |
| 969 | }; | 1024 | }; |
| 970 | 1025 | ||
| 971 | /** | 1026 | /** |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2b403c7ee32e..6a98b1b3bfde 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
| @@ -1020,7 +1020,7 @@ struct cfg80211_pmksa { | |||
| 1020 | * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. | 1020 | * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. |
| 1021 | * This allows the operation to be terminated prior to timeout based on | 1021 | * This allows the operation to be terminated prior to timeout based on |
| 1022 | * the duration value. | 1022 | * the duration value. |
| 1023 | * @action: Transmit an action frame | 1023 | * @mgmt_tx: Transmit a management frame |
| 1024 | * | 1024 | * |
| 1025 | * @testmode_cmd: run a test mode command | 1025 | * @testmode_cmd: run a test mode command |
| 1026 | * | 1026 | * |
| @@ -1172,7 +1172,7 @@ struct cfg80211_ops { | |||
| 1172 | struct net_device *dev, | 1172 | struct net_device *dev, |
| 1173 | u64 cookie); | 1173 | u64 cookie); |
| 1174 | 1174 | ||
| 1175 | int (*action)(struct wiphy *wiphy, struct net_device *dev, | 1175 | int (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev, |
| 1176 | struct ieee80211_channel *chan, | 1176 | struct ieee80211_channel *chan, |
| 1177 | enum nl80211_channel_type channel_type, | 1177 | enum nl80211_channel_type channel_type, |
| 1178 | bool channel_type_valid, | 1178 | bool channel_type_valid, |
| @@ -1236,6 +1236,10 @@ struct mac_address { | |||
| 1236 | u8 addr[ETH_ALEN]; | 1236 | u8 addr[ETH_ALEN]; |
| 1237 | }; | 1237 | }; |
| 1238 | 1238 | ||
| 1239 | struct ieee80211_txrx_stypes { | ||
| 1240 | u16 tx, rx; | ||
| 1241 | }; | ||
| 1242 | |||
| 1239 | /** | 1243 | /** |
| 1240 | * struct wiphy - wireless hardware description | 1244 | * struct wiphy - wireless hardware description |
| 1241 | * @reg_notifier: the driver's regulatory notification callback | 1245 | * @reg_notifier: the driver's regulatory notification callback |
| @@ -1286,6 +1290,10 @@ struct mac_address { | |||
| 1286 | * @privid: a pointer that drivers can use to identify if an arbitrary | 1290 | * @privid: a pointer that drivers can use to identify if an arbitrary |
| 1287 | * wiphy is theirs, e.g. in global notifiers | 1291 | * wiphy is theirs, e.g. in global notifiers |
| 1288 | * @bands: information about bands/channels supported by this device | 1292 | * @bands: information about bands/channels supported by this device |
| 1293 | * | ||
| 1294 | * @mgmt_stypes: bitmasks of frame subtypes that can be subscribed to or | ||
| 1295 | * transmitted through nl80211, points to an array indexed by interface | ||
| 1296 | * type | ||
| 1289 | */ | 1297 | */ |
| 1290 | struct wiphy { | 1298 | struct wiphy { |
| 1291 | /* assign these fields before you register the wiphy */ | 1299 | /* assign these fields before you register the wiphy */ |
| @@ -1294,9 +1302,12 @@ struct wiphy { | |||
| 1294 | u8 perm_addr[ETH_ALEN]; | 1302 | u8 perm_addr[ETH_ALEN]; |
| 1295 | u8 addr_mask[ETH_ALEN]; | 1303 | u8 addr_mask[ETH_ALEN]; |
| 1296 | 1304 | ||
| 1297 | u16 n_addresses; | ||
| 1298 | struct mac_address *addresses; | 1305 | struct mac_address *addresses; |
| 1299 | 1306 | ||
| 1307 | const struct ieee80211_txrx_stypes *mgmt_stypes; | ||
| 1308 | |||
| 1309 | u16 n_addresses; | ||
| 1310 | |||
| 1300 | /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ | 1311 | /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ |
| 1301 | u16 interface_modes; | 1312 | u16 interface_modes; |
| 1302 | 1313 | ||
| @@ -1492,8 +1503,8 @@ struct cfg80211_cached_keys; | |||
| 1492 | * set by driver (if supported) on add_interface BEFORE registering the | 1503 | * set by driver (if supported) on add_interface BEFORE registering the |
| 1493 | * netdev and may otherwise be used by driver read-only, will be update | 1504 | * netdev and may otherwise be used by driver read-only, will be update |
| 1494 | * by cfg80211 on change_interface | 1505 | * by cfg80211 on change_interface |
| 1495 | * @action_registrations: list of registrations for action frames | 1506 | * @mgmt_registrations: list of registrations for management frames |
| 1496 | * @action_registrations_lock: lock for the list | 1507 | * @mgmt_registrations_lock: lock for the list |
| 1497 | * @mtx: mutex used to lock data in this struct | 1508 | * @mtx: mutex used to lock data in this struct |
| 1498 | * @cleanup_work: work struct used for cleanup that can't be done directly | 1509 | * @cleanup_work: work struct used for cleanup that can't be done directly |
| 1499 | */ | 1510 | */ |
| @@ -1505,8 +1516,8 @@ struct wireless_dev { | |||
| 1505 | struct list_head list; | 1516 | struct list_head list; |
| 1506 | struct net_device *netdev; | 1517 | struct net_device *netdev; |
| 1507 | 1518 | ||
| 1508 | struct list_head action_registrations; | 1519 | struct list_head mgmt_registrations; |
| 1509 | spinlock_t action_registrations_lock; | 1520 | spinlock_t mgmt_registrations_lock; |
| 1510 | 1521 | ||
| 1511 | struct mutex mtx; | 1522 | struct mutex mtx; |
| 1512 | 1523 | ||
| @@ -2373,38 +2384,39 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
| 2373 | struct station_info *sinfo, gfp_t gfp); | 2384 | struct station_info *sinfo, gfp_t gfp); |
| 2374 | 2385 | ||
| 2375 | /** | 2386 | /** |
| 2376 | * cfg80211_rx_action - notification of received, unprocessed Action frame | 2387 | * cfg80211_rx_mgmt - notification of received, unprocessed management frame |
| 2377 | * @dev: network device | 2388 | * @dev: network device |
| 2378 | * @freq: Frequency on which the frame was received in MHz | 2389 | * @freq: Frequency on which the frame was received in MHz |
| 2379 | * @buf: Action frame (header + body) | 2390 | * @buf: Management frame (header + body) |
| 2380 | * @len: length of the frame data | 2391 | * @len: length of the frame data |
| 2381 | * @gfp: context flags | 2392 | * @gfp: context flags |
| 2382 | * Returns %true if a user space application is responsible for rejecting the | 2393 | * |
| 2383 | * unrecognized Action frame; %false if no such application is registered | 2394 | * Returns %true if a user space application has registered for this frame. |
| 2384 | * (i.e., the driver is responsible for rejecting the unrecognized Action | 2395 | * For action frames, that makes it responsible for rejecting unrecognized |
| 2385 | * frame) | 2396 | * action frames; %false otherwise, in which case for action frames the |
| 2397 | * driver is responsible for rejecting the frame. | ||
| 2386 | * | 2398 | * |
| 2387 | * This function is called whenever an Action frame is received for a station | 2399 | * This function is called whenever an Action frame is received for a station |
| 2388 | * mode interface, but is not processed in kernel. | 2400 | * mode interface, but is not processed in kernel. |
| 2389 | */ | 2401 | */ |
| 2390 | bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, | 2402 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, |
| 2391 | size_t len, gfp_t gfp); | 2403 | size_t len, gfp_t gfp); |
| 2392 | 2404 | ||
| 2393 | /** | 2405 | /** |
| 2394 | * cfg80211_action_tx_status - notification of TX status for Action frame | 2406 | * cfg80211_mgmt_tx_status - notification of TX status for management frame |
| 2395 | * @dev: network device | 2407 | * @dev: network device |
| 2396 | * @cookie: Cookie returned by cfg80211_ops::action() | 2408 | * @cookie: Cookie returned by cfg80211_ops::mgmt_tx() |
| 2397 | * @buf: Action frame (header + body) | 2409 | * @buf: Management frame (header + body) |
| 2398 | * @len: length of the frame data | 2410 | * @len: length of the frame data |
| 2399 | * @ack: Whether frame was acknowledged | 2411 | * @ack: Whether frame was acknowledged |
| 2400 | * @gfp: context flags | 2412 | * @gfp: context flags |
| 2401 | * | 2413 | * |
| 2402 | * This function is called whenever an Action frame was requested to be | 2414 | * This function is called whenever a management frame was requested to be |
| 2403 | * transmitted with cfg80211_ops::action() to report the TX status of the | 2415 | * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the |
| 2404 | * transmission attempt. | 2416 | * transmission attempt. |
| 2405 | */ | 2417 | */ |
| 2406 | void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, | 2418 | void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, |
| 2407 | const u8 *buf, size_t len, bool ack, gfp_t gfp); | 2419 | const u8 *buf, size_t len, bool ack, gfp_t gfp); |
| 2408 | 2420 | ||
| 2409 | 2421 | ||
| 2410 | /** | 2422 | /** |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f9a317766136..94787d21282c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -1521,11 +1521,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
| 1521 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | 1521 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); |
| 1522 | } | 1522 | } |
| 1523 | 1523 | ||
| 1524 | static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, | 1524 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, |
| 1525 | struct ieee80211_channel *chan, | 1525 | struct ieee80211_channel *chan, |
| 1526 | enum nl80211_channel_type channel_type, | 1526 | enum nl80211_channel_type channel_type, |
| 1527 | bool channel_type_valid, | 1527 | bool channel_type_valid, |
| 1528 | const u8 *buf, size_t len, u64 *cookie) | 1528 | const u8 *buf, size_t len, u64 *cookie) |
| 1529 | { | 1529 | { |
| 1530 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1530 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 1531 | struct ieee80211_local *local = sdata->local; | 1531 | struct ieee80211_local *local = sdata->local; |
| @@ -1625,6 +1625,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 1625 | .set_bitrate_mask = ieee80211_set_bitrate_mask, | 1625 | .set_bitrate_mask = ieee80211_set_bitrate_mask, |
| 1626 | .remain_on_channel = ieee80211_remain_on_channel, | 1626 | .remain_on_channel = ieee80211_remain_on_channel, |
| 1627 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | 1627 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, |
| 1628 | .action = ieee80211_action, | 1628 | .mgmt_tx = ieee80211_mgmt_tx, |
| 1629 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, | 1629 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, |
| 1630 | }; | 1630 | }; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1bf05bfd149d..e73ae51dc036 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -170,6 +170,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result; | |||
| 170 | #define IEEE80211_RX_RA_MATCH BIT(1) | 170 | #define IEEE80211_RX_RA_MATCH BIT(1) |
| 171 | #define IEEE80211_RX_AMSDU BIT(2) | 171 | #define IEEE80211_RX_AMSDU BIT(2) |
| 172 | #define IEEE80211_RX_FRAGMENTED BIT(3) | 172 | #define IEEE80211_RX_FRAGMENTED BIT(3) |
| 173 | #define IEEE80211_MALFORMED_ACTION_FRM BIT(4) | ||
| 173 | /* only add flags here that do not change with subframes of an aMPDU */ | 174 | /* only add flags here that do not change with subframes of an aMPDU */ |
| 174 | 175 | ||
| 175 | struct ieee80211_rx_data { | 176 | struct ieee80211_rx_data { |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9459aeee0ddc..86f434f234ae 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -177,7 +177,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 177 | /* no special treatment */ | 177 | /* no special treatment */ |
| 178 | break; | 178 | break; |
| 179 | case NL80211_IFTYPE_UNSPECIFIED: | 179 | case NL80211_IFTYPE_UNSPECIFIED: |
| 180 | case __NL80211_IFTYPE_AFTER_LAST: | 180 | case NUM_NL80211_IFTYPES: |
| 181 | /* cannot happen */ | 181 | /* cannot happen */ |
| 182 | WARN_ON(1); | 182 | WARN_ON(1); |
| 183 | break; | 183 | break; |
| @@ -634,7 +634,7 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
| 634 | case NL80211_IFTYPE_MONITOR: | 634 | case NL80211_IFTYPE_MONITOR: |
| 635 | break; | 635 | break; |
| 636 | case NL80211_IFTYPE_UNSPECIFIED: | 636 | case NL80211_IFTYPE_UNSPECIFIED: |
| 637 | case __NL80211_IFTYPE_AFTER_LAST: | 637 | case NUM_NL80211_IFTYPES: |
| 638 | BUG(); | 638 | BUG(); |
| 639 | break; | 639 | break; |
| 640 | } | 640 | } |
| @@ -886,7 +886,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
| 886 | case NL80211_IFTYPE_AP_VLAN: | 886 | case NL80211_IFTYPE_AP_VLAN: |
| 887 | break; | 887 | break; |
| 888 | case NL80211_IFTYPE_UNSPECIFIED: | 888 | case NL80211_IFTYPE_UNSPECIFIED: |
| 889 | case __NL80211_IFTYPE_AFTER_LAST: | 889 | case NUM_NL80211_IFTYPES: |
| 890 | BUG(); | 890 | BUG(); |
| 891 | break; | 891 | break; |
| 892 | } | 892 | } |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0afccda42a24..a53feac4618c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -417,6 +417,41 @@ void ieee80211_napi_complete(struct ieee80211_hw *hw) | |||
| 417 | } | 417 | } |
| 418 | EXPORT_SYMBOL(ieee80211_napi_complete); | 418 | EXPORT_SYMBOL(ieee80211_napi_complete); |
| 419 | 419 | ||
| 420 | /* There isn't a lot of sense in it, but you can transmit anything you like */ | ||
| 421 | static const struct ieee80211_txrx_stypes | ||
| 422 | ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||
| 423 | [NL80211_IFTYPE_ADHOC] = { | ||
| 424 | .tx = 0xffff, | ||
| 425 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4), | ||
| 426 | }, | ||
| 427 | [NL80211_IFTYPE_STATION] = { | ||
| 428 | .tx = 0xffff, | ||
| 429 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
| 430 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4), | ||
| 431 | }, | ||
| 432 | [NL80211_IFTYPE_AP] = { | ||
| 433 | .tx = 0xffff, | ||
| 434 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
| 435 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
| 436 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
| 437 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
| 438 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
| 439 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
| 440 | BIT(IEEE80211_STYPE_ACTION >> 4), | ||
| 441 | }, | ||
| 442 | [NL80211_IFTYPE_AP_VLAN] = { | ||
| 443 | /* copy AP */ | ||
| 444 | .tx = 0xffff, | ||
| 445 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
| 446 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
| 447 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
| 448 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
| 449 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
| 450 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
| 451 | BIT(IEEE80211_STYPE_ACTION >> 4), | ||
| 452 | }, | ||
| 453 | }; | ||
| 454 | |||
| 420 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 455 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
| 421 | const struct ieee80211_ops *ops) | 456 | const struct ieee80211_ops *ops) |
| 422 | { | 457 | { |
| @@ -446,6 +481,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 446 | if (!wiphy) | 481 | if (!wiphy) |
| 447 | return NULL; | 482 | return NULL; |
| 448 | 483 | ||
| 484 | wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; | ||
| 485 | |||
| 449 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | | 486 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
| 450 | WIPHY_FLAG_4ADDR_AP | | 487 | WIPHY_FLAG_4ADDR_AP | |
| 451 | WIPHY_FLAG_4ADDR_STATION; | 488 | WIPHY_FLAG_4ADDR_STATION; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4fdbed58ca2f..aa41e382bbb3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -1940,13 +1940,36 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
| 1940 | } | 1940 | } |
| 1941 | 1941 | ||
| 1942 | static ieee80211_rx_result debug_noinline | 1942 | static ieee80211_rx_result debug_noinline |
| 1943 | ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) | ||
| 1944 | { | ||
| 1945 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | ||
| 1946 | |||
| 1947 | /* | ||
| 1948 | * From here on, look only at management frames. | ||
| 1949 | * Data and control frames are already handled, | ||
| 1950 | * and unknown (reserved) frames are useless. | ||
| 1951 | */ | ||
| 1952 | if (rx->skb->len < 24) | ||
| 1953 | return RX_DROP_MONITOR; | ||
| 1954 | |||
| 1955 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | ||
| 1956 | return RX_DROP_MONITOR; | ||
| 1957 | |||
| 1958 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | ||
| 1959 | return RX_DROP_MONITOR; | ||
| 1960 | |||
| 1961 | if (ieee80211_drop_unencrypted_mgmt(rx)) | ||
| 1962 | return RX_DROP_UNUSABLE; | ||
| 1963 | |||
| 1964 | return RX_CONTINUE; | ||
| 1965 | } | ||
| 1966 | |||
| 1967 | static ieee80211_rx_result debug_noinline | ||
| 1943 | ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | 1968 | ieee80211_rx_h_action(struct ieee80211_rx_data *rx) |
| 1944 | { | 1969 | { |
| 1945 | struct ieee80211_local *local = rx->local; | 1970 | struct ieee80211_local *local = rx->local; |
| 1946 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1971 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 1947 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 1972 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
| 1948 | struct sk_buff *nskb; | ||
| 1949 | struct ieee80211_rx_status *status; | ||
| 1950 | int len = rx->skb->len; | 1973 | int len = rx->skb->len; |
| 1951 | 1974 | ||
| 1952 | if (!ieee80211_is_action(mgmt->frame_control)) | 1975 | if (!ieee80211_is_action(mgmt->frame_control)) |
| @@ -1962,9 +1985,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 1962 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1985 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
| 1963 | return RX_DROP_UNUSABLE; | 1986 | return RX_DROP_UNUSABLE; |
| 1964 | 1987 | ||
| 1965 | if (ieee80211_drop_unencrypted_mgmt(rx)) | ||
| 1966 | return RX_DROP_UNUSABLE; | ||
| 1967 | |||
| 1968 | switch (mgmt->u.action.category) { | 1988 | switch (mgmt->u.action.category) { |
| 1969 | case WLAN_CATEGORY_BACK: | 1989 | case WLAN_CATEGORY_BACK: |
| 1970 | /* | 1990 | /* |
| @@ -2055,17 +2075,36 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2055 | goto queue; | 2075 | goto queue; |
| 2056 | } | 2076 | } |
| 2057 | 2077 | ||
| 2078 | return RX_CONTINUE; | ||
| 2079 | |||
| 2058 | invalid: | 2080 | invalid: |
| 2059 | /* | 2081 | rx->flags |= IEEE80211_MALFORMED_ACTION_FRM; |
| 2060 | * For AP mode, hostapd is responsible for handling any action | 2082 | /* will return in the next handlers */ |
| 2061 | * frames that we didn't handle, including returning unknown | 2083 | return RX_CONTINUE; |
| 2062 | * ones. For all other modes we will return them to the sender, | 2084 | |
| 2063 | * setting the 0x80 bit in the action category, as required by | 2085 | handled: |
| 2064 | * 802.11-2007 7.3.1.11. | 2086 | if (rx->sta) |
| 2065 | */ | 2087 | rx->sta->rx_packets++; |
| 2066 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 2088 | dev_kfree_skb(rx->skb); |
| 2067 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 2089 | return RX_QUEUED; |
| 2068 | return RX_DROP_MONITOR; | 2090 | |
| 2091 | queue: | ||
| 2092 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; | ||
| 2093 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
| 2094 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
| 2095 | if (rx->sta) | ||
| 2096 | rx->sta->rx_packets++; | ||
| 2097 | return RX_QUEUED; | ||
| 2098 | } | ||
| 2099 | |||
| 2100 | static ieee80211_rx_result debug_noinline | ||
| 2101 | ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) | ||
| 2102 | { | ||
| 2103 | struct ieee80211_rx_status *status; | ||
| 2104 | |||
| 2105 | /* skip known-bad action frames and return them in the next handler */ | ||
| 2106 | if (rx->flags & IEEE80211_MALFORMED_ACTION_FRM) | ||
| 2107 | return RX_CONTINUE; | ||
| 2069 | 2108 | ||
| 2070 | /* | 2109 | /* |
| 2071 | * Getting here means the kernel doesn't know how to handle | 2110 | * Getting here means the kernel doesn't know how to handle |
| @@ -2075,10 +2114,44 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2075 | */ | 2114 | */ |
| 2076 | status = IEEE80211_SKB_RXCB(rx->skb); | 2115 | status = IEEE80211_SKB_RXCB(rx->skb); |
| 2077 | 2116 | ||
| 2078 | if (cfg80211_rx_action(rx->sdata->dev, status->freq, | 2117 | if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, |
| 2079 | rx->skb->data, rx->skb->len, | 2118 | rx->skb->data, rx->skb->len, |
| 2080 | GFP_ATOMIC)) | 2119 | GFP_ATOMIC)) { |
| 2081 | goto handled; | 2120 | if (rx->sta) |
| 2121 | rx->sta->rx_packets++; | ||
| 2122 | dev_kfree_skb(rx->skb); | ||
| 2123 | return RX_QUEUED; | ||
| 2124 | } | ||
| 2125 | |||
| 2126 | |||
| 2127 | return RX_CONTINUE; | ||
| 2128 | } | ||
| 2129 | |||
| 2130 | static ieee80211_rx_result debug_noinline | ||
| 2131 | ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) | ||
| 2132 | { | ||
| 2133 | struct ieee80211_local *local = rx->local; | ||
| 2134 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | ||
| 2135 | struct sk_buff *nskb; | ||
| 2136 | struct ieee80211_sub_if_data *sdata = rx->sdata; | ||
| 2137 | |||
| 2138 | if (!ieee80211_is_action(mgmt->frame_control)) | ||
| 2139 | return RX_CONTINUE; | ||
| 2140 | |||
| 2141 | /* | ||
| 2142 | * For AP mode, hostapd is responsible for handling any action | ||
| 2143 | * frames that we didn't handle, including returning unknown | ||
| 2144 | * ones. For all other modes we will return them to the sender, | ||
| 2145 | * setting the 0x80 bit in the action category, as required by | ||
| 2146 | * 802.11-2007 7.3.1.11. | ||
| 2147 | * Newer versions of hostapd shall also use the management frame | ||
| 2148 | * registration mechanisms, but older ones still use cooked | ||
| 2149 | * monitor interfaces so push all frames there. | ||
| 2150 | */ | ||
| 2151 | if (!(rx->flags & IEEE80211_MALFORMED_ACTION_FRM) && | ||
| 2152 | (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 2153 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | ||
| 2154 | return RX_DROP_MONITOR; | ||
| 2082 | 2155 | ||
| 2083 | /* do not return rejected action frames */ | 2156 | /* do not return rejected action frames */ |
| 2084 | if (mgmt->u.action.category & 0x80) | 2157 | if (mgmt->u.action.category & 0x80) |
| @@ -2097,20 +2170,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2097 | 2170 | ||
| 2098 | ieee80211_tx_skb(rx->sdata, nskb); | 2171 | ieee80211_tx_skb(rx->sdata, nskb); |
| 2099 | } | 2172 | } |
| 2100 | |||
| 2101 | handled: | ||
| 2102 | if (rx->sta) | ||
| 2103 | rx->sta->rx_packets++; | ||
| 2104 | dev_kfree_skb(rx->skb); | 2173 | dev_kfree_skb(rx->skb); |
| 2105 | return RX_QUEUED; | 2174 | return RX_QUEUED; |
| 2106 | |||
| 2107 | queue: | ||
| 2108 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; | ||
| 2109 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
| 2110 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
| 2111 | if (rx->sta) | ||
| 2112 | rx->sta->rx_packets++; | ||
| 2113 | return RX_QUEUED; | ||
| 2114 | } | 2175 | } |
| 2115 | 2176 | ||
| 2116 | static ieee80211_rx_result debug_noinline | 2177 | static ieee80211_rx_result debug_noinline |
| @@ -2121,15 +2182,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
| 2121 | struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; | 2182 | struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; |
| 2122 | __le16 stype; | 2183 | __le16 stype; |
| 2123 | 2184 | ||
| 2124 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | ||
| 2125 | return RX_DROP_MONITOR; | ||
| 2126 | |||
| 2127 | if (rx->skb->len < 24) | ||
| 2128 | return RX_DROP_MONITOR; | ||
| 2129 | |||
| 2130 | if (ieee80211_drop_unencrypted_mgmt(rx)) | ||
| 2131 | return RX_DROP_UNUSABLE; | ||
| 2132 | |||
| 2133 | rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); | 2185 | rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); |
| 2134 | if (rxs != RX_CONTINUE) | 2186 | if (rxs != RX_CONTINUE) |
| 2135 | return rxs; | 2187 | return rxs; |
| @@ -2374,7 +2426,10 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, | |||
| 2374 | if (res != RX_CONTINUE) | 2426 | if (res != RX_CONTINUE) |
| 2375 | goto rxh_next; | 2427 | goto rxh_next; |
| 2376 | 2428 | ||
| 2429 | CALL_RXH(ieee80211_rx_h_mgmt_check) | ||
| 2377 | CALL_RXH(ieee80211_rx_h_action) | 2430 | CALL_RXH(ieee80211_rx_h_action) |
| 2431 | CALL_RXH(ieee80211_rx_h_userspace_mgmt) | ||
| 2432 | CALL_RXH(ieee80211_rx_h_action_return) | ||
| 2378 | CALL_RXH(ieee80211_rx_h_mgmt) | 2433 | CALL_RXH(ieee80211_rx_h_mgmt) |
| 2379 | 2434 | ||
| 2380 | rxh_next: | 2435 | rxh_next: |
| @@ -2527,7 +2582,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
| 2527 | break; | 2582 | break; |
| 2528 | case NL80211_IFTYPE_MONITOR: | 2583 | case NL80211_IFTYPE_MONITOR: |
| 2529 | case NL80211_IFTYPE_UNSPECIFIED: | 2584 | case NL80211_IFTYPE_UNSPECIFIED: |
| 2530 | case __NL80211_IFTYPE_AFTER_LAST: | 2585 | case NUM_NL80211_IFTYPES: |
| 2531 | /* should never get here */ | 2586 | /* should never get here */ |
| 2532 | WARN_ON(1); | 2587 | WARN_ON(1); |
| 2533 | break; | 2588 | break; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 10caec5ea8fa..67a35841bef0 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -296,7 +296,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) | 298 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) |
| 299 | cfg80211_action_tx_status( | 299 | cfg80211_mgmt_tx_status( |
| 300 | skb->dev, (unsigned long) skb, skb->data, skb->len, | 300 | skb->dev, (unsigned long) skb, skb->data, skb->len, |
| 301 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); | 301 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); |
| 302 | 302 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 748387d45bc0..cd2b485fed4f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -471,7 +471,7 @@ void ieee80211_iterate_active_interfaces( | |||
| 471 | 471 | ||
| 472 | list_for_each_entry(sdata, &local->interfaces, list) { | 472 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 473 | switch (sdata->vif.type) { | 473 | switch (sdata->vif.type) { |
| 474 | case __NL80211_IFTYPE_AFTER_LAST: | 474 | case NUM_NL80211_IFTYPES: |
| 475 | case NL80211_IFTYPE_UNSPECIFIED: | 475 | case NL80211_IFTYPE_UNSPECIFIED: |
| 476 | case NL80211_IFTYPE_MONITOR: | 476 | case NL80211_IFTYPE_MONITOR: |
| 477 | case NL80211_IFTYPE_AP_VLAN: | 477 | case NL80211_IFTYPE_AP_VLAN: |
| @@ -505,7 +505,7 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
| 505 | 505 | ||
| 506 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 506 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 507 | switch (sdata->vif.type) { | 507 | switch (sdata->vif.type) { |
| 508 | case __NL80211_IFTYPE_AFTER_LAST: | 508 | case NUM_NL80211_IFTYPES: |
| 509 | case NL80211_IFTYPE_UNSPECIFIED: | 509 | case NL80211_IFTYPE_UNSPECIFIED: |
| 510 | case NL80211_IFTYPE_MONITOR: | 510 | case NL80211_IFTYPE_MONITOR: |
| 511 | case NL80211_IFTYPE_AP_VLAN: | 511 | case NL80211_IFTYPE_AP_VLAN: |
| @@ -1189,7 +1189,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1189 | /* ignore virtual */ | 1189 | /* ignore virtual */ |
| 1190 | break; | 1190 | break; |
| 1191 | case NL80211_IFTYPE_UNSPECIFIED: | 1191 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1192 | case __NL80211_IFTYPE_AFTER_LAST: | 1192 | case NUM_NL80211_IFTYPES: |
| 1193 | WARN_ON(1); | 1193 | WARN_ON(1); |
| 1194 | break; | 1194 | break; |
| 1195 | } | 1195 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index c70909c3eae4..d52630bbab04 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -433,7 +433,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 433 | 433 | ||
| 434 | /* sanity check ifmodes */ | 434 | /* sanity check ifmodes */ |
| 435 | WARN_ON(!ifmodes); | 435 | WARN_ON(!ifmodes); |
| 436 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 436 | ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1; |
| 437 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 437 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
| 438 | wiphy->interface_modes = ifmodes; | 438 | wiphy->interface_modes = ifmodes; |
| 439 | 439 | ||
| @@ -685,8 +685,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
| 685 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | 685 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); |
| 686 | INIT_LIST_HEAD(&wdev->event_list); | 686 | INIT_LIST_HEAD(&wdev->event_list); |
| 687 | spin_lock_init(&wdev->event_lock); | 687 | spin_lock_init(&wdev->event_lock); |
| 688 | INIT_LIST_HEAD(&wdev->action_registrations); | 688 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
| 689 | spin_lock_init(&wdev->action_registrations_lock); | 689 | spin_lock_init(&wdev->mgmt_registrations_lock); |
| 690 | 690 | ||
| 691 | mutex_lock(&rdev->devlist_mtx); | 691 | mutex_lock(&rdev->devlist_mtx); |
| 692 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 692 | list_add_rcu(&wdev->list, &rdev->netdev_list); |
| @@ -806,7 +806,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
| 806 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 806 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
| 807 | list_del_rcu(&wdev->list); | 807 | list_del_rcu(&wdev->list); |
| 808 | rdev->devlist_generation++; | 808 | rdev->devlist_generation++; |
| 809 | cfg80211_mlme_purge_actions(wdev); | 809 | cfg80211_mlme_purge_registrations(wdev); |
| 810 | #ifdef CONFIG_CFG80211_WEXT | 810 | #ifdef CONFIG_CFG80211_WEXT |
| 811 | kfree(wdev->wext.keys); | 811 | kfree(wdev->wext.keys); |
| 812 | #endif | 812 | #endif |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 63d57ae399c3..58ab2c791d28 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -331,16 +331,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
| 331 | const u8 *resp_ie, size_t resp_ie_len, | 331 | const u8 *resp_ie, size_t resp_ie_len, |
| 332 | u16 status, bool wextev, | 332 | u16 status, bool wextev, |
| 333 | struct cfg80211_bss *bss); | 333 | struct cfg80211_bss *bss); |
| 334 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 334 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
| 335 | const u8 *match_data, int match_len); | 335 | u16 frame_type, const u8 *match_data, |
| 336 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); | 336 | int match_len); |
| 337 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); | 337 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); |
| 338 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 338 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
| 339 | struct net_device *dev, | 339 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 340 | struct ieee80211_channel *chan, | 340 | struct net_device *dev, |
| 341 | enum nl80211_channel_type channel_type, | 341 | struct ieee80211_channel *chan, |
| 342 | bool channel_type_valid, | 342 | enum nl80211_channel_type channel_type, |
| 343 | const u8 *buf, size_t len, u64 *cookie); | 343 | bool channel_type_valid, |
| 344 | const u8 *buf, size_t len, u64 *cookie); | ||
| 344 | 345 | ||
| 345 | /* SME */ | 346 | /* SME */ |
| 346 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 347 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index ee0af32ed59e..8515b1e5c578 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
| @@ -748,31 +748,51 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
| 748 | } | 748 | } |
| 749 | EXPORT_SYMBOL(cfg80211_new_sta); | 749 | EXPORT_SYMBOL(cfg80211_new_sta); |
| 750 | 750 | ||
| 751 | struct cfg80211_action_registration { | 751 | struct cfg80211_mgmt_registration { |
| 752 | struct list_head list; | 752 | struct list_head list; |
| 753 | 753 | ||
| 754 | u32 nlpid; | 754 | u32 nlpid; |
| 755 | 755 | ||
| 756 | int match_len; | 756 | int match_len; |
| 757 | 757 | ||
| 758 | __le16 frame_type; | ||
| 759 | |||
| 758 | u8 match[]; | 760 | u8 match[]; |
| 759 | }; | 761 | }; |
| 760 | 762 | ||
| 761 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 763 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
| 762 | const u8 *match_data, int match_len) | 764 | u16 frame_type, const u8 *match_data, |
| 765 | int match_len) | ||
| 763 | { | 766 | { |
| 764 | struct cfg80211_action_registration *reg, *nreg; | 767 | struct cfg80211_mgmt_registration *reg, *nreg; |
| 765 | int err = 0; | 768 | int err = 0; |
| 769 | u16 mgmt_type; | ||
| 770 | |||
| 771 | if (!wdev->wiphy->mgmt_stypes) | ||
| 772 | return -EOPNOTSUPP; | ||
| 773 | |||
| 774 | if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) | ||
| 775 | return -EINVAL; | ||
| 776 | |||
| 777 | if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) | ||
| 778 | return -EINVAL; | ||
| 779 | |||
| 780 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | ||
| 781 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) | ||
| 782 | return -EINVAL; | ||
| 766 | 783 | ||
| 767 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); | 784 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); |
| 768 | if (!nreg) | 785 | if (!nreg) |
| 769 | return -ENOMEM; | 786 | return -ENOMEM; |
| 770 | 787 | ||
| 771 | spin_lock_bh(&wdev->action_registrations_lock); | 788 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
| 772 | 789 | ||
| 773 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 790 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { |
| 774 | int mlen = min(match_len, reg->match_len); | 791 | int mlen = min(match_len, reg->match_len); |
| 775 | 792 | ||
| 793 | if (frame_type != le16_to_cpu(reg->frame_type)) | ||
| 794 | continue; | ||
| 795 | |||
| 776 | if (memcmp(reg->match, match_data, mlen) == 0) { | 796 | if (memcmp(reg->match, match_data, mlen) == 0) { |
| 777 | err = -EALREADY; | 797 | err = -EALREADY; |
| 778 | break; | 798 | break; |
| @@ -787,62 +807,75 @@ int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | |||
| 787 | memcpy(nreg->match, match_data, match_len); | 807 | memcpy(nreg->match, match_data, match_len); |
| 788 | nreg->match_len = match_len; | 808 | nreg->match_len = match_len; |
| 789 | nreg->nlpid = snd_pid; | 809 | nreg->nlpid = snd_pid; |
| 790 | list_add(&nreg->list, &wdev->action_registrations); | 810 | nreg->frame_type = cpu_to_le16(frame_type); |
| 811 | list_add(&nreg->list, &wdev->mgmt_registrations); | ||
| 791 | 812 | ||
| 792 | out: | 813 | out: |
| 793 | spin_unlock_bh(&wdev->action_registrations_lock); | 814 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 794 | return err; | 815 | return err; |
| 795 | } | 816 | } |
| 796 | 817 | ||
| 797 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) | 818 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) |
| 798 | { | 819 | { |
| 799 | struct cfg80211_action_registration *reg, *tmp; | 820 | struct cfg80211_mgmt_registration *reg, *tmp; |
| 800 | 821 | ||
| 801 | spin_lock_bh(&wdev->action_registrations_lock); | 822 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
| 802 | 823 | ||
| 803 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 824 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
| 804 | if (reg->nlpid == nlpid) { | 825 | if (reg->nlpid == nlpid) { |
| 805 | list_del(®->list); | 826 | list_del(®->list); |
| 806 | kfree(reg); | 827 | kfree(reg); |
| 807 | } | 828 | } |
| 808 | } | 829 | } |
| 809 | 830 | ||
| 810 | spin_unlock_bh(&wdev->action_registrations_lock); | 831 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 811 | } | 832 | } |
| 812 | 833 | ||
| 813 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) | 834 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
| 814 | { | 835 | { |
| 815 | struct cfg80211_action_registration *reg, *tmp; | 836 | struct cfg80211_mgmt_registration *reg, *tmp; |
| 816 | 837 | ||
| 817 | spin_lock_bh(&wdev->action_registrations_lock); | 838 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
| 818 | 839 | ||
| 819 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 840 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
| 820 | list_del(®->list); | 841 | list_del(®->list); |
| 821 | kfree(reg); | 842 | kfree(reg); |
| 822 | } | 843 | } |
| 823 | 844 | ||
| 824 | spin_unlock_bh(&wdev->action_registrations_lock); | 845 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 825 | } | 846 | } |
| 826 | 847 | ||
| 827 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 848 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| 828 | struct net_device *dev, | 849 | struct net_device *dev, |
| 829 | struct ieee80211_channel *chan, | 850 | struct ieee80211_channel *chan, |
| 830 | enum nl80211_channel_type channel_type, | 851 | enum nl80211_channel_type channel_type, |
| 831 | bool channel_type_valid, | 852 | bool channel_type_valid, |
| 832 | const u8 *buf, size_t len, u64 *cookie) | 853 | const u8 *buf, size_t len, u64 *cookie) |
| 833 | { | 854 | { |
| 834 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 855 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 835 | const struct ieee80211_mgmt *mgmt; | 856 | const struct ieee80211_mgmt *mgmt; |
| 857 | u16 stype; | ||
| 858 | |||
| 859 | if (!wdev->wiphy->mgmt_stypes) | ||
| 860 | return -EOPNOTSUPP; | ||
| 836 | 861 | ||
| 837 | if (rdev->ops->action == NULL) | 862 | if (!rdev->ops->mgmt_tx) |
| 838 | return -EOPNOTSUPP; | 863 | return -EOPNOTSUPP; |
| 864 | |||
| 839 | if (len < 24 + 1) | 865 | if (len < 24 + 1) |
| 840 | return -EINVAL; | 866 | return -EINVAL; |
| 841 | 867 | ||
| 842 | mgmt = (const struct ieee80211_mgmt *) buf; | 868 | mgmt = (const struct ieee80211_mgmt *) buf; |
| 843 | if (!ieee80211_is_action(mgmt->frame_control)) | 869 | |
| 870 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | ||
| 844 | return -EINVAL; | 871 | return -EINVAL; |
| 845 | if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | 872 | |
| 873 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; | ||
| 874 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4))) | ||
| 875 | return -EINVAL; | ||
| 876 | |||
| 877 | if (ieee80211_is_action(mgmt->frame_control) && | ||
| 878 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | ||
| 846 | /* Verify that we are associated with the destination AP */ | 879 | /* Verify that we are associated with the destination AP */ |
| 847 | wdev_lock(wdev); | 880 | wdev_lock(wdev); |
| 848 | 881 | ||
| @@ -863,64 +896,75 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | |||
| 863 | return -EINVAL; | 896 | return -EINVAL; |
| 864 | 897 | ||
| 865 | /* Transmit the Action frame as requested by user space */ | 898 | /* Transmit the Action frame as requested by user space */ |
| 866 | return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, | 899 | return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type, |
| 867 | channel_type_valid, buf, len, cookie); | 900 | channel_type_valid, buf, len, cookie); |
| 868 | } | 901 | } |
| 869 | 902 | ||
| 870 | bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, | 903 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, |
| 871 | size_t len, gfp_t gfp) | 904 | size_t len, gfp_t gfp) |
| 872 | { | 905 | { |
| 873 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 906 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 874 | struct wiphy *wiphy = wdev->wiphy; | 907 | struct wiphy *wiphy = wdev->wiphy; |
| 875 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 908 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 876 | struct cfg80211_action_registration *reg; | 909 | struct cfg80211_mgmt_registration *reg; |
| 877 | const u8 *action_data; | 910 | const struct ieee80211_txrx_stypes *stypes = |
| 878 | int action_data_len; | 911 | &wiphy->mgmt_stypes[wdev->iftype]; |
| 912 | struct ieee80211_mgmt *mgmt = (void *)buf; | ||
| 913 | const u8 *data; | ||
| 914 | int data_len; | ||
| 879 | bool result = false; | 915 | bool result = false; |
| 916 | __le16 ftype = mgmt->frame_control & | ||
| 917 | cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); | ||
| 918 | u16 stype; | ||
| 880 | 919 | ||
| 881 | /* frame length - min size excluding category */ | 920 | stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; |
| 882 | action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1); | ||
| 883 | 921 | ||
| 884 | /* action data starts with category */ | 922 | if (!(stypes->rx & BIT(stype))) |
| 885 | action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1; | 923 | return false; |
| 886 | 924 | ||
| 887 | spin_lock_bh(&wdev->action_registrations_lock); | 925 | data = buf + ieee80211_hdrlen(mgmt->frame_control); |
| 926 | data_len = len - ieee80211_hdrlen(mgmt->frame_control); | ||
| 927 | |||
| 928 | spin_lock_bh(&wdev->mgmt_registrations_lock); | ||
| 929 | |||
| 930 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { | ||
| 931 | if (reg->frame_type != ftype) | ||
| 932 | continue; | ||
| 888 | 933 | ||
| 889 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 934 | if (reg->match_len > data_len) |
| 890 | if (reg->match_len > action_data_len) | ||
| 891 | continue; | 935 | continue; |
| 892 | 936 | ||
| 893 | if (memcmp(reg->match, action_data, reg->match_len)) | 937 | if (memcmp(reg->match, data, reg->match_len)) |
| 894 | continue; | 938 | continue; |
| 895 | 939 | ||
| 896 | /* found match! */ | 940 | /* found match! */ |
| 897 | 941 | ||
| 898 | /* Indicate the received Action frame to user space */ | 942 | /* Indicate the received Action frame to user space */ |
| 899 | if (nl80211_send_action(rdev, dev, reg->nlpid, freq, | 943 | if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, |
| 900 | buf, len, gfp)) | 944 | buf, len, gfp)) |
| 901 | continue; | 945 | continue; |
| 902 | 946 | ||
| 903 | result = true; | 947 | result = true; |
| 904 | break; | 948 | break; |
| 905 | } | 949 | } |
| 906 | 950 | ||
| 907 | spin_unlock_bh(&wdev->action_registrations_lock); | 951 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 908 | 952 | ||
| 909 | return result; | 953 | return result; |
| 910 | } | 954 | } |
| 911 | EXPORT_SYMBOL(cfg80211_rx_action); | 955 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
| 912 | 956 | ||
| 913 | void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, | 957 | void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, |
| 914 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | 958 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
| 915 | { | 959 | { |
| 916 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 960 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 917 | struct wiphy *wiphy = wdev->wiphy; | 961 | struct wiphy *wiphy = wdev->wiphy; |
| 918 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 962 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 919 | 963 | ||
| 920 | /* Indicate TX status of the Action frame to user space */ | 964 | /* Indicate TX status of the Action frame to user space */ |
| 921 | nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); | 965 | nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); |
| 922 | } | 966 | } |
| 923 | EXPORT_SYMBOL(cfg80211_action_tx_status); | 967 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
| 924 | 968 | ||
| 925 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | 969 | void cfg80211_cqm_rssi_notify(struct net_device *dev, |
| 926 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 970 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bb5b78eebeb2..927ffbd2aebc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -156,6 +156,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 156 | 156 | ||
| 157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | 157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, |
| 158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | 158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, |
| 159 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | ||
| 159 | }; | 160 | }; |
| 160 | 161 | ||
| 161 | /* policy for the attributes */ | 162 | /* policy for the attributes */ |
| @@ -437,6 +438,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
| 437 | struct ieee80211_rate *rate; | 438 | struct ieee80211_rate *rate; |
| 438 | int i; | 439 | int i; |
| 439 | u16 ifmodes = dev->wiphy.interface_modes; | 440 | u16 ifmodes = dev->wiphy.interface_modes; |
| 441 | const struct ieee80211_txrx_stypes *mgmt_stypes = | ||
| 442 | dev->wiphy.mgmt_stypes; | ||
| 440 | 443 | ||
| 441 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); | 444 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); |
| 442 | if (!hdr) | 445 | if (!hdr) |
| @@ -587,7 +590,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
| 587 | CMD(flush_pmksa, FLUSH_PMKSA); | 590 | CMD(flush_pmksa, FLUSH_PMKSA); |
| 588 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 591 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
| 589 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | 592 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); |
| 590 | CMD(action, ACTION); | 593 | CMD(mgmt_tx, FRAME); |
| 591 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 594 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
| 592 | i++; | 595 | i++; |
| 593 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 596 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
| @@ -608,6 +611,53 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
| 608 | 611 | ||
| 609 | nla_nest_end(msg, nl_cmds); | 612 | nla_nest_end(msg, nl_cmds); |
| 610 | 613 | ||
| 614 | if (mgmt_stypes) { | ||
| 615 | u16 stypes; | ||
| 616 | struct nlattr *nl_ftypes, *nl_ifs; | ||
| 617 | enum nl80211_iftype ift; | ||
| 618 | |||
| 619 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); | ||
| 620 | if (!nl_ifs) | ||
| 621 | goto nla_put_failure; | ||
| 622 | |||
| 623 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
| 624 | nl_ftypes = nla_nest_start(msg, ift); | ||
| 625 | if (!nl_ftypes) | ||
| 626 | goto nla_put_failure; | ||
| 627 | i = 0; | ||
| 628 | stypes = mgmt_stypes[ift].tx; | ||
| 629 | while (stypes) { | ||
| 630 | if (stypes & 1) | ||
| 631 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
| 632 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
| 633 | stypes >>= 1; | ||
| 634 | i++; | ||
| 635 | } | ||
| 636 | nla_nest_end(msg, nl_ftypes); | ||
| 637 | } | ||
| 638 | |||
| 639 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); | ||
| 640 | if (!nl_ifs) | ||
| 641 | goto nla_put_failure; | ||
| 642 | |||
| 643 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
| 644 | nl_ftypes = nla_nest_start(msg, ift); | ||
| 645 | if (!nl_ftypes) | ||
| 646 | goto nla_put_failure; | ||
| 647 | i = 0; | ||
| 648 | stypes = mgmt_stypes[ift].rx; | ||
| 649 | while (stypes) { | ||
| 650 | if (stypes & 1) | ||
| 651 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
| 652 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
| 653 | stypes >>= 1; | ||
| 654 | i++; | ||
| 655 | } | ||
| 656 | nla_nest_end(msg, nl_ftypes); | ||
| 657 | } | ||
| 658 | nla_nest_end(msg, nl_ifs); | ||
| 659 | } | ||
| 660 | |||
| 611 | return genlmsg_end(msg, hdr); | 661 | return genlmsg_end(msg, hdr); |
| 612 | 662 | ||
| 613 | nla_put_failure: | 663 | nla_put_failure: |
| @@ -4732,17 +4782,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
| 4732 | return err; | 4782 | return err; |
| 4733 | } | 4783 | } |
| 4734 | 4784 | ||
| 4735 | static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | 4785 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
| 4736 | { | 4786 | { |
| 4737 | struct cfg80211_registered_device *rdev; | 4787 | struct cfg80211_registered_device *rdev; |
| 4738 | struct net_device *dev; | 4788 | struct net_device *dev; |
| 4789 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | ||
| 4739 | int err; | 4790 | int err; |
| 4740 | 4791 | ||
| 4741 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 4792 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
| 4742 | return -EINVAL; | 4793 | return -EINVAL; |
| 4743 | 4794 | ||
| 4744 | if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) | 4795 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
| 4745 | return -EINVAL; | 4796 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
| 4746 | 4797 | ||
| 4747 | rtnl_lock(); | 4798 | rtnl_lock(); |
| 4748 | 4799 | ||
| @@ -4757,12 +4808,13 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4757 | } | 4808 | } |
| 4758 | 4809 | ||
| 4759 | /* not much point in registering if we can't reply */ | 4810 | /* not much point in registering if we can't reply */ |
| 4760 | if (!rdev->ops->action) { | 4811 | if (!rdev->ops->mgmt_tx) { |
| 4761 | err = -EOPNOTSUPP; | 4812 | err = -EOPNOTSUPP; |
| 4762 | goto out; | 4813 | goto out; |
| 4763 | } | 4814 | } |
| 4764 | 4815 | ||
| 4765 | err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, | 4816 | err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, |
| 4817 | frame_type, | ||
| 4766 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 4818 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
| 4767 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 4819 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
| 4768 | out: | 4820 | out: |
| @@ -4773,7 +4825,7 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4773 | return err; | 4825 | return err; |
| 4774 | } | 4826 | } |
| 4775 | 4827 | ||
| 4776 | static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | 4828 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
| 4777 | { | 4829 | { |
| 4778 | struct cfg80211_registered_device *rdev; | 4830 | struct cfg80211_registered_device *rdev; |
| 4779 | struct net_device *dev; | 4831 | struct net_device *dev; |
| @@ -4796,7 +4848,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4796 | if (err) | 4848 | if (err) |
| 4797 | goto unlock_rtnl; | 4849 | goto unlock_rtnl; |
| 4798 | 4850 | ||
| 4799 | if (!rdev->ops->action) { | 4851 | if (!rdev->ops->mgmt_tx) { |
| 4800 | err = -EOPNOTSUPP; | 4852 | err = -EOPNOTSUPP; |
| 4801 | goto out; | 4853 | goto out; |
| 4802 | } | 4854 | } |
| @@ -4839,17 +4891,17 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4839 | } | 4891 | } |
| 4840 | 4892 | ||
| 4841 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4893 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
| 4842 | NL80211_CMD_ACTION); | 4894 | NL80211_CMD_FRAME); |
| 4843 | 4895 | ||
| 4844 | if (IS_ERR(hdr)) { | 4896 | if (IS_ERR(hdr)) { |
| 4845 | err = PTR_ERR(hdr); | 4897 | err = PTR_ERR(hdr); |
| 4846 | goto free_msg; | 4898 | goto free_msg; |
| 4847 | } | 4899 | } |
| 4848 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, | 4900 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type, |
| 4849 | channel_type_valid, | 4901 | channel_type_valid, |
| 4850 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 4902 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
| 4851 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 4903 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
| 4852 | &cookie); | 4904 | &cookie); |
| 4853 | if (err) | 4905 | if (err) |
| 4854 | goto free_msg; | 4906 | goto free_msg; |
| 4855 | 4907 | ||
| @@ -5348,14 +5400,14 @@ static struct genl_ops nl80211_ops[] = { | |||
| 5348 | .flags = GENL_ADMIN_PERM, | 5400 | .flags = GENL_ADMIN_PERM, |
| 5349 | }, | 5401 | }, |
| 5350 | { | 5402 | { |
| 5351 | .cmd = NL80211_CMD_REGISTER_ACTION, | 5403 | .cmd = NL80211_CMD_REGISTER_FRAME, |
| 5352 | .doit = nl80211_register_action, | 5404 | .doit = nl80211_register_mgmt, |
| 5353 | .policy = nl80211_policy, | 5405 | .policy = nl80211_policy, |
| 5354 | .flags = GENL_ADMIN_PERM, | 5406 | .flags = GENL_ADMIN_PERM, |
| 5355 | }, | 5407 | }, |
| 5356 | { | 5408 | { |
| 5357 | .cmd = NL80211_CMD_ACTION, | 5409 | .cmd = NL80211_CMD_FRAME, |
| 5358 | .doit = nl80211_action, | 5410 | .doit = nl80211_tx_mgmt, |
| 5359 | .policy = nl80211_policy, | 5411 | .policy = nl80211_policy, |
| 5360 | .flags = GENL_ADMIN_PERM, | 5412 | .flags = GENL_ADMIN_PERM, |
| 5361 | }, | 5413 | }, |
| @@ -6055,9 +6107,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
| 6055 | nl80211_mlme_mcgrp.id, gfp); | 6107 | nl80211_mlme_mcgrp.id, gfp); |
| 6056 | } | 6108 | } |
| 6057 | 6109 | ||
| 6058 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 6110 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
| 6059 | struct net_device *netdev, u32 nlpid, | 6111 | struct net_device *netdev, u32 nlpid, |
| 6060 | int freq, const u8 *buf, size_t len, gfp_t gfp) | 6112 | int freq, const u8 *buf, size_t len, gfp_t gfp) |
| 6061 | { | 6113 | { |
| 6062 | struct sk_buff *msg; | 6114 | struct sk_buff *msg; |
| 6063 | void *hdr; | 6115 | void *hdr; |
| @@ -6067,7 +6119,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
| 6067 | if (!msg) | 6119 | if (!msg) |
| 6068 | return -ENOMEM; | 6120 | return -ENOMEM; |
| 6069 | 6121 | ||
| 6070 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); | 6122 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); |
| 6071 | if (!hdr) { | 6123 | if (!hdr) { |
| 6072 | nlmsg_free(msg); | 6124 | nlmsg_free(msg); |
| 6073 | return -ENOMEM; | 6125 | return -ENOMEM; |
| @@ -6095,10 +6147,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
| 6095 | return -ENOBUFS; | 6147 | return -ENOBUFS; |
| 6096 | } | 6148 | } |
| 6097 | 6149 | ||
| 6098 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 6150 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
| 6099 | struct net_device *netdev, u64 cookie, | 6151 | struct net_device *netdev, u64 cookie, |
| 6100 | const u8 *buf, size_t len, bool ack, | 6152 | const u8 *buf, size_t len, bool ack, |
| 6101 | gfp_t gfp) | 6153 | gfp_t gfp) |
| 6102 | { | 6154 | { |
| 6103 | struct sk_buff *msg; | 6155 | struct sk_buff *msg; |
| 6104 | void *hdr; | 6156 | void *hdr; |
| @@ -6107,7 +6159,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | |||
| 6107 | if (!msg) | 6159 | if (!msg) |
| 6108 | return; | 6160 | return; |
| 6109 | 6161 | ||
| 6110 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); | 6162 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS); |
| 6111 | if (!hdr) { | 6163 | if (!hdr) { |
| 6112 | nlmsg_free(msg); | 6164 | nlmsg_free(msg); |
| 6113 | return; | 6165 | return; |
| @@ -6194,7 +6246,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
| 6194 | 6246 | ||
| 6195 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) | 6247 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) |
| 6196 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 6248 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) |
| 6197 | cfg80211_mlme_unregister_actions(wdev, notify->pid); | 6249 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
| 6198 | 6250 | ||
| 6199 | rcu_read_unlock(); | 6251 | rcu_read_unlock(); |
| 6200 | 6252 | ||
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2ad7fbc7d9f1..30d2f939150d 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
| @@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
| 74 | struct net_device *dev, const u8 *mac_addr, | 74 | struct net_device *dev, const u8 *mac_addr, |
| 75 | struct station_info *sinfo, gfp_t gfp); | 75 | struct station_info *sinfo, gfp_t gfp); |
| 76 | 76 | ||
| 77 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 77 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
| 78 | struct net_device *netdev, u32 nlpid, int freq, | 78 | struct net_device *netdev, u32 nlpid, int freq, |
| 79 | const u8 *buf, size_t len, gfp_t gfp); | 79 | const u8 *buf, size_t len, gfp_t gfp); |
| 80 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 80 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
| 81 | struct net_device *netdev, u64 cookie, | 81 | struct net_device *netdev, u64 cookie, |
| 82 | const u8 *buf, size_t len, bool ack, | 82 | const u8 *buf, size_t len, bool ack, |
| 83 | gfp_t gfp); | 83 | gfp_t gfp); |
| 84 | 84 | ||
| 85 | void | 85 | void |
| 86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | 86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 1eb24162be61..8d961cc4ae98 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -823,7 +823,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 823 | /* monitor can't bridge anyway */ | 823 | /* monitor can't bridge anyway */ |
| 824 | break; | 824 | break; |
| 825 | case NL80211_IFTYPE_UNSPECIFIED: | 825 | case NL80211_IFTYPE_UNSPECIFIED: |
| 826 | case __NL80211_IFTYPE_AFTER_LAST: | 826 | case NUM_NL80211_IFTYPES: |
| 827 | /* not happening */ | 827 | /* not happening */ |
| 828 | break; | 828 | break; |
| 829 | } | 829 | } |
