X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/060c85b4cbcec4bd77bf5485c6bbc7539aecb62b..878684ff47f116c5a75e8d1640bf32ad5922dc19:/package/rt2x00/src/rt2x00mac.c diff --git a/package/rt2x00/src/rt2x00mac.c b/package/rt2x00/src/rt2x00mac.c index 349353bee..85ea8a8e6 100644 --- a/package/rt2x00/src/rt2x00mac.c +++ b/package/rt2x00/src/rt2x00mac.c @@ -19,10 +19,8 @@ */ /* - Module: rt2x00lib + Module: rt2x00mac Abstract: rt2x00 generic mac80211 routines. - Supported chipsets: RT2460, RT2560, RT2570, - rt2561, rt2561s, rt2661, rt2571W & rt2671. */ /* @@ -30,14 +28,16 @@ */ #define DRV_NAME "rt2x00lib" -#include +#include +#include #include "rt2x00.h" -#include "rt2x00dev.h" +#include "rt2x00lib.h" -static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, struct sk_buff *frag_skb, - struct ieee80211_tx_control *control) +static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, + struct sk_buff *frag_skb, + struct ieee80211_tx_control *control) { struct sk_buff *skb; int size; @@ -57,13 +57,13 @@ static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev, skb_put(skb, size); if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - ieee80211_ctstoself_get(rt2x00dev->hw, - frag_skb->data, frag_skb->len, control, - (struct ieee80211_cts*)(skb->data)); + ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id, + frag_skb->data, frag_skb->len, control, + (struct ieee80211_cts *)(skb->data)); else - ieee80211_rts_get(rt2x00dev->hw, - frag_skb->data, frag_skb->len, control, - (struct ieee80211_rts*)(skb->data)); + ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id, + frag_skb->data, frag_skb->len, control, + (struct ieee80211_rts *)(skb->data)); if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) { WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); @@ -73,23 +73,34 @@ static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev, return NETDEV_TX_OK; } -int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data; + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; struct data_ring *ring; u16 frame_control; + /* + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. + * Note that we can only stop the TX queues inside the TX path + * due to possible race conditions in mac80211. + */ + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { + ieee80211_stop_queues(hw); + return 0; + } + /* * Determine which ring to put packet on. */ - ring = rt2x00_get_ring(rt2x00dev, control->queue); + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); if (unlikely(!ring)) { ERROR(rt2x00dev, - "Attempt to send packet over invalid queue %d.\n" - "Please file bug report to %s.\n", - control->queue, DRV_PROJECT); + "Attempt to send packet over invalid queue %d.\n" + "Please file bug report to %s.\n", + control->queue, DRV_PROJECT); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -101,12 +112,13 @@ int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb, * frame as well as the data frame. */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS && - !is_cts_frame(frame_control) && !is_rts_frame(frame_control)) { + if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && + (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT))) { if (rt2x00_ring_free(ring) <= 1) return NETDEV_TX_BUSY; - if (rt2x00_tx_rts_cts(rt2x00dev, ring, skb, control)) + if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) return NETDEV_TX_BUSY; } @@ -118,29 +130,26 @@ int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb, return NETDEV_TX_OK; } -EXPORT_SYMBOL_GPL(rt2x00lib_tx); - -int rt2x00lib_reset(struct ieee80211_hw *hw) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - rt2x00lib_disable_radio(rt2x00dev); - return rt2x00lib_enable_radio(rt2x00dev); -} -EXPORT_SYMBOL_GPL(rt2x00lib_reset); +EXPORT_SYMBOL_GPL(rt2x00mac_tx); -int rt2x00lib_open(struct ieee80211_hw *hw) +int rt2x00mac_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; int status; + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + return 0; + /* - * We must wait on the firmware before - * we can safely continue. + * If this is the first interface which is added, + * we should load the firmware now. */ - status = rt2x00lib_load_firmware_wait(rt2x00dev); - if (status) - return status; + if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) { + status = rt2x00lib_load_firmware(rt2x00dev); + if (status) + return status; + } /* * Initialize the device. @@ -158,125 +167,111 @@ int rt2x00lib_open(struct ieee80211_hw *hw) return status; } + __set_bit(DEVICE_STARTED, &rt2x00dev->flags); + return 0; } -EXPORT_SYMBOL_GPL(rt2x00lib_open); +EXPORT_SYMBOL_GPL(rt2x00mac_start); -int rt2x00lib_stop(struct ieee80211_hw *hw) +void rt2x00mac_stop(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + return; + + /* + * Perhaps we can add something smarter here, + * but for now just disabling the radio should do. + */ rt2x00lib_disable_radio(rt2x00dev); - return 0; + __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); } -EXPORT_SYMBOL_GPL(rt2x00lib_stop); +EXPORT_SYMBOL_GPL(rt2x00mac_stop); -int rt2x00lib_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +int rt2x00mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; struct interface *intf = &rt2x00dev->interface; - /* - * We only support 1 non-monitor interface. - */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && - is_interface_present(&rt2x00dev->interface)) - return -ENOBUFS; - - /* - * We support muliple monitor mode interfaces. - * All we need to do is increase the monitor_count. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count++; - } else { - intf->id = conf->if_id; - intf->type = conf->type; - if (conf->type == IEEE80211_IF_TYPE_AP) - memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); - intf->promisc = 0; + /* FIXME: Beaconing is broken in rt2x00. */ + if (conf->type == IEEE80211_IF_TYPE_IBSS || + conf->type == IEEE80211_IF_TYPE_AP) { + ERROR(rt2x00dev, + "rt2x00 does not support Adhoc or Master mode"); + return -EOPNOTSUPP; } /* - * If this is the first interface which is being added, - * we should write the MAC address to the device. + * Don't allow interfaces to be added while + * either the device has disappeared or when + * another interface is already present. */ - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) - rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, conf->mac_addr); + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + is_interface_present(intf)) + return -ENOBUFS; + + intf->id = conf->if_id; + intf->type = conf->type; + if (conf->type == IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); + memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); /* - * Enable periodic link tuning if this is a non-monitor interface. + * The MAC adddress must be configured after the device + * has been initialized. Otherwise the device can reset + * the MAC registers. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR) - rt2x00_start_link_tune(rt2x00dev); + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_type(rt2x00dev, conf->type); return 0; } -EXPORT_SYMBOL_GPL(rt2x00lib_add_interface); +EXPORT_SYMBOL_GPL(rt2x00mac_add_interface); -void rt2x00lib_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +void rt2x00mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; struct interface *intf = &rt2x00dev->interface; /* - * We only support 1 non-monitor interface. + * Don't allow interfaces to be remove while + * either the device has disappeared or when + * no interface is present. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && - !is_interface_present(&rt2x00dev->interface)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + !is_interface_present(intf)) return; - /* - * We support muliple monitor mode interfaces. - * All we need to do is decrease the monitor_count. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count--; - } else if (intf->type == conf->type) { - intf->id = 0; - intf->type = -EINVAL; - memset(&intf->bssid, 0x00, ETH_ALEN); - intf->promisc = 0; - } - - /* - * When this is a non-monitor mode, stop the periodic link tuning. - */ - if (conf->type != IEEE80211_IF_TYPE_MNTR) - rt2x00_stop_link_tune(rt2x00dev); + intf->id = 0; + intf->type = INVALID_INTERFACE; + memset(&intf->bssid, 0x00, ETH_ALEN); + memset(&intf->mac, 0x00, ETH_ALEN); /* - * Check if we still have 1 non-monitor or a monitor - * interface enabled. In that case we should update the - * registers. + * Make sure the bssid and mac address registers + * are cleared to prevent false ACKing of frames. */ - if (is_monitor_present(&rt2x00dev->interface) ^ - is_interface_present(&rt2x00dev->interface)) { - if (is_interface_present(&rt2x00dev->interface)) - rt2x00lib_config_type(rt2x00dev, - rt2x00dev->interface.type); - else - rt2x00lib_config_type(rt2x00dev, - IEEE80211_IF_TYPE_MNTR); - } - - /* - * Check which interfaces have been disabled. - */ - if (!is_interface_present(&rt2x00dev->interface)) - __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - else if (!is_monitor_present(&rt2x00dev->interface)) - __clear_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags); + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_type(rt2x00dev, intf->type); } -EXPORT_SYMBOL_GPL(rt2x00lib_remove_interface); +EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); -int rt2x00lib_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; + /* + * 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; + /* * Check if we need to disable the radio, * if this is not the case, at least the RX must be disabled. @@ -285,46 +280,42 @@ int rt2x00lib_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (!conf->radio_enabled) rt2x00lib_disable_radio(rt2x00dev); else - rt2x00lib_toggle_rx(rt2x00dev, 0); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); } - rt2x00lib_config_phymode(rt2x00dev, conf->phymode); - rt2x00lib_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->freq, conf->power_level); - rt2x00lib_config_txpower(rt2x00dev, conf->power_level); - rt2x00lib_config_antenna(rt2x00dev, - conf->antenna_sel_tx, conf->antenna_sel_rx); - rt2x00dev->ops->lib->config_duration(rt2x00dev, - (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME), - conf->beacon_int); + rt2x00lib_config(rt2x00dev, conf, 0); /* * Reenable RX only if the radio should be on. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) - rt2x00lib_toggle_rx(rt2x00dev, 1); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); else if (conf->radio_enabled) return rt2x00lib_enable_radio(rt2x00dev); return 0; } -EXPORT_SYMBOL_GPL(rt2x00lib_config); +EXPORT_SYMBOL_GPL(rt2x00mac_config); -int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id, - struct ieee80211_if_conf *conf) +int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; struct interface *intf = &rt2x00dev->interface; int status; /* - * Monitor mode does not need configuring. + * 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; + + /* * If the given type does not match the configured type, * there has been a problem. */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) - return 0; - else if (conf->type != intf->type) + if (conf->type != intf->type) return -EINVAL; /* @@ -334,14 +325,7 @@ int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id, */ if (conf->type != IEEE80211_IF_TYPE_AP) memcpy(&intf->bssid, conf->bssid, ETH_ALEN); - - /* - * Enable configuration. - * For Monitor mode, promisc mode will be forced on. - */ - rt2x00lib_config_type(rt2x00dev, conf->type); - rt2x00lib_config_promisc(rt2x00dev, rt2x00dev->interface.promisc); - rt2x00dev->ops->lib->config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); /* * We only need to initialize the beacon when master mode is enabled. @@ -350,65 +334,86 @@ int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id, return 0; status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, - conf->beacon, conf->beacon_control); + conf->beacon, + conf->beacon_control); if (status) dev_kfree_skb(conf->beacon); return status; } -EXPORT_SYMBOL_GPL(rt2x00lib_config_interface); +EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); -void rt2x00lib_set_multicast_list(struct ieee80211_hw *hw, - unsigned short flags, int mc_count) +int rt2x00mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { struct rt2x00_dev *rt2x00dev = hw->priv; /* - * Promisc mode is forced on for Monitor interfaces. + * The dot11ACKFailureCount, dot11RTSFailureCount and + * dot11RTSSuccessCount are updated in interrupt time. + * dot11FCSErrorCount is updated in the link tuner. */ - if (is_monitor_present(&rt2x00dev->interface)) - return; + memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats)); - /* - * Check if the new state is different then the old state. - */ - if (test_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags) == - (flags & IFF_PROMISC)) - return; - - rt2x00dev->interface.promisc = (flags & IFF_PROMISC); - - /* - * Schedule the link tuner if this does not run - * automatically. The link tuner will be automatically - * switched off when it is not required. - */ - if (!work_pending(&rt2x00dev->link.work.work)) - queue_work(rt2x00dev->workqueue, &rt2x00dev->link.work.work); + return 0; } -EXPORT_SYMBOL_GPL(rt2x00lib_set_multicast_list); +EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); -int rt2x00lib_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) +int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) { struct rt2x00_dev *rt2x00dev = hw->priv; unsigned int i; for (i = 0; i < hw->queues; i++) memcpy(&stats->data[i], &rt2x00dev->tx[i].stats, - sizeof(rt2x00dev->tx[i].stats)); + sizeof(rt2x00dev->tx[i].stats)); return 0; } -EXPORT_SYMBOL_GPL(rt2x00lib_get_tx_stats); +EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); + +void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, + int cts_protection, int preamble) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int short_preamble; + int ack_timeout; + int ack_consume_time; + int difs; + + /* + * We only support changing preamble mode. + */ + if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE)) + return; + + short_preamble = !preamble; + preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE; + + difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS; + ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10); + + ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + + if (short_preamble) + __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + else + __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + + rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble, + ack_timeout, ack_consume_time); +} +EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed); -int rt2x00lib_conf_tx(struct ieee80211_hw *hw, int queue, - const struct ieee80211_tx_queue_params *params) +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; struct data_ring *ring; - ring = rt2x00_get_ring(rt2x00dev, queue); + ring = rt2x00lib_get_ring(rt2x00dev, queue); if (unlikely(!ring)) return -EINVAL; @@ -432,10 +437,10 @@ int rt2x00lib_conf_tx(struct ieee80211_hw *hw, int queue, ring->tx_params.aifs = 2; INFO(rt2x00dev, - "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", - queue, ring->tx_params.cw_min, ring->tx_params.cw_max, - ring->tx_params.aifs); + "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", + queue, ring->tx_params.cw_min, ring->tx_params.cw_max, + ring->tx_params.aifs); return 0; } -EXPORT_SYMBOL_GPL(rt2x00lib_conf_tx); +EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);