Exemplo n.º 1
0
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
                               struct iw_request_info *info,
                               struct iw_freq *wextfreq, char *extra)
{
    struct wireless_dev *wdev = dev->ieee80211_ptr;
    struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
    struct ieee80211_channel *chan = NULL;
    int err, freq;

    /* call only for ibss! */
    if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
        return -EINVAL;

    if (!rdev->ops->join_ibss)
        return -EOPNOTSUPP;

    freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
    if (freq < 0)
        return freq;

    if (freq) {
        chan = ieee80211_get_channel(wdev->wiphy, freq);
        if (!chan)
            return -EINVAL;
        if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
                chan->flags & IEEE80211_CHAN_DISABLED)
            return -EINVAL;
    }

    if (wdev->wext.ibss.chandef.chan == chan)
        return 0;

    wdev_lock(wdev);
    err = 0;
    if (wdev->ssid_len)
        err = __cfg80211_leave_ibss(rdev, dev, true);
    wdev_unlock(wdev);

    if (err)
        return err;

    if (chan) {
        wdev->wext.ibss.chandef.chan = chan;
        wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
        wdev->wext.ibss.channel_fixed = true;
    } else {
        /* cfg80211_ibss_wext_join will pick one if needed */
        wdev->wext.ibss.channel_fixed = false;
    }

    mutex_lock(&rdev->devlist_mtx);
    wdev_lock(wdev);
    err = cfg80211_ibss_wext_join(rdev, wdev);
    wdev_unlock(wdev);
    mutex_unlock(&rdev->devlist_mtx);

    return err;
}
Exemplo n.º 2
0
int cfg80211_ibss_wext_siwap(struct net_device *dev,
			     struct iw_request_info *info,
			     struct sockaddr *ap_addr, char *extra)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
	u8 *bssid = ap_addr->sa_data;
	int err;

	/* call only for ibss! */
	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
		return -EINVAL;

	if (!rdev->ops->join_ibss)
		return -EOPNOTSUPP;

	if (ap_addr->sa_family != ARPHRD_ETHER)
		return -EINVAL;

	/* automatic mode */
	if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
		bssid = NULL;

	if (bssid && !is_valid_ether_addr(bssid))
		return -EINVAL;

	/* both automatic */
	if (!bssid && !wdev->wext.ibss.bssid)
		return 0;

	/* fixed already - and no change */
	if (wdev->wext.ibss.bssid && bssid &&
	    ether_addr_equal(bssid, wdev->wext.ibss.bssid))
		return 0;

	wdev_lock(wdev);
	err = 0;
	if (wdev->ssid_len)
		err = __cfg80211_leave_ibss(rdev, dev, true);
	wdev_unlock(wdev);

	if (err)
		return err;

	if (bssid) {
		memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
		wdev->wext.ibss.bssid = wdev->wext.bssid;
	} else
		wdev->wext.ibss.bssid = NULL;

	wdev_lock(wdev);
	err = cfg80211_ibss_wext_join(rdev, wdev);
	wdev_unlock(wdev);

	return err;
}
Exemplo n.º 3
0
int cfg80211_ibss_wext_siwessid(struct net_device *dev,
                                struct iw_request_info *info,
                                struct iw_point *data, char *ssid)
{
    struct wireless_dev *wdev = dev->ieee80211_ptr;
    struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
    size_t len = data->length;
    int err;

    /* call only for ibss! */
    if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
        return -EINVAL;

    if (!rdev->ops->join_ibss)
        return -EOPNOTSUPP;

    wdev_lock(wdev);
    err = 0;
    if (wdev->ssid_len)
        err = __cfg80211_leave_ibss(rdev, dev, true);
    wdev_unlock(wdev);

    if (err)
        return err;

    /* iwconfig uses nul termination in SSID.. */
    if (len > 0 && ssid[len - 1] == '\0')
        len--;

    wdev->wext.ibss.ssid = wdev->ssid;
    memcpy(wdev->wext.ibss.ssid, ssid, len);
    wdev->wext.ibss.ssid_len = len;

    mutex_lock(&rdev->devlist_mtx);
    wdev_lock(wdev);
    err = cfg80211_ibss_wext_join(rdev, wdev);
    wdev_unlock(wdev);
    mutex_unlock(&rdev->devlist_mtx);

    return err;
}
Exemplo n.º 4
0
static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
				     struct net_device *dev, bool pairwise,
				     const u8 *addr, bool remove, bool tx_key,
				     int idx, struct key_params *params)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err, i;
	bool rejoin = false;

	if (pairwise && !addr)
		return -EINVAL;

	if (!wdev->wext.keys) {
		wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
					      GFP_KERNEL);
		if (!wdev->wext.keys)
			return -ENOMEM;
		for (i = 0; i < 6; i++)
			wdev->wext.keys->params[i].key =
				wdev->wext.keys->data[i];
	}

	if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
	    wdev->iftype != NL80211_IFTYPE_STATION)
		return -EOPNOTSUPP;

	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
		if (!wdev->current_bss)
			return -ENOLINK;

		if (!rdev->ops->set_default_mgmt_key)
			return -EOPNOTSUPP;

		if (idx < 4 || idx > 5)
			return -EINVAL;
	} else if (idx < 0 || idx > 3)
		return -EINVAL;

	if (remove) {
		err = 0;
		if (wdev->current_bss) {
			/*
			 * If removing the current TX key, we will need to
			 * join a new IBSS without the privacy bit clear.
			 */
			if (idx == wdev->wext.default_key &&
			    wdev->iftype == NL80211_IFTYPE_ADHOC) {
				__cfg80211_leave_ibss(rdev, wdev->netdev, true);
				rejoin = true;
			}

			if (!pairwise && addr &&
			    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
				err = -ENOENT;
			else
				err = rdev->ops->del_key(&rdev->wiphy, dev, idx,
							 pairwise, addr);
		}
		wdev->wext.connect.privacy = false;
		/*
		 * Applications using wireless extensions expect to be
		 * able to delete keys that don't exist, so allow that.
		 */
		if (err == -ENOENT)
			err = 0;
		if (!err) {
			if (!addr) {
				wdev->wext.keys->params[idx].key_len = 0;
				wdev->wext.keys->params[idx].cipher = 0;
			}
			if (idx == wdev->wext.default_key)
				wdev->wext.default_key = -1;
			else if (idx == wdev->wext.default_mgmt_key)
				wdev->wext.default_mgmt_key = -1;
		}

		if (!err && rejoin)
			err = cfg80211_ibss_wext_join(rdev, wdev);

		return err;
	}

	if (addr)
		tx_key = false;

	if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr))
		return -EINVAL;

	err = 0;
	if (wdev->current_bss)
		err = rdev->ops->add_key(&rdev->wiphy, dev, idx,
					 pairwise, addr, params);
	if (err)
		return err;

	if (!addr) {
		wdev->wext.keys->params[idx] = *params;
		memcpy(wdev->wext.keys->data[idx],
			params->key, params->key_len);
		wdev->wext.keys->params[idx].key =
			wdev->wext.keys->data[idx];
	}

	if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
	     params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
	    (tx_key || (!addr && wdev->wext.default_key == -1))) {
		if (wdev->current_bss) {
			/*
			 * If we are getting a new TX key from not having
			 * had one before we need to join a new IBSS with
			 * the privacy bit set.
			 */
			if (wdev->iftype == NL80211_IFTYPE_ADHOC &&
			    wdev->wext.default_key == -1) {
				__cfg80211_leave_ibss(rdev, wdev->netdev, true);
				rejoin = true;
			}
			err = rdev->ops->set_default_key(&rdev->wiphy, dev,
							 idx, true, true);
		}
		if (!err) {
			wdev->wext.default_key = idx;
			if (rejoin)
				err = cfg80211_ibss_wext_join(rdev, wdev);
		}
		return err;
	}

	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
	    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
		if (wdev->current_bss)
			err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
							      dev, idx);
		if (!err)
			wdev->wext.default_mgmt_key = idx;
		return err;
	}

	return 0;
}