Ejemplo n.º 1
0
static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
				      struct net_device *ndev,
				      struct cfg80211_beacon_data *bcon)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	int rc;

	wil_dbg_misc(wil, "%s()\n", __func__);

	if (wil_fix_bcon(wil, bcon)) {
		wil_dbg_misc(wil, "Fixed bcon\n");
		wil_print_bcon_data(bcon);
	}

	/* FW do not form regular beacon, so bcon IE's are not set
	 * For the DMG bcon, when it will be supported, bcon IE's will
	 * be reused; add something like:
	 * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
	 * bcon->beacon_ies);
	 */
	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
			bcon->proberesp_ies_len,
			bcon->proberesp_ies);
	if (rc) {
		wil_err(wil, "set_ie(PROBE_RESP) failed\n");
		return rc;
	}

	rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
			bcon->assocresp_ies_len,
			bcon->assocresp_ies);
	if (rc) {
		wil_err(wil, "set_ie(ASSOC_RESP) failed\n");
		return rc;
	}

	return 0;
}
Ejemplo n.º 2
0
int wil_p2p_search(struct wil6210_priv *wil,
		   struct cfg80211_scan_request *request)
{
	int rc;
	struct wil_p2p_info *p2p = &wil->p2p;

	wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);

	lockdep_assert_held(&wil->mutex);

	if (p2p->discovery_started) {
		wil_err(wil, "search failed. discovery already ongoing\n");
		rc = -EBUSY;
		goto out;
	}

	rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
	if (rc) {
		wil_err(wil, "wmi_p2p_cfg failed\n");
		goto out;
	}

	rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
	if (rc) {
		wil_err(wil, "wmi_set_ssid failed\n");
		goto out_stop;
	}

	/* Set application IE to probe request and probe response */
	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
			request->ie_len, request->ie);
	if (rc) {
		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
		goto out_stop;
	}

	/* supplicant doesn't provide Probe Response IEs. As a workaround -
	 * re-use Probe Request IEs
	 */
	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
			request->ie_len, request->ie);
	if (rc) {
		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
		goto out_stop;
	}

	rc = wmi_start_search(wil);
	if (rc) {
		wil_err(wil, "wmi_start_search failed\n");
		goto out_stop;
	}

	p2p->discovery_started = 1;
	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
	mod_timer(&p2p->discovery_timer,
		  jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));

out_stop:
	if (rc)
		wmi_stop_discovery(wil);

out:
	return rc;
}
Ejemplo n.º 3
0
static int wil_cfg80211_start_ap(struct wiphy *wiphy,
                                 struct net_device *ndev,
                                 struct cfg80211_ap_settings *info)
{
    int rc = 0;
    struct wil6210_priv *wil = wiphy_to_wil(wiphy);
    struct wireless_dev *wdev = ndev->ieee80211_ptr;
    struct ieee80211_channel *channel = info->chandef.chan;
    struct cfg80211_beacon_data *bcon = &info->beacon;
    u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);

    if (!channel) {
        wil_err(wil, "AP: No channel???\n");
        return -EINVAL;
    }

    wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
                 channel->center_freq, info->privacy ? "secure" : "open");
    print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
                         info->ssid, info->ssid_len);

    if (wil_fix_bcon(wil, bcon))
        wil_dbg_misc(wil, "Fixed bcon\n");

    mutex_lock(&wil->mutex);

    rc = wil_reset(wil);
    if (rc)
        goto out;

    /* Rx VRING. */
    rc = wil_rx_init(wil);
    if (rc)
        goto out;

    rc = wmi_set_ssid(wil, info->ssid_len, info->ssid);
    if (rc)
        goto out;

    /* MAC address - pre-requisite for other commands */
    wmi_set_mac_address(wil, ndev->dev_addr);

    /* IE's */
    /* bcon 'head IE's are not relevant for 60g band */
    /*
     * FW do not form regular beacon, so bcon IE's are not set
     * For the DMG bcon, when it will be supported, bcon IE's will
     * be reused; add something like:
     * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
     * bcon->beacon_ies);
     */
    wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
               bcon->proberesp_ies);
    wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
               bcon->assocresp_ies);

    wil->secure_pcp = info->privacy;

    rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
                       channel->hw_value);
    if (rc)
        goto out;


    netif_carrier_on(ndev);

out:
    mutex_unlock(&wil->mutex);
    return rc;
}
Ejemplo n.º 4
0
static int wil_cfg80211_connect(struct wiphy *wiphy,
                                struct net_device *ndev,
                                struct cfg80211_connect_params *sme)
{
    struct wil6210_priv *wil = wiphy_to_wil(wiphy);
    struct cfg80211_bss *bss;
    struct wmi_connect_cmd conn;
    const u8 *ssid_eid;
    const u8 *rsn_eid;
    int ch;
    int rc = 0;

    if (test_bit(wil_status_fwconnecting, &wil->status) ||
            test_bit(wil_status_fwconnected, &wil->status))
        return -EALREADY;

    bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
                           sme->ssid, sme->ssid_len,
                           WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
    if (!bss) {
        wil_err(wil, "Unable to find BSS\n");
        return -ENOENT;
    }

    ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
    if (!ssid_eid) {
        wil_err(wil, "No SSID\n");
        rc = -ENOENT;
        goto out;
    }

    rsn_eid = sme->ie ?
              cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
              NULL;
    if (rsn_eid) {
        if (sme->ie_len > WMI_MAX_IE_LEN) {
            rc = -ERANGE;
            wil_err(wil, "IE too large (%td bytes)\n",
                    sme->ie_len);
            goto out;
        }
        /*
         * For secure assoc, send:
         * (1) WMI_DELETE_CIPHER_KEY_CMD
         * (2) WMI_SET_APPIE_CMD
         */
        rc = wmi_del_cipher_key(wil, 0, bss->bssid);
        if (rc) {
            wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
            goto out;
        }
        /* WMI_SET_APPIE_CMD */
        rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
        if (rc) {
            wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
            goto out;
        }
    }

    /* WMI_CONNECT_CMD */
    memset(&conn, 0, sizeof(conn));
    switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
    case WLAN_CAPABILITY_DMG_TYPE_AP:
        conn.network_type = WMI_NETTYPE_INFRA;
        break;
    case WLAN_CAPABILITY_DMG_TYPE_PBSS:
        conn.network_type = WMI_NETTYPE_P2P;
        break;
    default:
        wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
                bss->capability);
        goto out;
    }
    if (rsn_eid) {
        conn.dot11_auth_mode = WMI_AUTH11_SHARED;
        conn.auth_mode = WMI_AUTH_WPA2_PSK;
        conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
        conn.pairwise_crypto_len = 16;
    } else {
        conn.dot11_auth_mode = WMI_AUTH11_OPEN;
        conn.auth_mode = WMI_AUTH_NONE;
    }

    conn.ssid_len = min_t(u8, ssid_eid[1], 32);
    memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);

    ch = bss->channel->hw_value;
    if (ch == 0) {
        wil_err(wil, "BSS at unknown frequency %dMhz\n",
                bss->channel->center_freq);
        rc = -EOPNOTSUPP;
        goto out;
    }
    conn.channel = ch - 1;

    memcpy(conn.bssid, bss->bssid, ETH_ALEN);
    memcpy(conn.dst_mac, bss->bssid, ETH_ALEN);

    set_bit(wil_status_fwconnecting, &wil->status);

    rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
    if (rc == 0) {
        /* Connect can take lots of time */
        mod_timer(&wil->connect_timer,
                  jiffies + msecs_to_jiffies(2000));
    } else {
        clear_bit(wil_status_fwconnecting, &wil->status);
    }

out:
    cfg80211_put_bss(wiphy, bss);

    return rc;
}
Ejemplo n.º 5
0
static int wil_cfg80211_scan(struct wiphy *wiphy,
			     struct cfg80211_scan_request *request)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct wireless_dev *wdev = wil->wdev;
	struct {
		struct wmi_start_scan_cmd cmd;
		u16 chnl[4];
	} __packed cmd;
	uint i, n;
	int rc;

	if (wil->scan_request) {
		wil_err(wil, "Already scanning\n");
		return -EAGAIN;
	}

	/* check we are client side */
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		break;
	default:
		return -EOPNOTSUPP;
	}

	/* FW don't support scan after connection attempt */
	if (test_bit(wil_status_dontscan, &wil->status)) {
		wil_err(wil, "Can't scan now\n");
		return -EBUSY;
	}

	wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
	wil->scan_request = request;
	mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);

	memset(&cmd, 0, sizeof(cmd));
	cmd.cmd.num_channels = 0;
	n = min(request->n_channels, 4U);
	for (i = 0; i < n; i++) {
		int ch = request->channels[i]->hw_value;

		if (ch == 0) {
			wil_err(wil,
				"Scan requested for unknown frequency %dMhz\n",
				request->channels[i]->center_freq);
			continue;
		}
		/* 0-based channel indexes */
		cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
		wil_dbg_misc(wil, "Scan for ch %d  : %d MHz\n", ch,
			     request->channels[i]->center_freq);
	}

	if (request->ie_len)
		print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET,
				     request->ie, request->ie_len);
	else
		wil_dbg_misc(wil, "Scan has no IE's\n");

	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len,
			request->ie);
	if (rc) {
		wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc);
		goto out;
	}

	rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
			cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));

out:
	if (rc) {
		del_timer_sync(&wil->scan_timer);
		wil->scan_request = NULL;
	}

	return rc;
}