|
@@ -2027,6 +2027,165 @@ void ieee80211_rx_bss_list_deinit(struct net_device *dev)
|
|
|
}
|
|
|
|
|
|
|
|
|
+static int ieee80211_sta_join_ibss(struct net_device *dev,
|
|
|
+ struct ieee80211_if_sta *ifsta,
|
|
|
+ struct ieee80211_sta_bss *bss)
|
|
|
+{
|
|
|
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
|
|
+ int res, rates, i, j;
|
|
|
+ struct sk_buff *skb;
|
|
|
+ struct ieee80211_mgmt *mgmt;
|
|
|
+ struct ieee80211_tx_control control;
|
|
|
+ struct rate_selection ratesel;
|
|
|
+ u8 *pos;
|
|
|
+ struct ieee80211_sub_if_data *sdata;
|
|
|
+ struct ieee80211_supported_band *sband;
|
|
|
+
|
|
|
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
|
|
+
|
|
|
+ /* Remove possible STA entries from other IBSS networks. */
|
|
|
+ sta_info_flush(local, NULL);
|
|
|
+
|
|
|
+ if (local->ops->reset_tsf) {
|
|
|
+ /* Reset own TSF to allow time synchronization work. */
|
|
|
+ local->ops->reset_tsf(local_to_hw(local));
|
|
|
+ }
|
|
|
+ memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
|
|
|
+ res = ieee80211_if_config(dev);
|
|
|
+ if (res)
|
|
|
+ return res;
|
|
|
+
|
|
|
+ local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
|
|
|
+
|
|
|
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
|
+ sdata->drop_unencrypted = bss->capability &
|
|
|
+ WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
|
|
+
|
|
|
+ res = ieee80211_set_freq(local, bss->freq);
|
|
|
+
|
|
|
+ if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
|
|
|
+ printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
|
|
|
+ "%d MHz\n", dev->name, local->oper_channel->center_freq);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Set beacon template */
|
|
|
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
|
|
|
+ do {
|
|
|
+ if (!skb)
|
|
|
+ break;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ memset(mgmt->da, 0xff, ETH_ALEN);
|
|
|
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
|
|
|
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
|
|
+ mgmt->u.beacon.beacon_int =
|
|
|
+ cpu_to_le16(local->hw.conf.beacon_int);
|
|
|
+ mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
|
|
|
+
|
|
|
+ pos = skb_put(skb, 2 + ifsta->ssid_len);
|
|
|
+ *pos++ = WLAN_EID_SSID;
|
|
|
+ *pos++ = ifsta->ssid_len;
|
|
|
+ memcpy(pos, ifsta->ssid, ifsta->ssid_len);
|
|
|
+
|
|
|
+ rates = bss->supp_rates_len;
|
|
|
+ if (rates > 8)
|
|
|
+ rates = 8;
|
|
|
+ pos = skb_put(skb, 2 + rates);
|
|
|
+ *pos++ = WLAN_EID_SUPP_RATES;
|
|
|
+ *pos++ = rates;
|
|
|
+ memcpy(pos, bss->supp_rates, rates);
|
|
|
+
|
|
|
+ if (bss->band == IEEE80211_BAND_2GHZ) {
|
|
|
+ pos = skb_put(skb, 2 + 1);
|
|
|
+ *pos++ = WLAN_EID_DS_PARAMS;
|
|
|
+ *pos++ = 1;
|
|
|
+ *pos++ = ieee80211_frequency_to_channel(bss->freq);
|
|
|
+ }
|
|
|
+
|
|
|
+ pos = skb_put(skb, 2 + 2);
|
|
|
+ *pos++ = WLAN_EID_IBSS_PARAMS;
|
|
|
+ *pos++ = 2;
|
|
|
+ /* FIX: set ATIM window based on scan results */
|
|
|
+ *pos++ = 0;
|
|
|
+ *pos++ = 0;
|
|
|
+
|
|
|
+ if (bss->supp_rates_len > 8) {
|
|
|
+ rates = bss->supp_rates_len - 8;
|
|
|
+ pos = skb_put(skb, 2 + rates);
|
|
|
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
|
|
|
+ *pos++ = rates;
|
|
|
+ memcpy(pos, &bss->supp_rates[8], rates);
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(&control, 0, sizeof(control));
|
|
|
+ rate_control_get_rate(dev, sband, skb, &ratesel);
|
|
|
+ if (!ratesel.rate) {
|
|
|
+ printk(KERN_DEBUG "%s: Failed to determine TX rate "
|
|
|
+ "for IBSS beacon\n", dev->name);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ control.vif = &sdata->vif;
|
|
|
+ control.tx_rate = ratesel.rate;
|
|
|
+ if (sdata->bss_conf.use_short_preamble &&
|
|
|
+ ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
|
|
+ control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
|
|
|
+ control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
|
|
|
+ control.flags |= IEEE80211_TXCTL_NO_ACK;
|
|
|
+ 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, &control) == 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;
|
|
|
+ } while (0);
|
|
|
+
|
|
|
+ if (skb) {
|
|
|
+ printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
|
|
|
+ "template\n", dev->name);
|
|
|
+ dev_kfree_skb(skb);
|
|
|
+ }
|
|
|
+
|
|
|
+ ifsta->state = IEEE80211_IBSS_JOINED;
|
|
|
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
|
|
|
+
|
|
|
+ ieee80211_rx_bss_put(dev, bss);
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static void ieee80211_rx_bss_info(struct net_device *dev,
|
|
|
struct ieee80211_mgmt *mgmt,
|
|
|
size_t len,
|
|
@@ -2891,164 +3050,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-static int ieee80211_sta_join_ibss(struct net_device *dev,
|
|
|
- struct ieee80211_if_sta *ifsta,
|
|
|
- struct ieee80211_sta_bss *bss)
|
|
|
-{
|
|
|
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
|
|
- int res, rates, i, j;
|
|
|
- struct sk_buff *skb;
|
|
|
- struct ieee80211_mgmt *mgmt;
|
|
|
- struct ieee80211_tx_control control;
|
|
|
- struct rate_selection ratesel;
|
|
|
- u8 *pos;
|
|
|
- struct ieee80211_sub_if_data *sdata;
|
|
|
- struct ieee80211_supported_band *sband;
|
|
|
-
|
|
|
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
|
|
-
|
|
|
- /* Remove possible STA entries from other IBSS networks. */
|
|
|
- sta_info_flush(local, NULL);
|
|
|
-
|
|
|
- if (local->ops->reset_tsf) {
|
|
|
- /* Reset own TSF to allow time synchronization work. */
|
|
|
- local->ops->reset_tsf(local_to_hw(local));
|
|
|
- }
|
|
|
- memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
|
|
|
- res = ieee80211_if_config(dev);
|
|
|
- if (res)
|
|
|
- return res;
|
|
|
-
|
|
|
- local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
|
|
|
-
|
|
|
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
|
- sdata->drop_unencrypted = bss->capability &
|
|
|
- WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
|
|
-
|
|
|
- res = ieee80211_set_freq(local, bss->freq);
|
|
|
-
|
|
|
- if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
|
|
|
- printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
|
|
|
- "%d MHz\n", dev->name, local->oper_channel->center_freq);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- /* Set beacon template based on scan results */
|
|
|
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
|
|
|
- do {
|
|
|
- if (!skb)
|
|
|
- break;
|
|
|
-
|
|
|
- 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);
|
|
|
- memset(mgmt->da, 0xff, ETH_ALEN);
|
|
|
- memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
|
|
|
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
|
|
|
- mgmt->u.beacon.beacon_int =
|
|
|
- cpu_to_le16(local->hw.conf.beacon_int);
|
|
|
- mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
|
|
|
-
|
|
|
- pos = skb_put(skb, 2 + ifsta->ssid_len);
|
|
|
- *pos++ = WLAN_EID_SSID;
|
|
|
- *pos++ = ifsta->ssid_len;
|
|
|
- memcpy(pos, ifsta->ssid, ifsta->ssid_len);
|
|
|
-
|
|
|
- rates = bss->supp_rates_len;
|
|
|
- if (rates > 8)
|
|
|
- rates = 8;
|
|
|
- pos = skb_put(skb, 2 + rates);
|
|
|
- *pos++ = WLAN_EID_SUPP_RATES;
|
|
|
- *pos++ = rates;
|
|
|
- memcpy(pos, bss->supp_rates, rates);
|
|
|
-
|
|
|
- if (bss->band == IEEE80211_BAND_2GHZ) {
|
|
|
- pos = skb_put(skb, 2 + 1);
|
|
|
- *pos++ = WLAN_EID_DS_PARAMS;
|
|
|
- *pos++ = 1;
|
|
|
- *pos++ = ieee80211_frequency_to_channel(bss->freq);
|
|
|
- }
|
|
|
-
|
|
|
- pos = skb_put(skb, 2 + 2);
|
|
|
- *pos++ = WLAN_EID_IBSS_PARAMS;
|
|
|
- *pos++ = 2;
|
|
|
- /* FIX: set ATIM window based on scan results */
|
|
|
- *pos++ = 0;
|
|
|
- *pos++ = 0;
|
|
|
-
|
|
|
- if (bss->supp_rates_len > 8) {
|
|
|
- rates = bss->supp_rates_len - 8;
|
|
|
- pos = skb_put(skb, 2 + rates);
|
|
|
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
|
|
|
- *pos++ = rates;
|
|
|
- memcpy(pos, &bss->supp_rates[8], rates);
|
|
|
- }
|
|
|
-
|
|
|
- memset(&control, 0, sizeof(control));
|
|
|
- rate_control_get_rate(dev, sband, skb, &ratesel);
|
|
|
- if (!ratesel.rate) {
|
|
|
- printk(KERN_DEBUG "%s: Failed to determine TX rate "
|
|
|
- "for IBSS beacon\n", dev->name);
|
|
|
- break;
|
|
|
- }
|
|
|
- control.vif = &sdata->vif;
|
|
|
- control.tx_rate = ratesel.rate;
|
|
|
- if (sdata->bss_conf.use_short_preamble &&
|
|
|
- ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
|
|
- control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
|
|
|
- control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
|
|
|
- control.flags |= IEEE80211_TXCTL_NO_ACK;
|
|
|
- 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, &control) == 0) {
|
|
|
- printk(KERN_DEBUG "%s: Configured IBSS beacon "
|
|
|
- "template based on scan results\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;
|
|
|
- } while (0);
|
|
|
-
|
|
|
- if (skb) {
|
|
|
- printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
|
|
|
- "template\n", dev->name);
|
|
|
- dev_kfree_skb(skb);
|
|
|
- }
|
|
|
-
|
|
|
- ifsta->state = IEEE80211_IBSS_JOINED;
|
|
|
- mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
|
|
|
-
|
|
|
- ieee80211_rx_bss_put(dev, bss);
|
|
|
-
|
|
|
- return res;
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
static int ieee80211_sta_create_ibss(struct net_device *dev,
|
|
|
struct ieee80211_if_sta *ifsta)
|