/*
 *  pack xtlv buffer from memory according to xtlv_desc_t
 */
int
bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items)
{
	int res = 0;
	void *ptlv = *tlv_buf;

	while (items->len != 0) {
		if ((res = bcm_pack_xtlv_entry(&ptlv,
			buflen, items->type,
			items->len, items->ptr) != BCME_OK)) {
			break;
		}
		items++;
	}
	*tlv_buf = ptlv; /* update the external pointer */
	return res;
}
Example #2
0
int
wl_cfgnan_transmit_handler(struct net_device *ndev,
	struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data)
{
	wl_nan_ioc_t *nanioc = NULL;
	void *pxtlv;
	s32 ret = BCME_OK;
	u16 start, end;
	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
	uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE;

	/*
	 * proceed only if mandatory arguments are present - subscriber id,
	 * publisher id, mac address
	 */
	if ((!cmd_data->sub_id) || (!cmd_data->pub_id) ||
		ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) {
		WL_ERR((" mandatory arguments are not present \n"));
		return -EINVAL;
	}

	nanioc = kzalloc(nanioc_size, kflags);
	if (!nanioc) {
		WL_ERR((" memory allocation failed \n"));
		return -ENOMEM;
	}

	/*
	 * command to test
	 *
	 * wl: wl nan trasnmit <sub_id> <pub_id> <mac_addr> -info <hex_string>
	 *
	 * wpa_cli: DRIVER NAN_TRANSMIT SUB_ID=<sub_id> PUB_ID=<pub_id>
	 *          MAC_ADDR=<mac_addr> SVC_INFO=<hex_string>
	 */

	/* nan transmit */
	start = end = NAN_IOCTL_BUF_SIZE;
	nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
	nanioc->id = htod16(WL_NAN_CMD_TRANSMIT);
	pxtlv = nanioc->data;

	ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_INSTANCE_ID,
		sizeof(wl_nan_instance_id_t), &cmd_data->sub_id);
	if (unlikely(ret)) {
		goto fail;
	}
	ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_REQUESTOR_ID,
		sizeof(wl_nan_instance_id_t), &cmd_data->pub_id);
	if (unlikely(ret)) {
		goto fail;
	}
	ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_ADDR,
		ETHER_ADDR_LEN, &cmd_data->mac_addr.octet);
	if (unlikely(ret)) {
		goto fail;
	}
	if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) {
		WL_DBG((" optional svc_info present, pack it \n"));
		ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
			&end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data);
		if (unlikely(ret)) {
			goto fail;
		}
	}

	nanioc->len = start - end;
	nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len;
	ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size,
		cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
	if (unlikely(ret)) {
		WL_ERR((" nan transmit failed, error = %d \n", ret));
		goto fail;
	} else {
		WL_DBG((" nan transmit successful \n"));
	}

fail:
	if (nanioc) {
		kfree(nanioc);
	}

	return ret;
}
Example #3
0
int
wl_cfgnan_pub_handler(struct net_device *ndev,
	struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data)
{
	wl_nan_ioc_t *nanioc = NULL;
	struct bcm_tlvbuf *tbuf = NULL;
	wl_nan_disc_params_t params;
	s32 ret = BCME_OK;
	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
	uint16 tbuf_size = BCM_XTLV_HDR_SIZE + sizeof(params);
	uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE;
	void *pxtlv;
	u16 start, end;

	/*
	 * proceed only if mandatory arguments are present - publisher id,
	 * service hash
	 */
	if ((!cmd_data->pub_id) || (!cmd_data->svc_hash.data) ||
		(!cmd_data->svc_hash.dlen)) {
		WL_ERR((" mandatory arguments are not present \n"));
		return -EINVAL;
	}

	nanioc = kzalloc(nanioc_size, kflags);
	if (!nanioc) {
		WL_ERR((" memory allocation failed \n"));
		return -ENOMEM;
	}

	tbuf = bcm_xtlv_buf_alloc(NULL, tbuf_size);
	if (!tbuf) {
		WL_ERR((" memory allocation failed \n"));
		ret = -ENOMEM;
		goto fail;
	}

	/*
	 * command to test
	 *
	 * wl: wl nan publish 10 NAN123 -info <hex_string
	 *     wl nan publish 10 NAN123 -info <hex_string -period 1 -ttl 0xffffffff
	 *
	 * wpa_cli: DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123
	 *          SVC_INFO=<hex_string>
	 *          DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123
	 *          SVC_INFO=<hex_string> PUB_PR=1 PUB_INT=0xffffffff
	 */

	/* nan publish */
	start = end = NAN_IOCTL_BUF_SIZE;
	nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
	nanioc->id = htod16(WL_NAN_CMD_PUBLISH);
	pxtlv = nanioc->data;

	/* disovery parameters */
	if (cmd_data->pub_pr) {
		params.period = cmd_data->pub_pr;
	} else {
		params.period = 1;
	}
	if (cmd_data->pub_int) {
		params.ttl = cmd_data->pub_int;
	} else {
		params.ttl = WL_NAN_TTL_UNTIL_CANCEL;
	}
	params.flags = WL_NAN_PUB_BOTH;
	params.instance_id = (wl_nan_instance_id_t)cmd_data->pub_id;
	memcpy((char *)params.svc_hash, cmd_data->svc_hash.data,
		cmd_data->svc_hash.dlen);
	ret = bcm_pack_xtlv_entry(&pxtlv,
		&end, WL_NAN_XTLV_SVC_PARAMS, sizeof(wl_nan_disc_params_t), &params);
	if (unlikely(ret)) {
		goto fail;
	}
	if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) {
		WL_DBG((" optional svc_info present, pack it \n"));
		ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
			&end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data);
		if (unlikely(ret)) {
			goto fail;
		}
	}

	nanioc->len = start - end;
	nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len;
	ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size,
		cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
	if (unlikely(ret)) {
		WL_ERR((" nan publish failed, error = %d \n", ret));
		goto fail;
	} else {
		WL_DBG((" nan publish successful \n"));
	}

fail:
	if (tbuf) {
		bcm_xtlv_buf_free(NULL, tbuf);
	}
	if (nanioc) {
		kfree(nanioc);
	}

	return ret;
}
Example #4
0
int
wl_cfgnan_stop_handler(struct net_device *ndev,
	struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data)
{
	wl_nan_ioc_t *nanioc = NULL;
	struct ether_addr cluster_id = ether_null;
	void *pxtlv;
	s32 ret = BCME_OK;
	u16 start, end;
	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
	uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE;
	uint8 nan_enable = FALSE;

	if (cfg->nan_running == false) {
		WL_DBG((" nan not running, do nothing \n"));
		return BCME_OK;
	}

	nanioc = kzalloc(nanioc_size, kflags);
	if (!nanioc) {
		WL_ERR((" memory allocation failed \n"));
		return -ENOMEM;
	}

	/*
	 * command to test
	 *
	 * wl: wl nan stop
	 *     wl nan 0
	 *
	 * wpa_cli: DRIVER NAN_STOP
	 */

	/* nan stop */

	start = end = NAN_IOCTL_BUF_SIZE;
	nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
	nanioc->id = htod16(WL_NAN_CMD_STOP);
	pxtlv = nanioc->data;
	ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID,
		ETHER_ADDR_LEN, &cluster_id);
	if (unlikely(ret)) {
		goto fail;
	}
	nanioc->len = start - end;
	nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len;
	ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size,
		cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
	if (unlikely(ret)) {
		WL_ERR((" nan stop failed, error = %d \n", ret));
		goto fail;
	} else {
		WL_DBG((" nan stop successful \n"));
	}

	/* nan disable */
	memset(nanioc, 0, nanioc_size);
	start = end = NAN_IOCTL_BUF_SIZE;
	nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
	nanioc->id = htod16(WL_NAN_CMD_ENABLE);
	pxtlv = nanioc->data;
	ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE,
		sizeof(uint8), &nan_enable);
	if (unlikely(ret)) {
		goto fail;
	}
	nanioc->len = start - end;
	nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len;
	ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size,
		cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
	if (unlikely(ret)) {
		WL_ERR((" nan disable failed, error = %d \n", ret));
		goto fail;
	} else {
		WL_DBG((" nan disable successful \n"));
	}

fail:
	if (nanioc) {
		kfree(nanioc);
	}

	return ret;
}
Example #5
0
int
wl_cfgnan_enable_events(struct net_device *ndev, struct bcm_cfg80211 *cfg)
{
	wl_nan_ioc_t *nanioc = NULL;
	void *pxtlv;
	u32 event_mask = 0;
	s32 ret = BCME_OK;
	u16 start, end;
	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
	uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE;

	nanioc = kzalloc(nanioc_size, kflags);
	if (!nanioc) {
		WL_ERR((" memory allocation failed \n"));
		return -ENOMEM;
	}

	ret = wl_add_remove_eventmsg(ndev, WLC_E_NAN, true);
	if (unlikely(ret)) {
		WL_ERR((" nan event enable failed, error = %d \n", ret));
		goto fail;
	}
	if (g_nan_debug) {
		/* enable all nan events */
		event_mask = NAN_EVENT_MASK_ALL;
	} else {
		/* enable only selected nan events to avoid unnecessary host wake up */
		event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_START);
		event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_JOIN);
		event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_DISCOVERY_RESULT);
		event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_RECEIVE);
		event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_TERMINATED);
		event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_STOP);
		event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_CLEAR_BIT);
		event_mask = htod32(event_mask);
	}

	start = end = NAN_IOCTL_BUF_SIZE;
	nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
	nanioc->id = htod16(WL_NAN_CMD_EVENT_MASK);
	pxtlv = nanioc->data;
	ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_EVENT_MASK,
		sizeof(uint32), &event_mask);
	if (unlikely(ret)) {
		goto fail;
	}
	nanioc->len = start - end;
	nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len;
	ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size,
		cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
	if (unlikely(ret)) {
		WL_ERR((" nan event selective enable failed, error = %d \n", ret));
		goto fail;
	} else {
		WL_DBG((" nan event selective enable successful \n"));
	}

	ret = wl_add_remove_eventmsg(ndev, WLC_E_PROXD, true);
	if (unlikely(ret)) {
		WL_ERR((" proxd event enable failed, error = %d \n", ret));
		goto fail;
	}

fail:
	if (nanioc) {
		kfree(nanioc);
	}

	return ret;
}
Example #6
0
int
wl_cfgnan_set_config_handler(struct net_device *ndev,
	struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data)
{
	wl_nan_ioc_t *nanioc = NULL;
	void *pxtlv;
	s32 ret = BCME_OK;
	u16 start, end;
	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
	uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE;

	nanioc = kzalloc(nanioc_size, kflags);
	if (!nanioc) {
		WL_ERR((" memory allocation failed \n"));
		return -ENOMEM;
	}

	/*
	 * command to test
	 *
	 * wl: wl nan <attr> <value> (wl nan role 1)
	 *
	 * wpa_cli: DRIVER NAN_CONFIG_SET ATTR=<attr> <value>...<value>
	 *
	 * wpa_cli: DRIVER NAN_SET_CONFIG ATTR=ATTR_ROLE ROLE=1
	 */

	/* nan set config */
	start = end = NAN_IOCTL_BUF_SIZE;
	nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
	nanioc->id = htod16(WL_NAN_CMD_ATTR);
	pxtlv = nanioc->data;

	switch (cmd_data->attr.type) {
	case WL_NAN_XTLV_ROLE:
		ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ROLE,
			sizeof(u32), &cmd_data->role);
		break;
	case WL_NAN_XTLV_MASTER_PREF:
		ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MASTER_PREF,
			sizeof(u16), &cmd_data->master_pref);
		break;
	case WL_NAN_XTLV_DW_LEN:
		ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_DW_LEN,
			sizeof(u16), &cmd_data->dw_len);
		break;
	case WL_NAN_XTLV_CLUSTER_ID:
	case WL_NAN_XTLV_IF_ADDR:
	case WL_NAN_XTLV_BCN_INTERVAL:
	case WL_NAN_XTLV_MAC_CHANSPEC:
	case WL_NAN_XTLV_MAC_TXRATE:
	default:
		ret = -EINVAL;
		break;
	}
	if (unlikely(ret)) {
		WL_ERR((" unsupported attribute, attr = %s (%d) \n",
			cmd_data->attr.name, cmd_data->attr.type));
		goto fail;
	}

	nanioc->len = start - end;
	nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len;
	ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size,
		cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
	if (unlikely(ret)) {
		WL_ERR((" nan set config failed, error = %d \n", ret));
		goto fail;
	} else {
		WL_DBG((" nan set config successful \n"));
	}

fail:
	if (nanioc) {
		kfree(nanioc);
	}

	return ret;
}