From 9d139c810a2aa17365cc548d0cd2a189d8433c65 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Jul 2008 14:40:37 +0200 Subject: mac80211: revamp beacon configuration This patch changes mac80211's beacon configuration handling to never pass skbs to the driver directly but rather always require the driver to use ieee80211_beacon_get(). Additionally, it introduces "change flags" on the config_interface() call to enable drivers to figure out what is changing. Finally, it removes the beacon_update() driver callback in favour of having IBSS beacon delivered by ieee80211_beacon_get() as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 4 +- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/main.c | 59 ++++++++++-------------- net/mac80211/mlme.c | 112 ++++++++++++++++++--------------------------- net/mac80211/tx.c | 36 +++++++++------ net/mac80211/wext.c | 2 +- 6 files changed, 95 insertions(+), 121 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ea03010..8e7ba0e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -469,7 +469,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, kfree(old); - return ieee80211_if_config_beacon(sdata->dev); + return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); } static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, @@ -523,7 +523,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) synchronize_rcu(); kfree(old); - return ieee80211_if_config_beacon(dev); + return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); } /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2146c0c..934c3ef 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -854,8 +854,7 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) /* ieee80211.c */ int ieee80211_hw_config(struct ieee80211_local *local); -int ieee80211_if_config(struct net_device *dev); -int ieee80211_if_config_beacon(struct net_device *dev); +int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_info *req_ht_cap, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0759ab2c..36859e7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -307,7 +307,8 @@ static int ieee80211_open(struct net_device *dev) if (res) goto err_stop; - ieee80211_if_config(dev); + if (ieee80211_vif_is_mesh(&sdata->vif)) + ieee80211_start_mesh(sdata->dev); changed |= ieee80211_reset_erp_info(dev); ieee80211_bss_info_change_notify(sdata, changed); ieee80211_enable_keys(sdata); @@ -985,57 +986,47 @@ void ieee80211_if_setup(struct net_device *dev) /* everything else */ -static int __ieee80211_if_config(struct net_device *dev, - struct sk_buff *beacon) +int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = sdata->local; struct ieee80211_if_conf conf; - if (!local->ops->config_interface || !netif_running(dev)) + if (WARN_ON(!netif_running(sdata->dev))) + return 0; + + if (!local->ops->config_interface) return 0; memset(&conf, 0, sizeof(conf)); - conf.type = sdata->vif.type; + conf.changed = changed; + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { - conf.beacon = beacon; - ieee80211_start_mesh(dev); } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { + conf.bssid = sdata->dev->dev_addr; conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; - conf.beacon = beacon; + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + u8 zero[ETH_ALEN] = { 0 }; + conf.bssid = zero; + conf.ssid = zero; + conf.ssid_len = 0; + } else { + WARN_ON(1); + return -EINVAL; } - return local->ops->config_interface(local_to_hw(local), - &sdata->vif, &conf); -} -int ieee80211_if_config(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && - (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) - return ieee80211_if_config_beacon(dev); - return __ieee80211_if_config(dev, NULL); -} + if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) + return -EINVAL; -int ieee80211_if_config_beacon(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sk_buff *skb; + if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID))) + return -EINVAL; - if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) - return 0; - skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif); - if (!skb) - return -ENOMEM; - return __ieee80211_if_config(dev, skb); + return local->ops->config_interface(local_to_hw(local), + &sdata->vif, &conf); } int ieee80211_hw_config(struct ieee80211_local *local) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 64d710a..61d7f81 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2406,8 +2406,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, int res, rates, i, j; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - struct ieee80211_tx_info *control; - struct rate_selection ratesel; u8 *pos; struct ieee80211_sub_if_data *sdata; struct ieee80211_supported_band *sband; @@ -2425,7 +2423,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, local->ops->reset_tsf(local_to_hw(local)); } memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); - res = ieee80211_if_config(dev); + res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); if (res) return res; @@ -2439,19 +2437,16 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, if (res) return res; - /* Set beacon template */ + /* Build IBSS probe response */ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - do { - if (!skb) - break; - + if (skb) { skb_reserve(skb, local->hw.extra_tx_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_BEACON); + IEEE80211_STYPE_PROBE_RESP); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); @@ -2495,61 +2490,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, memcpy(pos, &bss->supp_rates[8], rates); } - control = IEEE80211_SKB_CB(skb); - - rate_control_get_rate(dev, sband, skb, &ratesel); - if (ratesel.rate_idx < 0) { - printk(KERN_DEBUG "%s: Failed to determine TX rate " - "for IBSS beacon\n", dev->name); - break; - } - control->control.vif = &sdata->vif; - control->tx_rate_idx = ratesel.rate_idx; - if (sdata->bss_conf.use_short_preamble && - sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) - control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->flags |= IEEE80211_TX_CTL_NO_ACK; - control->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; - control->control.retry_limit = 1; - - ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); - if (ifsta->probe_resp) { - mgmt = (struct ieee80211_mgmt *) - ifsta->probe_resp->data; - mgmt->frame_control = - IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_PROBE_RESP); - } else { - printk(KERN_DEBUG "%s: Could not allocate ProbeResp " - "template for IBSS\n", dev->name); - } - - if (local->ops->beacon_update && - local->ops->beacon_update(local_to_hw(local), skb) == 0) { - printk(KERN_DEBUG "%s: Configured IBSS beacon " - "template\n", dev->name); - skb = NULL; - } - - rates = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - for (i = 0; i < bss->supp_rates_len; i++) { - int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == bitrate) - rates |= BIT(j); - } - ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + ifsta->probe_resp = skb; - ieee80211_sta_def_wmm_params(dev, bss, 1); - } while (0); + ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); + } - if (skb) { - printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " - "template\n", dev->name); - dev_kfree_skb(skb); + rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < bss->supp_rates_len; i++) { + int bitrate = (bss->supp_rates[i] & 0x7f) * 5; + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == bitrate) + rates |= BIT(j); } + ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + + ieee80211_sta_def_wmm_params(dev, bss, 1); ifsta->state = IEEE80211_IBSS_JOINED; mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); @@ -3333,7 +3289,7 @@ static void ieee80211_mesh_housekeeping(struct net_device *dev, free_plinks = mesh_plink_availables(sdata); if (free_plinks != sdata->u.sta.accepting_plinks) - ieee80211_if_config_beacon(dev); + ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); mod_timer(&ifsta->timer, jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL); @@ -3757,28 +3713,45 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta; + int res; if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; ifsta = &sdata->u.sta; - if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) + if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { + memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); + memcpy(ifsta->ssid, ssid, len); + ifsta->ssid_len = len; ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - memcpy(ifsta->ssid, ssid, len); - memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); - ifsta->ssid_len = len; + + res = 0; + /* + * Hack! MLME code needs to be cleaned up to have different + * entry points for configuration and internal selection change + */ + if (netif_running(sdata->dev)) + res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); + if (res) { + printk(KERN_DEBUG "%s: Failed to config new SSID to " + "the low-level driver\n", dev->name); + return res; + } + } if (len) ifsta->flags |= IEEE80211_STA_SSID_SET; else ifsta->flags &= ~IEEE80211_STA_SSID_SET; + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { ifsta->ibss_join_req = jiffies; ifsta->state = IEEE80211_IBSS_SEARCH; return ieee80211_sta_find_ibss(dev, ifsta); } + return 0; } @@ -3804,7 +3777,12 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid) if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { memcpy(ifsta->bssid, bssid, ETH_ALEN); - res = ieee80211_if_config(dev); + res = 0; + /* + * Hack! See also ieee80211_sta_set_ssid. + */ + if (netif_running(sdata->dev)) + res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); if (res) { printk(KERN_DEBUG "%s: Failed to config new BSSID to " "the low-level driver\n", dev->name); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a757dcc..8843416 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1788,17 +1788,17 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; + struct sk_buff *skb = NULL; struct ieee80211_tx_info *info; struct net_device *bdev; struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; + struct ieee80211_if_sta *ifsta = NULL; struct rate_selection rsel; struct beacon_data *beacon; struct ieee80211_supported_band *sband; struct ieee80211_mgmt *mgmt; int *num_beacons; - bool err = true; enum ieee80211_band band = local->hw.conf.channel->band; u8 *pos; @@ -1852,9 +1852,24 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, beacon->tail, beacon->tail_len); num_beacons = &ap->num_beacons; + } else + goto out; + } else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + struct ieee80211_hdr *hdr; + ifsta = &sdata->u.sta; - err = false; - } + if (!ifsta->probe_resp) + goto out; + + skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC); + if (!skb) + goto out; + + hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_BEACON); + + num_beacons = &ifsta->num_beacons; } else if (ieee80211_vif_is_mesh(&sdata->vif)) { /* headroom, head length, tail length and maximum TIM length */ skb = dev_alloc_skb(local->tx_headroom + 400); @@ -1881,17 +1896,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, mesh_mgmt_ies_add(skb, sdata->dev); num_beacons = &sdata->u.sta.num_beacons; - - err = false; - } - - if (err) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "no beacon data avail for %s\n", - bdev->name); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - skb = NULL; + } else { + WARN_ON(1); goto out; } diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index c041db9..34fa8ed 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -444,7 +444,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, memset(sdata->u.ap.ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); sdata->u.ap.ssid_len = len; - return ieee80211_if_config(dev); + return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); } return -EOPNOTSUPP; } -- cgit v1.1