Almost all drivers below cfg80211 get the API wrong (except for cfg80211) and are unable to cope with multiple registrations for the same frame type, which is valid due to the match filter. This seems to indicate the API is wrong, and we should maintain the full information in cfg80211 instead of the drivers. Change the API to no longer inform the driver about individual registrations and unregistrations, but rather every time about the entire state of the entire wiphy and single wdev, whenever it may have changed. This also simplifies the code in cfg80211 as it no longer has to track exactly what was unregistered and can free things immediately.
Unified · Split
| @@ -3249,22 +3249,19 @@ static int ath6kl_get_antenna(struct wiphy *wiphy, · 3248 unmodified lines | ||
| 3249 | 3249 | return 0; |
| 3250 | 3250 | } |
| 3251 | 3251 | |
| 3252 | −static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, | |
| 3253 | − struct wireless_dev *wdev, | |
| 3254 | − u16 frame_type, bool reg) | |
| 3252 | +static void ath6kl_update_mgmt_frame_registrations(struct wiphy *wiphy, | |
| 3253 | + struct wireless_dev *wdev, | |
| 3254 | + struct mgmt_frame_regs *upd) | |
| 3255 | 3255 | { |
| 3256 | 3256 | struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); |
| 3257 | 3257 | |
| 3258 | − ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", | |
| 3259 | − __func__, frame_type, reg); | |
| 3260 | − if (frame_type == IEEE80211_STYPE_PROBE_REQ) { | |
| 3261 | − /* | |
| 3262 | − * Note: This notification callback is not allowed to sleep, so | |
| 3263 | − * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we | |
| 3264 | − * hardcode target to report Probe Request frames all the time. | |
| 3265 | − */ | |
| 3266 | − vif->probe_req_report = reg; | |
| 3267 | − } | |
| 3258 | + /* | |
| 3259 | + * FIXME: send WMI_PROBE_REQ_REPORT_CMD here instead of hardcoding | |
| 3260 | + * the reporting in the target all the time, this callback | |
| 3261 | + * *is* allowed to sleep after all. | |
| 3262 | + */ | |
| 3263 | + vif->probe_req_report = | |
| 3264 | + upd->interface_stypes & BIT(IEEE80211_STYPE_PROBE_REQ >> 4); | |
| 3268 | 3265 | } |
| 3269 | 3266 | |
| 3270 | 3267 | static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, |
| @@ -3464,7 +3461,8 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { · 193 unmodified lines | ||
| 3464 | 3461 | .remain_on_channel = ath6kl_remain_on_channel, |
| 3465 | 3462 | .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, |
| 3466 | 3463 | .mgmt_tx = ath6kl_mgmt_tx, |
| 3467 | − .mgmt_frame_register = ath6kl_mgmt_frame_register, | |
| 3464 | + .update_mgmt_frame_registrations = | |
| 3465 | + ath6kl_update_mgmt_frame_registrations, | |
| 3468 | 3466 | .get_antenna = ath6kl_get_antenna, |
| 3469 | 3467 | .sched_scan_start = ath6kl_cfg80211_sscan_start, |
| 3470 | 3468 | .sched_scan_stop = ath6kl_cfg80211_sscan_stop, |
| @@ -4979,21 +4979,15 @@ brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, · 4978 unmodified lines | ||
| 4979 | 4979 | } |
| 4980 | 4980 | |
| 4981 | 4981 | static void |
| 4982 | −brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, | |
| 4983 | − struct wireless_dev *wdev, | |
| 4984 | − u16 frame_type, bool reg) | |
| 4982 | +brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy, | |
| 4983 | + struct wireless_dev *wdev, | |
| 4984 | + struct mgmt_frame_regs *upd) | |
| 4985 | 4985 | { |
| 4986 | 4986 | struct brcmf_cfg80211_vif *vif; |
| 4987 | − u16 mgmt_type; | |
| 4988 | 4987 | |
| 4989 | − brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg); | |
| 4990 | − | |
| 4991 | − mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | |
| 4992 | 4988 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); |
| 4993 | − if (reg) | |
| 4994 | − vif->mgmt_rx_reg |= BIT(mgmt_type); | |
| 4995 | − else | |
| 4996 | − vif->mgmt_rx_reg &= ~BIT(mgmt_type); | |
| 4989 | + | |
| 4990 | + vif->mgmt_rx_reg = upd->interface_stypes; | |
| 4997 | 4991 | } |
| 4998 | 4992 | |
| 4999 | 4993 | |
| @@ -5408,7 +5402,8 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { · 408 unmodified lines | ||
| 5408 | 5402 | .change_station = brcmf_cfg80211_change_station, |
| 5409 | 5403 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, |
| 5410 | 5404 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, |
| 5411 | − .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, | |
| 5405 | + .update_mgmt_frame_registrations = | |
| 5406 | + brcmf_cfg80211_update_mgmt_frame_registrations, | |
| 5412 | 5407 | .mgmt_tx = brcmf_cfg80211_mgmt_tx, |
| 5413 | 5408 | .remain_on_channel = brcmf_p2p_remain_on_channel, |
| 5414 | 5409 | .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, |
| @@ -269,17 +269,12 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, · 268 unmodified lines | ||
| 269 | 269 | * CFG802.11 operation handler to register a mgmt frame. |
| 270 | 270 | */ |
| 271 | 271 | static void |
| 272 | −mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy, | |
| 273 | − struct wireless_dev *wdev, | |
| 274 | − u16 frame_type, bool reg) | |
| 272 | +mwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy, | |
| 273 | + struct wireless_dev *wdev, | |
| 274 | + struct mgmt_frame_regs *upd) | |
| 275 | 275 | { |
| 276 | 276 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); |
| 277 | − u32 mask; | |
| 278 | − | |
| 279 | − if (reg) | |
| 280 | − mask = priv->mgmt_frame_mask | BIT(frame_type >> 4); | |
| 281 | − else | |
| 282 | − mask = priv->mgmt_frame_mask & ~BIT(frame_type >> 4); | |
| 277 | + u32 mask = upd->interface_stypes; | |
| 283 | 278 | |
| 284 | 279 | if (mask != priv->mgmt_frame_mask) { |
| 285 | 280 | priv->mgmt_frame_mask = mask; |
| @@ -4189,7 +4184,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { · 3903 unmodified lines | ||
| 4189 | 4184 | .del_key = mwifiex_cfg80211_del_key, |
| 4190 | 4185 | .set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key, |
| 4191 | 4186 | .mgmt_tx = mwifiex_cfg80211_mgmt_tx, |
| 4192 | − .mgmt_frame_register = mwifiex_cfg80211_mgmt_frame_register, | |
| 4187 | + .update_mgmt_frame_registrations = | |
| 4188 | + mwifiex_cfg80211_update_mgmt_frame_registrations, | |
| 4193 | 4189 | .remain_on_channel = mwifiex_cfg80211_remain_on_channel, |
| 4194 | 4190 | .cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel, |
| 4195 | 4191 | .set_default_key = mwifiex_cfg80211_set_default_key, |
| @@ -389,55 +389,57 @@ static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed) · 388 unmodified lines | ||
| 389 | 389 | } |
| 390 | 390 | |
| 391 | 391 | static void |
| 392 | −qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, | |
| 393 | − u16 frame_type, bool reg) | |
| 392 | +qtnf_update_mgmt_frame_registrations(struct wiphy *wiphy, | |
| 393 | + struct wireless_dev *wdev, | |
| 394 | + struct mgmt_frame_regs *upd) | |
| 394 | 395 | { |
| 395 | 396 | struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); |
| 396 | − u16 mgmt_type; | |
| 397 | − u16 new_mask; | |
| 398 | − u16 qlink_frame_type = 0; | |
| 397 | + u16 new_mask = upd->interface_stypes; | |
| 398 | + u16 old_mask = vif->mgmt_frames_bitmask; | |
| 399 | + static const struct { | |
| 400 | + u16 mask, qlink_type; | |
| 401 | + } updates[] = { | |
| 402 | + { | |
| 403 | + .mask = BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | |
| 404 | + BIT(IEEE80211_STYPE_ASSOC_REQ >> 4), | |
| 405 | + .qlink_type = QLINK_MGMT_FRAME_ASSOC_REQ, | |
| 406 | + }, | |
| 407 | + { | |
| 408 | + .mask = BIT(IEEE80211_STYPE_AUTH >> 4), | |
| 409 | + .qlink_type = QLINK_MGMT_FRAME_AUTH, | |
| 410 | + }, | |
| 411 | + { | |
| 412 | + .mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4), | |
| 413 | + .qlink_type = QLINK_MGMT_FRAME_PROBE_REQ, | |
| 414 | + }, | |
| 415 | + { | |
| 416 | + .mask = BIT(IEEE80211_STYPE_ACTION >> 4), | |
| 417 | + .qlink_type = QLINK_MGMT_FRAME_ACTION, | |
| 418 | + }, | |
| 419 | + }; | |
| 420 | + unsigned int i; | |
| 399 | 421 | |
| 400 | − mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | |
| 422 | + if (new_mask == old_mask) | |
| 423 | + return; | |
| 401 | 424 | |
| 402 | − if (reg) | |
| 403 | − new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type); | |
| 404 | − else | |
| 405 | − new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type); | |
| 425 | + for (i = 0; i < ARRAY_SIZE(updates); i++) { | |
| 426 | + u16 mask = updates[i].mask; | |
| 427 | + u16 qlink_frame_type = updates[i].qlink_type; | |
| 428 | + bool reg; | |
| 406 | 429 | |
| 407 | − if (new_mask == vif->mgmt_frames_bitmask) | |
| 408 | − return; | |
| 430 | + /* the ! are here due to the assoc/reassoc merge */ | |
| 431 | + if (!(new_mask & mask) == !(old_mask & mask)) | |
| 432 | + continue; | |
| 409 | 433 | |
| 410 | − switch (frame_type & IEEE80211_FCTL_STYPE) { | |
| 411 | − case IEEE80211_STYPE_REASSOC_REQ: | |
| 412 | − case IEEE80211_STYPE_ASSOC_REQ: | |
| 413 | − qlink_frame_type = QLINK_MGMT_FRAME_ASSOC_REQ; | |
| 414 | − break; | |
| 415 | − case IEEE80211_STYPE_AUTH: | |
| 416 | − qlink_frame_type = QLINK_MGMT_FRAME_AUTH; | |
| 417 | − break; | |
| 418 | − case IEEE80211_STYPE_PROBE_REQ: | |
| 419 | − qlink_frame_type = QLINK_MGMT_FRAME_PROBE_REQ; | |
| 420 | − break; | |
| 421 | − case IEEE80211_STYPE_ACTION: | |
| 422 | − qlink_frame_type = QLINK_MGMT_FRAME_ACTION; | |
| 423 | − break; | |
| 424 | − default: | |
| 425 | − pr_warn("VIF%u.%u: unsupported frame type: %X\n", | |
| 426 | − vif->mac->macid, vif->vifid, | |
| 427 | − (frame_type & IEEE80211_FCTL_STYPE) >> 4); | |
| 428 | − return; | |
| 429 | − } | |
| 434 | + reg = new_mask & mask; | |
| 430 | 435 | |
| 431 | − if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) { | |
| 432 | − pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n", | |
| 433 | − vif->mac->macid, vif->vifid, reg ? "" : "un", | |
| 434 | − frame_type); | |
| 435 | − return; | |
| 436 | + if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) | |
| 437 | + pr_warn("VIF%u.%u: failed to %sregister qlink frame type 0x%x\n", | |
| 438 | + vif->mac->macid, vif->vifid, reg ? "" : "un", | |
| 439 | + qlink_frame_type); | |
| 436 | 440 | } |
| 437 | 441 | |
| 438 | 442 | vif->mgmt_frames_bitmask = new_mask; |
| 439 | − pr_debug("VIF%u.%u: %sregistered mgmt frame type 0x%x\n", | |
| 440 | − vif->mac->macid, vif->vifid, reg ? "" : "un", frame_type); | |
| 441 | 443 | } |
| 442 | 444 | |
| 443 | 445 | static int |
| @@ -1017,7 +1019,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = { · 573 unmodified lines | ||
| 1017 | 1019 | .change_beacon = qtnf_change_beacon, |
| 1018 | 1020 | .stop_ap = qtnf_stop_ap, |
| 1019 | 1021 | .set_wiphy_params = qtnf_set_wiphy_params, |
| 1020 | − .mgmt_frame_register = qtnf_mgmt_frame_register, | |
| 1022 | + .update_mgmt_frame_registrations = | |
| 1023 | + qtnf_update_mgmt_frame_registrations, | |
| 1021 | 1024 | .mgmt_tx = qtnf_mgmt_tx, |
| 1022 | 1025 | .change_station = qtnf_change_station, |
| 1023 | 1026 | .del_station = qtnf_del_station, |
| @@ -3384,6 +3384,17 @@ struct cfg80211_update_owe_info { · 3383 unmodified lines | ||
| 3384 | 3384 | size_t ie_len; |
| 3385 | 3385 | }; |
| 3386 | 3386 | |
| 3387 | +/** | |
| 3388 | + * struct mgmt_frame_regs - management frame registrations data | |
| 3389 | + * @global_stypes: bitmap of management frame subtypes registered | |
| 3390 | + * for the entire device | |
| 3391 | + * @interface_stypes: bitmap of management frame subtypes registered | |
| 3392 | + * for the given interface | |
| 3393 | + */ | |
| 3394 | +struct mgmt_frame_regs { | |
| 3395 | + u32 global_stypes, interface_stypes; | |
| 3396 | +}; | |
| 3397 | + | |
| 3387 | 3398 | /** |
| 3388 | 3399 | * struct cfg80211_ops - backend description for wireless configuration |
| 3389 | 3400 | * |
| @@ -3608,8 +3619,8 @@ struct cfg80211_update_owe_info { · 218 unmodified lines | ||
| 3608 | 3619 | * The driver should not call cfg80211_sched_scan_stopped() for a requested |
| 3609 | 3620 | * stop (when this method returns 0). |
| 3610 | 3621 | * |
| 3611 | − * @mgmt_frame_register: Notify driver that a management frame type was | |
| 3612 | − * registered. The callback is allowed to sleep. | |
| 3622 | + * @update_mgmt_frame_registrations: Notify the driver that management frame | |
| 3623 | + * registrations were updated. The callback is allowed to sleep. | |
| 3613 | 3624 | * |
| 3614 | 3625 | * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device. |
| 3615 | 3626 | * Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may |
| @@ -3932,9 +3943,9 @@ struct cfg80211_ops { · 316 unmodified lines | ||
| 3932 | 3943 | struct net_device *dev, |
| 3933 | 3944 | u32 rate, u32 pkts, u32 intvl); |
| 3934 | 3945 | |
| 3935 | − void (*mgmt_frame_register)(struct wiphy *wiphy, | |
| 3936 | − struct wireless_dev *wdev, | |
| 3937 | − u16 frame_type, bool reg); | |
| 3946 | + void (*update_mgmt_frame_registrations)(struct wiphy *wiphy, | |
| 3947 | + struct wireless_dev *wdev, | |
| 3948 | + struct mgmt_frame_regs *upd); | |
| 3938 | 3949 | |
| 3939 | 3950 | int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); |
| 3940 | 3951 | int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); |
| @@ -5015,6 +5026,7 @@ struct cfg80211_cqm_config; · 1074 unmodified lines | ||
| 5015 | 5026 | * by cfg80211 on change_interface |
| 5016 | 5027 | * @mgmt_registrations: list of registrations for management frames |
| 5017 | 5028 | * @mgmt_registrations_lock: lock for the list |
| 5029 | + * @mgmt_registrations_update_wk: update work to defer from atomic context | |
| 5018 | 5030 | * @mtx: mutex used to lock data in this struct, may be used by drivers |
| 5019 | 5031 | * and some API functions require it held |
| 5020 | 5032 | * @beacon_interval: beacon interval used on this device for transmitting |
| @@ -5060,6 +5072,7 @@ struct wireless_dev { · 39 unmodified lines | ||
| 5060 | 5072 | |
| 5061 | 5073 | struct list_head mgmt_registrations; |
| 5062 | 5074 | spinlock_t mgmt_registrations_lock; |
| 5075 | + struct work_struct mgmt_registrations_update_wk; | |
| 5063 | 5076 | |
| 5064 | 5077 | struct mutex mtx; |
| 5065 | 5078 | |
| @@ -1647,7 +1647,7 @@ struct ieee80211_vif { · 1646 unmodified lines | ||
| 1647 | 1647 | struct dentry *debugfs_dir; |
| 1648 | 1648 | #endif |
| 1649 | 1649 | |
| 1650 | − unsigned int probe_req_reg; | |
| 1650 | + bool probe_req_reg; | |
| 1651 | 1651 | |
| 1652 | 1652 | bool txqs_stopped[IEEE80211_NUM_ACS]; |
| 1653 | 1653 | |
| @@ -3398,44 +3398,35 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb, · 3397 unmodified lines | ||
| 3398 | 3398 | return 0; |
| 3399 | 3399 | } |
| 3400 | 3400 | |
| 3401 | −static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, | |
| 3401 | +static void | |
| 3402 | +ieee80211_update_mgmt_frame_registrations(struct wiphy *wiphy, | |
| 3402 | 3403 | struct wireless_dev *wdev, |
| 3403 | − u16 frame_type, bool reg) | |
| 3404 | + struct mgmt_frame_regs *upd) | |
| 3404 | 3405 | { |
| 3405 | 3406 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 3406 | 3407 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
| 3408 | + u32 preq_mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4); | |
| 3409 | + bool global_change, intf_change; | |
| 3407 | 3410 | |
| 3408 | − switch (frame_type) { | |
| 3409 | − case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: | |
| 3410 | − if (reg) { | |
| 3411 | − local->probe_req_reg++; | |
| 3412 | − sdata->vif.probe_req_reg++; | |
| 3413 | − } else { | |
| 3414 | − if (local->probe_req_reg) | |
| 3415 | − local->probe_req_reg--; | |
| 3411 | + global_change = | |
| 3412 | + local->probe_req_reg != !!(upd->global_stypes & preq_mask); | |
| 3413 | + local->probe_req_reg = upd->global_stypes & preq_mask; | |
| 3416 | 3414 | |
| 3417 | − if (sdata->vif.probe_req_reg) | |
| 3418 | − sdata->vif.probe_req_reg--; | |
| 3419 | − } | |
| 3415 | + intf_change = sdata->vif.probe_req_reg != | |
| 3416 | + !!(upd->interface_stypes & preq_mask); | |
| 3417 | + sdata->vif.probe_req_reg = upd->interface_stypes & preq_mask; | |
| 3420 | 3418 | |
| 3421 | − if (!local->open_count) | |
| 3422 | − break; | |
| 3419 | + if (!local->open_count) | |
| 3420 | + return; | |
| 3423 | 3421 | |
| 3424 | − if (ieee80211_sdata_running(sdata)) { | |
| 3425 | − if (sdata->vif.probe_req_reg == 1) | |
| 3426 | − drv_config_iface_filter(local, sdata, | |
| 3427 | − FIF_PROBE_REQ, | |
| 3428 | − FIF_PROBE_REQ); | |
| 3429 | − else if (sdata->vif.probe_req_reg == 0) | |
| 3430 | − drv_config_iface_filter(local, sdata, 0, | |
| 3431 | − FIF_PROBE_REQ); | |
| 3432 | − } | |
| 3422 | + if (intf_change && ieee80211_sdata_running(sdata)) | |
| 3423 | + drv_config_iface_filter(local, sdata, | |
| 3424 | + sdata->vif.probe_req_reg ? | |
| 3425 | + FIF_PROBE_REQ : 0, | |
| 3426 | + FIF_PROBE_REQ); | |
| 3433 | 3427 | |
| 3428 | + if (global_change) | |
| 3434 | 3429 | ieee80211_configure_filter(local); |
| 3435 | − break; | |
| 3436 | − default: | |
| 3437 | − break; | |
| 3438 | − } | |
| 3439 | 3430 | } |
| 3440 | 3431 | |
| 3441 | 3432 | static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) |
| @@ -4020,7 +4011,8 @@ const struct cfg80211_ops mac80211_config_ops = { · 578 unmodified lines | ||
| 4020 | 4011 | .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait, |
| 4021 | 4012 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, |
| 4022 | 4013 | .set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config, |
| 4023 | − .mgmt_frame_register = ieee80211_mgmt_frame_register, | |
| 4014 | + .update_mgmt_frame_registrations = | |
| 4015 | + ieee80211_update_mgmt_frame_registrations, | |
| 4024 | 4016 | .set_antenna = ieee80211_set_antenna, |
| 4025 | 4017 | .get_antenna = ieee80211_get_antenna, |
| 4026 | 4018 | .set_rekey_data = ieee80211_set_rekey_data, |
| @@ -1167,7 +1167,7 @@ struct ieee80211_local { · 1166 unmodified lines | ||
| 1167 | 1167 | /* number of interfaces with corresponding FIF_ flags */ |
| 1168 | 1168 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll, |
| 1169 | 1169 | fif_probe_req; |
| 1170 | − int probe_req_reg; | |
| 1170 | + bool probe_req_reg; | |
| 1171 | 1171 | unsigned int filter_flags; /* FIF_* */ |
| 1172 | 1172 | |
| 1173 | 1173 | bool wiphy_ciphers_allocated; |
| @@ -480,9 +480,6 @@ use_default_name: · 479 unmodified lines | ||
| 480 | 480 | INIT_LIST_HEAD(&rdev->bss_list); |
| 481 | 481 | INIT_LIST_HEAD(&rdev->sched_scan_req_list); |
| 482 | 482 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
| 483 | − INIT_LIST_HEAD(&rdev->mlme_unreg); | |
| 484 | − spin_lock_init(&rdev->mlme_unreg_lock); | |
| 485 | − INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk); | |
| 486 | 483 | INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk, |
| 487 | 484 | cfg80211_dfs_channels_update_work); |
| 488 | 485 | #ifdef CONFIG_CFG80211_WEXT |
| @@ -1030,7 +1027,6 @@ void wiphy_unregister(struct wiphy *wiphy) · 541 unmodified lines | ||
| 1030 | 1027 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
| 1031 | 1028 | flush_work(&rdev->destroy_work); |
| 1032 | 1029 | flush_work(&rdev->sched_scan_stop_wk); |
| 1033 | − flush_work(&rdev->mlme_unreg_wk); | |
| 1034 | 1030 | flush_work(&rdev->propagate_radar_detect_wk); |
| 1035 | 1031 | flush_work(&rdev->propagate_cac_done_wk); |
| 1036 | 1032 | |
| @@ -1094,6 +1090,7 @@ static void __cfg80211_unregister_wdev(struct wireless_dev *wdev, bool sync) · 57 unmodified lines | ||
| 1094 | 1090 | rdev->devlist_generation++; |
| 1095 | 1091 | |
| 1096 | 1092 | cfg80211_mlme_purge_registrations(wdev); |
| 1093 | + flush_work(&wdev->mgmt_registrations_update_wk); | |
| 1097 | 1094 | |
| 1098 | 1095 | switch (wdev->iftype) { |
| 1099 | 1096 | case NL80211_IFTYPE_P2P_DEVICE: |
| @@ -1238,6 +1235,8 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev, · 138 unmodified lines | ||
| 1238 | 1235 | spin_lock_init(&wdev->event_lock); |
| 1239 | 1236 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
| 1240 | 1237 | spin_lock_init(&wdev->mgmt_registrations_lock); |
| 1238 | + INIT_WORK(&wdev->mgmt_registrations_update_wk, | |
| 1239 | + cfg80211_mgmt_registrations_update_wk); | |
| 1241 | 1240 | INIT_LIST_HEAD(&wdev->pmsr_list); |
| 1242 | 1241 | spin_lock_init(&wdev->pmsr_lock); |
| 1243 | 1242 | INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk); |
| @@ -60,10 +60,6 @@ struct cfg80211_registered_device { · 59 unmodified lines | ||
| 60 | 60 | struct list_head beacon_registrations; |
| 61 | 61 | spinlock_t beacon_registrations_lock; |
| 62 | 62 | |
| 63 | − struct list_head mlme_unreg; | |
| 64 | − spinlock_t mlme_unreg_lock; | |
| 65 | − struct work_struct mlme_unreg_wk; | |
| 66 | − | |
| 67 | 63 | /* protected by RTNL only */ |
| 68 | 64 | int num_running_ifaces; |
| 69 | 65 | int num_running_monitor_ifaces; |
| @@ -386,7 +382,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, · 316 unmodified lines | ||
| 386 | 382 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
| 387 | 383 | u16 frame_type, const u8 *match_data, |
| 388 | 384 | int match_len, struct netlink_ext_ack *extack); |
| 389 | −void cfg80211_mlme_unreg_wk(struct work_struct *wk); | |
| 385 | +void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk); | |
| 390 | 386 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); |
| 391 | 387 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
| 392 | 388 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| @@ -429,43 +429,37 @@ struct cfg80211_mgmt_registration { · 428 unmodified lines | ||
| 429 | 429 | u8 match[]; |
| 430 | 430 | }; |
| 431 | 431 | |
| 432 | −static void | |
| 433 | −cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev) | |
| 432 | +static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev) | |
| 434 | 433 | { |
| 434 | + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | |
| 435 | + struct wireless_dev *tmp; | |
| 435 | 436 | struct cfg80211_mgmt_registration *reg; |
| 437 | + struct mgmt_frame_regs upd = {}; | |
| 436 | 438 | |
| 437 | 439 | ASSERT_RTNL(); |
| 438 | 440 | |
| 439 | − spin_lock_bh(&rdev->mlme_unreg_lock); | |
| 440 | − while ((reg = list_first_entry_or_null(&rdev->mlme_unreg, | |
| 441 | − struct cfg80211_mgmt_registration, | |
| 442 | − list))) { | |
| 443 | − list_del(®->list); | |
| 444 | − spin_unlock_bh(&rdev->mlme_unreg_lock); | |
| 445 | − | |
| 446 | − if (rdev->ops->mgmt_frame_register) { | |
| 447 | − u16 frame_type = le16_to_cpu(reg->frame_type); | |
| 441 | + rcu_read_lock(); | |
| 442 | + list_for_each_entry_rcu(tmp, &rdev->wiphy.wdev_list, list) { | |
| 443 | + list_for_each_entry_rcu(reg, &tmp->mgmt_registrations, list) { | |
| 444 | + u32 mask = BIT(le16_to_cpu(reg->frame_type) >> 4); | |
| 448 | 445 | |
| 449 | − rdev_mgmt_frame_register(rdev, reg->wdev, | |
| 450 | − frame_type, false); | |
| 446 | + upd.global_stypes |= mask; | |
| 447 | + if (tmp == wdev) | |
| 448 | + upd.interface_stypes |= mask; | |
| 451 | 449 | } |
| 452 | − | |
| 453 | − kfree(reg); | |
| 454 | − | |
| 455 | − spin_lock_bh(&rdev->mlme_unreg_lock); | |
| 456 | 450 | } |
| 457 | − spin_unlock_bh(&rdev->mlme_unreg_lock); | |
| 451 | + rcu_read_unlock(); | |
| 452 | + | |
| 453 | + rdev_update_mgmt_frame_registrations(rdev, wdev, &upd); | |
| 458 | 454 | } |
| 459 | 455 | |
| 460 | −void cfg80211_mlme_unreg_wk(struct work_struct *wk) | |
| 456 | +void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk) | |
| 461 | 457 | { |
| 462 | − struct cfg80211_registered_device *rdev; | |
| 463 | − | |
| 464 | − rdev = container_of(wk, struct cfg80211_registered_device, | |
| 465 | − mlme_unreg_wk); | |
| 458 | + struct wireless_dev *wdev = container_of(wk, struct wireless_dev, | |
| 459 | + mgmt_registrations_update_wk); | |
| 466 | 460 | |
| 467 | 461 | rtnl_lock(); |
| 468 | − cfg80211_process_mlme_unregistrations(rdev); | |
| 462 | + cfg80211_mgmt_registrations_update(wdev); | |
| 469 | 463 | rtnl_unlock(); |
| 470 | 464 | } |
| 471 | 465 | |
| @@ -473,8 +467,6 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, · 1 unmodified line | ||
| 473 | 467 | u16 frame_type, const u8 *match_data, |
| 474 | 468 | int match_len, struct netlink_ext_ack *extack) |
| 475 | 469 | { |
| 476 | − struct wiphy *wiphy = wdev->wiphy; | |
| 477 | − struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | |
| 478 | 470 | struct cfg80211_mgmt_registration *reg, *nreg; |
| 479 | 471 | int err = 0; |
| 480 | 472 | u16 mgmt_type; |
| @@ -534,10 +526,8 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, · 53 unmodified lines | ||
| 534 | 526 | } |
| 535 | 527 | } |
| 536 | 528 | |
| 537 | − if (err) { | |
| 538 | − kfree(nreg); | |
| 529 | + if (err) | |
| 539 | 530 | goto out; |
| 540 | − } | |
| 541 | 531 | |
| 542 | 532 | memcpy(nreg->match, match_data, match_len); |
| 543 | 533 | nreg->match_len = match_len; |
| @@ -547,15 +537,12 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, · 3 unmodified lines | ||
| 547 | 537 | list_add(&nreg->list, &wdev->mgmt_registrations); |
| 548 | 538 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 549 | 539 | |
| 550 | − /* process all unregistrations to avoid driver confusion */ | |
| 551 | − cfg80211_process_mlme_unregistrations(rdev); | |
| 552 | − | |
| 553 | − if (rdev->ops->mgmt_frame_register) | |
| 554 | − rdev_mgmt_frame_register(rdev, wdev, frame_type, true); | |
| 540 | + cfg80211_mgmt_registrations_update(wdev); | |
| 555 | 541 | |
| 556 | 542 | return 0; |
| 557 | 543 | |
| 558 | 544 | out: |
| 545 | + kfree(nreg); | |
| 559 | 546 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 560 | 547 | |
| 561 | 548 | return err; |
| @@ -574,11 +561,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) · 12 unmodified lines | ||
| 574 | 561 | continue; |
| 575 | 562 | |
| 576 | 563 | list_del(®->list); |
| 577 | − spin_lock(&rdev->mlme_unreg_lock); | |
| 578 | − list_add_tail(®->list, &rdev->mlme_unreg); | |
| 579 | − spin_unlock(&rdev->mlme_unreg_lock); | |
| 564 | + kfree(reg); | |
| 580 | 565 | |
| 581 | − schedule_work(&rdev->mlme_unreg_wk); | |
| 566 | + schedule_work(&wdev->mgmt_registrations_update_wk); | |
| 582 | 567 | } |
| 583 | 568 | |
| 584 | 569 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| @@ -594,15 +579,16 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) · 9 unmodified lines | ||
| 594 | 579 | |
| 595 | 580 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
| 596 | 581 | { |
| 597 | − struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | |
| 582 | + struct cfg80211_mgmt_registration *reg, *tmp; | |
| 598 | 583 | |
| 599 | 584 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
| 600 | − spin_lock(&rdev->mlme_unreg_lock); | |
| 601 | − list_splice_tail_init(&wdev->mgmt_registrations, &rdev->mlme_unreg); | |
| 602 | − spin_unlock(&rdev->mlme_unreg_lock); | |
| 585 | + list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { | |
| 586 | + list_del(®->list); | |
| 587 | + kfree(reg); | |
| 588 | + } | |
| 603 | 589 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 604 | 590 | |
| 605 | − cfg80211_process_mlme_unregistrations(rdev); | |
| 591 | + cfg80211_mgmt_registrations_update(wdev); | |
| 606 | 592 | } |
| 607 | 593 | |
| 608 | 594 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
| @@ -819,13 +819,16 @@ rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev, · 818 unmodified lines | ||
| 819 | 819 | } |
| 820 | 820 | |
| 821 | 821 | static inline void |
| 822 | −rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev, | |
| 823 | − struct wireless_dev *wdev, u16 frame_type, bool reg) | |
| 822 | +rdev_update_mgmt_frame_registrations(struct cfg80211_registered_device *rdev, | |
| 823 | + struct wireless_dev *wdev, | |
| 824 | + struct mgmt_frame_regs *upd) | |
| 824 | 825 | { |
| 825 | 826 | might_sleep(); |
| 826 | 827 | |
| 827 | − trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); | |
| 828 | − rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); | |
| 828 | + trace_rdev_update_mgmt_frame_registrations(&rdev->wiphy, wdev, upd); | |
| 829 | + if (rdev->ops->update_mgmt_frame_registrations) | |
| 830 | + rdev->ops->update_mgmt_frame_registrations(&rdev->wiphy, wdev, | |
| 831 | + upd); | |
| 829 | 832 | trace_rdev_return_void(&rdev->wiphy); |
| 830 | 833 | } |
| 831 | 834 | |
| @@ -1582,25 +1582,25 @@ TRACE_EVENT(rdev_set_bitrate_mask, · 1581 unmodified lines | ||
| 1582 | 1582 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) |
| 1583 | 1583 | ); |
| 1584 | 1584 | |
| 1585 | −TRACE_EVENT(rdev_mgmt_frame_register, | |
| 1585 | +TRACE_EVENT(rdev_update_mgmt_frame_registrations, | |
| 1586 | 1586 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 1587 | − u16 frame_type, bool reg), | |
| 1588 | − TP_ARGS(wiphy, wdev, frame_type, reg), | |
| 1587 | + struct mgmt_frame_regs *upd), | |
| 1588 | + TP_ARGS(wiphy, wdev, upd), | |
| 1589 | 1589 | TP_STRUCT__entry( |
| 1590 | 1590 | WIPHY_ENTRY |
| 1591 | 1591 | WDEV_ENTRY |
| 1592 | − __field(u16, frame_type) | |
| 1593 | − __field(bool, reg) | |
| 1592 | + __field(u16, global_stypes) | |
| 1593 | + __field(u16, interface_stypes) | |
| 1594 | 1594 | ), |
| 1595 | 1595 | TP_fast_assign( |
| 1596 | 1596 | WIPHY_ASSIGN; |
| 1597 | 1597 | WDEV_ASSIGN; |
| 1598 | − __entry->frame_type = frame_type; | |
| 1599 | − __entry->reg = reg; | |
| 1598 | + __entry->global_stypes = upd->global_stypes; | |
| 1599 | + __entry->interface_stypes = upd->interface_stypes; | |
| 1600 | 1600 | ), |
| 1601 | − TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", frame_type: 0x%.2x, reg: %s ", | |
| 1602 | − WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type, | |
| 1603 | − __entry->reg ? "true" : "false") | |
| 1601 | + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", global: 0x%.2x, intf: 0x%.2x", | |
| 1602 | + WIPHY_PR_ARG, WDEV_PR_ARG, | |
| 1603 | + __entry->global_stypes, __entry->interface_stypes) | |
| 1604 | 1604 | ); |
| 1605 | 1605 | |
| 1606 | 1606 | TRACE_EVENT(rdev_return_int_tx_rx, |