Пример #1
0
static int iwm_wext_siwpower(struct net_device *dev,
                             struct iw_request_info *info,
                             struct iw_param *wrq, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);
    u32 power_index;

    if (wrq->disabled) {
        power_index = IWM_POWER_INDEX_MIN;
        goto set;
    } else
        power_index = IWM_POWER_INDEX_DEFAULT;

    switch (wrq->flags & IW_POWER_MODE) {
    case IW_POWER_ON:
    case IW_POWER_MODE:
    case IW_POWER_ALL_R:
        break;
    default:
        return -EINVAL;
    }

set:
    if (power_index == iwm->conf.power_index)
        return 0;

    iwm->conf.power_index = power_index;

    return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
                                   CFG_POWER_INDEX, iwm->conf.power_index);
}
Пример #2
0
static int iwm_wext_siwessid(struct net_device *dev,
                             struct iw_request_info *info,
                             struct iw_point *data, char *ssid)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);
    size_t len = data->length;
    int ret;

    if (iwm->conf.mode == UMAC_MODE_IBSS)
        return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);

    if (!test_bit(IWM_STATUS_READY, &iwm->status))
        return -EIO;

    if (len > 0 && ssid[len - 1] == '\0')
        len--;

    if (iwm->umac_profile_active) {
        if (iwm->umac_profile->ssid.ssid_len == len &&
                !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
            return 0;

        ret = iwm_invalidate_mlme_profile(iwm);
        if (ret < 0) {
            IWM_ERR(iwm, "Couldn't invalidate profile\n");
            return ret;
        }
    }

    iwm->umac_profile->ssid.ssid_len = len;
    memcpy(iwm->umac_profile->ssid.ssid, ssid, len);

    return iwm_send_mlme_profile(iwm);
}
Пример #3
0
static int iwm_wext_giwpower(struct net_device *dev,
                             struct iw_request_info *info,
                             union iwreq_data *wrqu, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);

    wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);

    return 0;
}
Пример #4
0
static int iwm_wext_giwrate(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_param *rate, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);

    rate->value = iwm->rate * 1000000;

    return 0;
}
Пример #5
0
static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);
    struct iw_statistics *wstats = &iwm->wstats;

    if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
        memset(wstats, 0, sizeof(struct iw_statistics));
        wstats->qual.updated = IW_QUAL_ALL_INVALID;
    }

    return wstats;
}
Пример #6
0
static int iwm_wext_giwencode(struct net_device *dev,
                              struct iw_request_info *info,
                              struct iw_point *erq, char *key)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);
    int idx, i;

    idx = erq->flags & IW_ENCODE_INDEX;
    if (idx < 1 || idx > 4) {
        idx = -1;
        if (!iwm->default_key) {
            erq->length = 0;
            erq->flags |= IW_ENCODE_NOKEY;
            return 0;
        } else
            for (i = 0; i < IWM_NUM_KEYS; i++) {
                if (iwm->default_key == &iwm->keys[i]) {
                    idx = i;
                    break;
                }
            }
        if (idx < 0)
            return -EINVAL;
    } else
        idx--;

    erq->flags = idx + 1;

    if (!iwm->keys[idx].in_use) {
        erq->length = 0;
        erq->flags |= IW_ENCODE_DISABLED;
        return 0;
    }

    memcpy(key, iwm->keys[idx].key,
           min_t(int, erq->length, iwm->keys[idx].key_len));
    erq->length = iwm->keys[idx].key_len;
    erq->flags |= IW_ENCODE_ENABLED;

    if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
        switch (iwm->umac_profile->sec.auth_type) {
        case UMAC_AUTH_TYPE_OPEN:
            erq->flags |= IW_ENCODE_OPEN;
            break;
        default:
            erq->flags |= IW_ENCODE_RESTRICTED;
            break;
        }
    }

    return 0;
}
Пример #7
0
static int iwm_wext_giwfreq(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_freq *freq, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);

    if (iwm->conf.mode == UMAC_MODE_IBSS)
        return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);

    freq->e = 0;
    freq->m = iwm->channel;

    return 0;
}
Пример #8
0
static int iwm_wext_siwfreq(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_freq *freq, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);

    if (freq->flags == IW_FREQ_AUTO)
        return 0;

    /* frequency/channel can only be set in IBSS mode */
    if (iwm->conf.mode != UMAC_MODE_IBSS)
        return -EOPNOTSUPP;

    return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
}
Пример #9
0
static int iwm_wext_siwauth(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_param *data, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);
    int ret;

    if ((data->flags) &
            (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
             IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
        /* We need to invalidate the current profile */
        if (iwm->umac_profile_active) {
            ret = iwm_invalidate_mlme_profile(iwm);
            if (ret < 0) {
                IWM_ERR(iwm, "Couldn't invalidate profile\n");
                return ret;
            }
        }
    }

    switch (data->flags & IW_AUTH_INDEX) {
    case IW_AUTH_WPA_VERSION:
        return iwm_set_wpa_version(iwm, data->value);
        break;
    case IW_AUTH_CIPHER_PAIRWISE:
        return iwm_set_cipher(iwm, data->value, 1);
        break;
    case IW_AUTH_CIPHER_GROUP:
        return iwm_set_cipher(iwm, data->value, 0);
        break;
    case IW_AUTH_KEY_MGMT:
        return iwm_set_key_mgt(iwm, data->value);
        break;
    case IW_AUTH_80211_AUTH_ALG:
        return iwm_set_auth_alg(iwm, data->value);
        break;
    default:
        return -ENOTSUPP;
    }

    return 0;
}
Пример #10
0
static int iwm_wext_giwessid(struct net_device *dev,
                             struct iw_request_info *info,
                             struct iw_point *data, char *ssid)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);

    if (iwm->conf.mode == UMAC_MODE_IBSS)
        return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);

    if (!test_bit(IWM_STATUS_READY, &iwm->status))
        return -EIO;

    data->length = iwm->umac_profile->ssid.ssid_len;
    if (data->length) {
        memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
        data->flags = 1;
    } else
        data->flags = 0;

    return 0;
}
Пример #11
0
static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
                          struct sockaddr *ap_addr, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);

    switch (iwm->conf.mode) {
    case UMAC_MODE_IBSS:
        return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
    case UMAC_MODE_BSS:
        if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
            ap_addr->sa_family = ARPHRD_ETHER;
            memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
        } else
            memset(&ap_addr->sa_data, 0, ETH_ALEN);
        break;
    default:
        return -EOPNOTSUPP;
    }

    return 0;
}
Пример #12
0
static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
                          struct sockaddr *ap_addr, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);

    if (iwm->conf.mode == UMAC_MODE_IBSS)
        return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);

    if (!test_bit(IWM_STATUS_READY, &iwm->status))
        return -EIO;

    if (is_zero_ether_addr(ap_addr->sa_data) ||
            is_broadcast_ether_addr(ap_addr->sa_data)) {
        IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
                     iwm->umac_profile->bssid[0]);
        memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
        iwm->umac_profile->bss_num = 0;
    } else {
        IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
                     ap_addr->sa_data);
        memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
               ETH_ALEN);
        iwm->umac_profile->bss_num = 1;
    }

    if (iwm->umac_profile_active) {
        if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
            return 0;

        iwm_invalidate_mlme_profile(iwm);
    }

    if (iwm->umac_profile->ssid.ssid_len)
        return iwm_send_mlme_profile(iwm);

    return 0;
}
Пример #13
0
static int iwm_wext_siwencodeext(struct net_device *dev,
                                 struct iw_request_info *info,
                                 struct iw_point *erq, char *extra)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);
    struct iwm_key *key;
    struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
    int uninitialized_var(alg), idx, i, remove = 0;

    IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
    IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
    IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
    IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
    IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);

    switch (ext->alg) {
    case IW_ENCODE_ALG_NONE:
        remove = 1;
        break;
    case IW_ENCODE_ALG_WEP:
        if (ext->key_len == WLAN_KEY_LEN_WEP40)
            alg = UMAC_CIPHER_TYPE_WEP_40;
        else if (ext->key_len == WLAN_KEY_LEN_WEP104)
            alg = UMAC_CIPHER_TYPE_WEP_104;
        else {
            IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
            return -EINVAL;
        }

        break;
    case IW_ENCODE_ALG_TKIP:
        alg = UMAC_CIPHER_TYPE_TKIP;
        break;
    case IW_ENCODE_ALG_CCMP:
        alg = UMAC_CIPHER_TYPE_CCMP;
        break;
    default:
        return -EOPNOTSUPP;
    }

    idx = erq->flags & IW_ENCODE_INDEX;

    if (idx == 0) {
        if (iwm->default_key)
            for (i = 0; i < IWM_NUM_KEYS; i++) {
                if (iwm->default_key == &iwm->keys[i]) {
                    idx = i;
                    break;
                }
            }
    } else if (idx < 1 || idx > 4) {
        return -EINVAL;
    } else
        idx--;

    if (erq->flags & IW_ENCODE_DISABLED)
        remove = 1;
    else if ((erq->length == 0) ||
             (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
        iwm->default_key = &iwm->keys[idx];
        if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
            return iwm_set_tx_key(iwm, idx);
    }

    key = iwm_key_init(iwm, idx, !remove, ext, alg);

    return iwm_set_key(iwm, remove, !iwm->default_key, key);
}
Пример #14
0
static int iwm_stop(struct net_device *ndev)
{
	struct iwm_priv *iwm = ndev_to_iwm(ndev);

	return iwm_down(iwm);
}
Пример #15
0
static int iwm_wext_siwencode(struct net_device *dev,
                              struct iw_request_info *info,
                              struct iw_point *erq, char *key_buf)
{
    struct iwm_priv *iwm = ndev_to_iwm(dev);
    struct iwm_key *uninitialized_var(key);
    int idx, i, uninitialized_var(alg), remove = 0, ret;

    IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
    IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);

    if (!iwm->umac_profile) {
        IWM_ERR(iwm, "UMAC profile not allocated yet\n");
        return -ENODEV;
    }

    if (erq->length == WLAN_KEY_LEN_WEP40) {
        alg = UMAC_CIPHER_TYPE_WEP_40;
        iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
        iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
    } else if (erq->length == WLAN_KEY_LEN_WEP104) {
        alg = UMAC_CIPHER_TYPE_WEP_104;
        iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
        iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
    }

    if (erq->flags & IW_ENCODE_RESTRICTED)
        iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
    else
        iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;

    idx = erq->flags & IW_ENCODE_INDEX;
    if (idx == 0) {
        if (iwm->default_key)
            for (i = 0; i < IWM_NUM_KEYS; i++) {
                if (iwm->default_key == &iwm->keys[i]) {
                    idx = i;
                    break;
                }
            }
        else
            iwm->default_key = &iwm->keys[idx];
    } else if (idx < 1 || idx > 4) {
        return -EINVAL;
    } else
        idx--;

    if (erq->flags & IW_ENCODE_DISABLED)
        remove = 1;
    else if (erq->length == 0) {
        if (!iwm->keys[idx].in_use)
            return -EINVAL;
        iwm->default_key = &iwm->keys[idx];
    }

    if (erq->length) {
        key = &iwm->keys[idx];
        memset(key, 0, sizeof(struct iwm_key));
        memset(key->hdr.mac, 0xff, ETH_ALEN);
        key->hdr.key_idx = idx;
        key->hdr.multicast = 1;
        key->in_use = !remove;
        key->alg = alg;
        key->key_len = erq->length;
        memcpy(key->key, key_buf, erq->length);

        IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
                     idx, !!iwm->default_key);
    }

    if (remove) {
        if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
            int j;
            for (j = 0; j < IWM_NUM_KEYS; j++)
                if (iwm->keys[j].in_use) {
                    struct iwm_key *k = &iwm->keys[j];

                    k->in_use = 0;
                    ret = iwm_set_key(iwm, remove, 0, k);
                    if (ret < 0)
                        return ret;
                }

            iwm->umac_profile->sec.ucast_cipher =
                UMAC_CIPHER_TYPE_NONE;
            iwm->umac_profile->sec.mcast_cipher =
                UMAC_CIPHER_TYPE_NONE;
            iwm->umac_profile->sec.auth_type =
                UMAC_AUTH_TYPE_OPEN;

            return 0;
        } else {
            key->in_use = 0;
            return iwm_set_key(iwm, remove, 0, key);
        }
    }

    /*
     * If we havent set a profile yet, we cant set keys.
     * Keys will be pushed after we're associated.
     */
    if (!iwm->umac_profile_active)
        return 0;

    /*
     * If there is a current active profile, but no
     * default key, it's not worth trying to associate again.
     */
    if (!iwm->default_key)
        return 0;

    /*
     * Here we have an active profile, but a key setting changed.
     * We thus have to invalidate the current profile, and push the
     * new one. Keys will be pushed when association takes place.
     */
    ret = iwm_invalidate_mlme_profile(iwm);
    if (ret < 0) {
        IWM_ERR(iwm, "Couldn't invalidate profile\n");
        return ret;
    }

    return iwm_send_mlme_profile(iwm);
}
Пример #16
0
int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
	struct iwm_priv *iwm = ndev_to_iwm(netdev);
	struct wireless_dev *wdev = iwm_to_wdev(iwm);
	struct iwm_tx_info *tx_info;
	struct iwm_tx_queue *txq;
	struct iwm_sta_info *sta_info;
	u8 *dst_addr, sta_id;
	u16 queue;
	int ret;


	if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
		IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: "
			   "not associated\n");
		netif_tx_stop_all_queues(netdev);
		goto drop;
	}

	queue = skb_get_queue_mapping(skb);
	BUG_ON(queue >= IWM_TX_DATA_QUEUES); 

	txq = &iwm->txq[queue];

	
	if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) ||
	    (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) {
		IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue);
		netif_stop_subqueue(netdev, queue);
		return NETDEV_TX_BUSY;
	}

	ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype,
				       iwm->bssid, 0);
	if (ret) {
		IWM_ERR(iwm, "build wifi header failed\n");
		goto drop;
	}

	dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1;

	for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) {
		sta_info = &iwm->sta_table[sta_id];
		if (sta_info->valid &&
		    !memcmp(dst_addr, sta_info->addr, ETH_ALEN))
			break;
	}

	if (sta_id == IWM_STA_TABLE_NUM) {
		IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n",
			dst_addr);
		goto drop;
	}

	tx_info = skb_to_tx_info(skb);
	tx_info->sta = sta_id;
	tx_info->color = sta_info->color;
	
	if (sta_info->qos)
		tx_info->tid = skb->priority;
	else
		tx_info->tid = IWM_UMAC_MGMT_TID;

	spin_lock_bh(&iwm->txq[queue].lock);
	skb_queue_tail(&iwm->txq[queue].queue, skb);
	spin_unlock_bh(&iwm->txq[queue].lock);

	queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);

	netdev->stats.tx_packets++;
	netdev->stats.tx_bytes += skb->len;
	return NETDEV_TX_OK;

 drop:
	netdev->stats.tx_dropped++;
	dev_kfree_skb_any(skb);
	return NETDEV_TX_OK;
}
Пример #17
0
static int iwm_open(struct net_device *ndev)
{
	struct iwm_priv *iwm = ndev_to_iwm(ndev);

	return iwm_up(iwm);
}