void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); /* * Don't allow interfaces to be remove while * either the device has disappeared or when * no interface is present. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) return; if (vif->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count--; else rt2x00dev->intf_sta_count--; /* * Release beacon entry so it is available for * new interfaces again. */ clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); /* * Make sure the bssid and mac address registers * are cleared to prevent false ACKing of frames. */ rt2x00lib_config_intf(rt2x00dev, intf, NL80211_IFTYPE_UNSPECIFIED, NULL, NULL); }
int rt2x00mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); int update_bssid = 0; int status = 0; /* * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return 0; spin_lock(&intf->lock); /* * conf->bssid can be NULL if coming from the internal * beacon update routine. */ if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { update_bssid = 1; memcpy(&intf->bssid, conf->bssid, ETH_ALEN); } spin_unlock(&intf->lock); /* * Call rt2x00_config_intf() outside of the spinlock context since * the call will sleep for USB drivers. By using the ieee80211_if_conf * values as arguments we make keep access to rt2x00_intf thread safe * even without the lock. */ rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, update_bssid ? conf->bssid : NULL); /* * Update the beacon. */ if (conf->changed & IEEE80211_IFCC_BEACON) status = rt2x00queue_update_beacon(rt2x00dev, vif); return status; }
static void rt2x00lib_resume_intf(void *data, u8 *mac, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); spin_lock(&intf->lock); rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, intf->bssid); /* * Master or Ad-hoc mode require a new beacon update. */ if (vif->type == IEEE80211_IF_TYPE_AP || vif->type == IEEE80211_IF_TYPE_IBSS) intf->delayed_flags |= DELAYED_UPDATE_BEACON; spin_unlock(&intf->lock); }
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); /* * mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return; /* * Update the BSSID. */ if (changes & BSS_CHANGED_BSSID) rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, bss_conf->bssid); /* * Start/stop beaconing. */ if (changes & BSS_CHANGED_BEACON_ENABLED) { if (!bss_conf->enable_beacon && intf->enable_beacon) { rt2x00dev->intf_beaconing--; intf->enable_beacon = false; /* * Clear beacon in the H/W for this vif. This is needed * to disable beaconing on this particular interface * and keep it running on other interfaces. */ rt2x00queue_clear_beacon(rt2x00dev, vif); if (rt2x00dev->intf_beaconing == 0) { /* * Last beaconing interface disabled * -> stop beacon queue. */ mutex_lock(&intf->beacon_skb_mutex); rt2x00queue_stop_queue(rt2x00dev->bcn); mutex_unlock(&intf->beacon_skb_mutex); } } else if (bss_conf->enable_beacon && !intf->enable_beacon) { rt2x00dev->intf_beaconing++; intf->enable_beacon = true; /* * Upload beacon to the H/W. This is only required on * USB devices. PCI devices fetch beacons periodically. */ if (rt2x00_is_usb(rt2x00dev)) rt2x00queue_update_beacon(rt2x00dev, vif); if (rt2x00dev->intf_beaconing == 1) { /* * First beaconing interface enabled * -> start beacon queue. */ mutex_lock(&intf->beacon_skb_mutex); rt2x00queue_start_queue(rt2x00dev->bcn); mutex_unlock(&intf->beacon_skb_mutex); } } } /* * When the association status has changed we must reset the link * tuner counter. This is because some drivers determine if they * should perform link tuning based on the number of seconds * while associated or not associated. */ if (changes & BSS_CHANGED_ASSOC) { rt2x00dev->link.count = 0; if (bss_conf->assoc) rt2x00dev->intf_associated++; else rt2x00dev->intf_associated--; rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); clear_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags); } /* * Check for access point which do not support 802.11e . We have to * generate data frames sequence number in S/W for such AP, because * of H/W bug. */ if (changes & BSS_CHANGED_QOS && !bss_conf->qos) set_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags); /* * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes); }
int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); struct data_queue *queue = rt2x00dev->bcn; struct queue_entry *entry = NULL; unsigned int i; /* * Don't allow interfaces to be added * the device has disappeared. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; /* * Loop through all beacon queues to find a free * entry. Since there are as much beacon entries * as the maximum interfaces, this search shouldn't * fail. */ for (i = 0; i < queue->limit; i++) { entry = &queue->entries[i]; if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) break; } if (unlikely(i == queue->limit)) return -ENOBUFS; /* * We are now absolutely sure the interface can be created, * increase interface count and start initialization. */ if (vif->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count++; else rt2x00dev->intf_sta_count++; mutex_init(&intf->beacon_skb_mutex); intf->beacon = entry; /* * The MAC address must be configured after the device * has been initialized. Otherwise the device can reset * the MAC registers. * The BSSID address must only be configured in AP mode, * however we should not send an empty BSSID address for * STA interfaces at this time, since this can cause * invalid behavior in the device. */ rt2x00lib_config_intf(rt2x00dev, intf, vif->type, vif->addr, NULL); /* * Some filters depend on the current working mode. We can force * an update during the next configure_filter() run by mac80211 by * resetting the current packet_filter state. */ rt2x00dev->packet_filter = 0; return 0; }
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); /* * mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return; spin_lock(&intf->lock); /* * conf->bssid can be NULL if coming from the internal * beacon update routine. */ if (changes & BSS_CHANGED_BSSID) memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN); spin_unlock(&intf->lock); /* * Call rt2x00_config_intf() outside of the spinlock context since * the call will sleep for USB drivers. By using the ieee80211_if_conf * values as arguments we make keep access to rt2x00_intf thread safe * even without the lock. */ if (changes & BSS_CHANGED_BSSID) rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, bss_conf->bssid); /* * Update the beacon. */ if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) rt2x00queue_update_beacon(rt2x00dev, vif, bss_conf->enable_beacon); /* * When the association status has changed we must reset the link * tuner counter. This is because some drivers determine if they * should perform link tuning based on the number of seconds * while associated or not associated. */ if (changes & BSS_CHANGED_ASSOC) { rt2x00dev->link.count = 0; if (bss_conf->assoc) rt2x00dev->intf_associated++; else rt2x00dev->intf_associated--; rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } /* * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes); }
int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); struct queue_entry *entry = NULL; unsigned int i; /* * Don't allow interfaces to be added * the device has disappeared. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; switch (vif->type) { case NL80211_IFTYPE_AP: /* * We don't support mixed combinations of * sta and ap interfaces. */ if (rt2x00dev->intf_sta_count) return -ENOBUFS; /* * Check if we exceeded the maximum amount * of supported interfaces. */ if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf) return -ENOBUFS; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_WDS: /* * We don't support mixed combinations of * sta and ap interfaces. */ if (rt2x00dev->intf_ap_count) return -ENOBUFS; /* * Check if we exceeded the maximum amount * of supported interfaces. */ if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf) return -ENOBUFS; break; default: return -EINVAL; } /* * Loop through all beacon queues to find a free * entry. Since there are as much beacon entries * as the maximum interfaces, this search shouldn't * fail. */ for (i = 0; i < queue->limit; i++) { entry = &queue->entries[i]; if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) break; } if (unlikely(i == queue->limit)) return -ENOBUFS; /* * We are now absolutely sure the interface can be created, * increase interface count and start initialization. */ if (vif->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count++; else rt2x00dev->intf_sta_count++; spin_lock_init(&intf->lock); spin_lock_init(&intf->seqlock); mutex_init(&intf->beacon_skb_mutex); intf->beacon = entry; /* * The MAC adddress must be configured after the device * has been initialized. Otherwise the device can reset * the MAC registers. * The BSSID address must only be configured in AP mode, * however we should not send an empty BSSID address for * STA interfaces at this time, since this can cause * invalid behavior in the device. */ memcpy(&intf->mac, vif->addr, ETH_ALEN); if (vif->type == NL80211_IFTYPE_AP) { memcpy(&intf->bssid, vif->addr, ETH_ALEN); rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, intf->bssid); } else { rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL); } /* * Some filters depend on the current working mode. We can force * an update during the next configure_filter() run by mac80211 by * resetting the current packet_filter state. */ rt2x00dev->packet_filter = 0; return 0; }