Esempio n. 1
0
static int wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
	struct wireless_dev *wdev, const void  *data, int len)
{
	int err = 0;
	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
	dhd_pno_gscan_capabilities_t *reply = NULL;
	uint32 reply_len = 0;


	reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
	   DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
	if (!reply) {
		WL_ERR(("Could not get capabilities\n"));
		err = -EINVAL;
		return err;
	}

	err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
	        reply, reply_len);

	if (unlikely(err))
		WL_ERR(("Vendor Command reply failed ret:%d \n", err));

	kfree(reply);
	return err;
}
Esempio n. 2
0
s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
{
#ifndef DHD_SDALIGN
#define DHD_SDALIGN	32
#endif
	struct net_device *ndev;
	s32 err = 0;

	WL_TRACE(("In\n"));
	if (dhd_dongle_up) {
		WL_ERR(("Dongle is already up\n"));
		return err;
	}

	ndev = bcmcfg_to_prmry_ndev(cfg);

	err = wl_dongle_up(ndev);
	if (unlikely(err)) {
		WL_ERR(("wl_dongle_up failed\n"));
		goto default_conf_out;
	}
	dhd_dongle_up = true;

default_conf_out:

	return err;

}
static int wl_cfgvendor_get_feature_set(struct wiphy *wiphy,
	struct wireless_dev *wdev, const void  *data, int len)
{
	int err = 0;
	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
	int reply;

	reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));

	err =  wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
	        &reply, sizeof(int));

	if (unlikely(err))
		WL_ERR(("Vendor Command reply failed ret:%d \n", err));

	return err;
}
Esempio n. 4
0
s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg)
{
	struct net_device *ndev;
	s32 err = 0;

	WL_TRACE(("In\n"));
	if (!dhd_dongle_up) {
		WL_ERR(("Dongle is already down\n"));
		return err;
	}

	ndev = bcmcfg_to_prmry_ndev(cfg);
	wl_dongle_down(ndev);
	dhd_dongle_up = FALSE;
	return 0;
}
Esempio n. 5
0
static int wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
	struct wireless_dev *wdev, const void  *data, int len)
{
	int err = 0, type, band;
	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
	uint16 *reply = NULL;
	uint32 reply_len = 0, num_channels, mem_needed;
	struct sk_buff *skb;

	type = nla_type(data);

	if (type == GSCAN_ATTRIBUTE_BAND) {
		band = nla_get_u32(data);
	} else {
		return -1;
	}

	reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
	   DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);

	if (!reply) {
		WL_ERR(("Could not get channel list\n"));
		err = -EINVAL;
		return err;
	}
	num_channels =  reply_len/ sizeof(uint32);
	mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);

	/* Alloc the SKB for vendor_event */
	skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
	if (unlikely(!skb)) {
		WL_ERR(("skb alloc failed"));
		err = -ENOMEM;
		goto exit;
	}

	nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
	nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);

	err =  rtw_cfg80211_vendor_cmd_reply(skb);

	if (unlikely(err))
		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
exit:
	kfree(reply);
	return err;
}
Esempio n. 6
0
static int wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy,
	struct wireless_dev *wdev, const void *data, int len)
{
	int err = 0;
	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
	int type;
	u32 nodfs;

	type = nla_type(data);
	if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) {
		nodfs = nla_get_u32(data);
		err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs);
	} else {
		err = -1;
	}
	return err;
}
static int wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
	struct wireless_dev *wdev, const void  *data, int len)
{
	int err = 0;
	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
	struct sk_buff *skb;
	int *reply;
	int num, mem_needed, i;

	reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), &num);

	if (!reply) {
		WL_ERR(("Could not get feature list matrix\n"));
		err = -EINVAL;
		return err;
	}

	mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) +
	             ATTRIBUTE_U32_LEN;

	/* Alloc the SKB for vendor_event */
	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
	if (unlikely(!skb)) {
		WL_ERR(("skb alloc failed"));
		err = -ENOMEM;
		goto exit;
	}

	nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num);
	for (i = 0; i < num; i++) {
		nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]);
	}

	err =  cfg80211_vendor_cmd_reply(skb);

	if (unlikely(err))
		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
exit:
	kfree(reply);
	return err;
}
static int wl_cfgvendor_set_pno_mac_oui(struct wiphy *wiphy,
	struct wireless_dev *wdev, const void  *data, int len)
{
	int err = 0;
	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
	int type;
	uint8 pno_random_mac_oui[DOT11_OUI_LEN];

	type = nla_type(data);

	if (type == ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI) {
		memcpy(pno_random_mac_oui, nla_data(data), DOT11_OUI_LEN);

		err = dhd_dev_pno_set_mac_oui(bcmcfg_to_prmry_ndev(cfg), pno_random_mac_oui);

		if (unlikely(err))
			WL_ERR(("Bad OUI, could not set:%d \n", err));

	} else {
		err = -1;
	}

	return err;
}
Esempio n. 9
0
s32
wl_cfgnan_notify_nan_status(struct bcm_cfg80211 *cfg,
	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data)
{
	s32 ret = BCME_OK;
	u16 data_len;
	u32 event_num;
	s32 event_type;
	nan_event_hdr_t nan_hdr;
	wl_nan_tlv_data_t tlv_data;
	u8 *buf = NULL;
	u32 buf_len;
	u8 *ptr;
	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;

	if (!event || !data) {
		WL_ERR((" event data is NULL \n"));
		return -EINVAL;
	}

	event_type = ntoh32(event->event_type);
	event_num = ntoh32(event->reason);
	data_len = ntoh32(event->datalen);
	memset(&nan_hdr, 0, sizeof(nan_event_hdr_t));
	nan_hdr.event_subtype = event_num;

	WL_DBG((" nan event: type: %d num: %d len: %d \n",
		event_type, event_num, data_len));

	if (INVALID_NAN_EVENT(event_num)) {
		WL_ERR((" unsupported event, num: %d \n", event_num));
		return -EINVAL;
	}

	if (g_nan_debug) {
		WL_DBG((" event name: %s \n", nan_event_name[event_num]));
		WL_DBG((" event data: \n"));
		prhex(NULL, data, data_len);
	}

	/* unpack the tlvs */
	memset(&tlv_data, 0, sizeof(wl_nan_tlv_data_t));
	bcm_unpack_xtlv_buf(&tlv_data, data, data_len,
		wl_cfgnan_set_vars_cbfn);

	/*
	 * send as preformatted hex string
	 *
	 * EVENT_NAN <event_type> <tlv_hex_string>
	 */

	buf_len = NAN_IOCTL_BUF_SIZE;
	buf = ptr = kzalloc(buf_len, kflags);
	if (!buf) {
		WL_ERR((" memory allocation failed \n"));
		ret = -ENOMEM;
		goto fail;
	}

	switch (event_num) {
	case WL_NAN_EVENT_START:
	case WL_NAN_EVENT_JOIN:
	case WL_NAN_EVENT_STOP:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF,
			nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid));
		break;
	case WL_NAN_EVENT_ROLE:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s "ROLE_PREFIX "%d "
			CLUS_ID_PREFIX MACF, nan_event_str[event_num],
			tlv_data.nstatus.role, ETHER_TO_MACF(tlv_data.nstatus.cid));
		break;
	case WL_NAN_EVENT_DISCOVERY_RESULT:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d "
			SUB_ID_PREFIX"%d " MAC_ADDR_PREFIX MACF,
			nan_event_str[event_num], tlv_data.pub_id, tlv_data.sub_id,
			ETHER_TO_MACF(tlv_data.mac_addr));
		if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) {
			WL_DBG((" service info present \n"));
			if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) {
				WL_ERR((" service info length = %d\n",
					tlv_data.svc_info.dlen));
				WL_ERR((" insufficent buffer to copy service info \n"));
				ret = -EOVERFLOW;
				goto fail;
			}
			ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX);
			ptr += bcm_format_hex(ptr, tlv_data.svc_info.data,
				tlv_data.svc_info.dlen);
		} else {
			WL_DBG((" service info not present \n"));
		}

		if (tlv_data.vend_info.data && tlv_data.vend_info.dlen) {
			struct ether_addr *ea;
			u8 *data = tlv_data.vend_info.data;
			uint32 bitmap;
			u16 dlen = tlv_data.vend_info.dlen;
			chanspec_t chanspec;
			uint8 mapcontrol;
			uint8 proto;

			WL_DBG((" vendor info present \n"));
			if ((*data != NAN_ATTR_VENDOR_SPECIFIC) ||
				(dlen < NAN_VENDOR_HDR_SIZE)) {
				WL_ERR((" error in vendor info attribute \n"));
				ret = -EINVAL;
				goto fail;
			} else {
				WL_DBG((" vendor info not present \n"));
			}

			if (*(data + 6) == NAN_VENDOR_TYPE_RTT) {
				data += NAN_VENDOR_HDR_SIZE;
				ea = (struct ether_addr *)data;
				data += ETHER_ADDR_LEN;
				mapcontrol = *data++;
				proto = *data++;
				bitmap = *(uint32 *)data;
				data += 4;
				chanspec = *(chanspec_t *)data;
				ptr += sprintf(ptr, " "BITMAP_PREFIX"0x%x "CHAN_PREFIX"%d/%s",
					bitmap, wf_chspec_ctlchan(chanspec),
					wf_chspec_to_bw_str(chanspec));
				WL_DBG((" bitmap: 0x%x channel: %d bandwidth: %s \n", bitmap,
					wf_chspec_ctlchan(chanspec),
					wf_chspec_to_bw_str(chanspec)));
			}
		}
		break;
	case WL_NAN_EVENT_REPLIED:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d "
				MAC_ADDR_PREFIX MACF, nan_event_str[event_num],
				tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr));
		break;
	case WL_NAN_EVENT_TERMINATED:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d ",
			nan_event_str[event_num], tlv_data.pub_id);
		break;
	case WL_NAN_EVENT_RECEIVE:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " PUB_ID_PREFIX"%d "
				MAC_ADDR_PREFIX MACF, nan_event_str[event_num],
				tlv_data.pub_id, ETHER_TO_MACF(tlv_data.mac_addr));
		if (tlv_data.svc_info.data && tlv_data.svc_info.dlen) {
			WL_DBG((" service info present \n"));
			if ((strlen(ptr) + tlv_data.svc_info.dlen) >= buf_len) {
				WL_ERR((" service info length = %d\n",
					tlv_data.svc_info.dlen));
				WL_ERR((" insufficent buffer to copy service info \n"));
				ret = -EOVERFLOW;
				goto fail;
			}
			ptr += sprintf(ptr, " %s", SVC_INFO_PREFIX);
			ptr += bcm_format_hex(ptr, tlv_data.svc_info.data,
				tlv_data.svc_info.dlen);
		} else {
			WL_DBG((" service info not present \n"));
		}
		break;
	case WL_NAN_EVENT_SCAN_COMPLETE:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF,
			nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid));
		break;
	case WL_NAN_EVENT_STATUS_CHG:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF,
			nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid));
		break;
	case WL_NAN_EVENT_MERGE:
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " CLUS_ID_PREFIX MACF,
			nan_event_str[event_num], ETHER_TO_MACF(tlv_data.nstatus.cid));
		break;
	default:
		WL_ERR((" unknown event \n"));
		break;
	}

#ifdef WL_GENL
	/* send the preformatted string to the upper layer as event */
	WL_DBG((" formatted string for userspace: %s, len: %zu \n",
		buf, strlen(buf)));
	wl_genl_send_msg(bcmcfg_to_prmry_ndev(cfg), 0, buf, strlen(buf), 0, 0);
#endif /* WL_GENL */

fail:
	if (buf) {
		kfree(buf);
	}
	if (tlv_data.svc_info.data) {
		kfree(tlv_data.svc_info.data);
		tlv_data.svc_info.data = NULL;
		tlv_data.svc_info.dlen = 0;
	}
	if (tlv_data.vend_info.data) {
		kfree(tlv_data.vend_info.data);
		tlv_data.vend_info.data = NULL;
		tlv_data.vend_info.dlen = 0;
	}

	return ret;
}
Esempio n. 10
0
s32
wl_cfgnan_notify_proxd_status(struct bcm_cfg80211 *cfg,
	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data)
{
	s32 ret = BCME_OK;
	wl_nan_ranging_event_data_t *rdata;
	s32 status;
	u16 data_len;
	s32 event_type;
	s32 event_num;
	u8 *buf = NULL;
	u32 buf_len;
	u8 *ptr;
	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
	s32 i;

	if (!event || !data) {
		WL_ERR((" event data is NULL \n"));
		return -EINVAL;
	}

	status = ntoh32(event->reason);
	event_type = ntoh32(event->event_type);
	event_num = ntoh32(event->reason);
	data_len = ntoh32(event->datalen);

	WL_DBG((" proxd event: type: %d num: %d len: %d \n",
		event_type, event_num, data_len));

	if (INVALID_PROXD_EVENT(event_num)) {
		WL_ERR((" unsupported event, num: %d \n", event_num));
		return -EINVAL;
	}

	if (g_nan_debug) {
		WL_DBG((" event name: WLC_E_PROXD_NAN_EVENT \n"));
		WL_DBG((" event data: \n"));
		prhex(NULL, data, data_len);
	}

	if (data_len < sizeof(wl_nan_ranging_event_data_t)) {
		WL_ERR((" wrong data len \n"));
		return -EINVAL;
	}

	rdata = (wl_nan_ranging_event_data_t *)data;

	WL_DBG((" proxd event: count:%d success_count:%d mode:%d \n",
		rdata->count, rdata->success_count, rdata->mode));

	if (g_nan_debug) {
		prhex(" event data: ", data, data_len);
	}

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

	for (i = 0; i < rdata->count; i++) {
		if (&rdata->rr[i] == NULL) {
			ret = -EINVAL;
			goto fail;
		}

		ptr = buf;
		WL_DBG((" ranging data for mac:"MACDBG" \n",
			MAC2STRDBG(rdata->rr[i].ea.octet)));
		ptr += sprintf(buf, SUPP_EVENT_PREFIX"%s " MAC_ADDR_PREFIX MACF
			" "STATUS_PREFIX"%s", EVENT_RTT_STATUS_STR,
			ETHER_TO_MACF(rdata->rr[i].ea), (rdata->rr[i].status == 1) ?
			"success" : "fail");

		if (rdata->rr[i].status == 1) {
			/* add tsf and distance only if status is success */
			ptr += sprintf(ptr, " "TIMESTAMP_PREFIX"0x%x "
				DISTANCE_PREFIX"%d.%04d", rdata->rr[i].timestamp,
				rdata->rr[i].distance >> 4,
				((rdata->rr[i].distance & 0x0f) * 625));
		}

#ifdef WL_GENL
		/* send the preformatted string to the upper layer as event */
		WL_DBG((" formatted string for userspace: %s, len: %zu \n",
			buf, strlen(buf)));
		wl_genl_send_msg(bcmcfg_to_prmry_ndev(cfg), 0, buf, strlen(buf), 0, 0);
#endif /* WL_GENL */
	}
Esempio n. 11
0
static int wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
	struct wireless_dev *wdev, const void  *data, int len)
{
	int err = 0;
	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
	gscan_results_cache_t *results, *iter;
	uint32 reply_len, complete = 0, num_results_iter;
	int32 mem_needed;
	wifi_gscan_result_t *ptr;
	uint16 num_scan_ids, num_results;
	struct sk_buff *skb;
	struct nlattr *scan_hdr;

	dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
	dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
	results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
	             DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);

	if (!results) {
		WL_ERR(("No results to send %d\n", err));
		err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
		        results, 0);

		if (unlikely(err))
			WL_ERR(("Vendor Command reply failed ret:%d \n", err));
		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
		return err;
	}
	num_scan_ids = reply_len & 0xFFFF;
	num_results = (reply_len & 0xFFFF0000) >> 16;
	mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
	             (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
	             VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;

	if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
		mem_needed = (int32)NLMSG_DEFAULT_SIZE;
		complete = 0;
	} else {
		complete = 1;
	}

	WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed,
		(int)NLMSG_DEFAULT_SIZE));
	/* Alloc the SKB for vendor_event */
	skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
	if (unlikely(!skb)) {
		WL_ERR(("skb alloc failed"));
		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
		return -ENOMEM;
	}
	iter = results;

	nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, complete);

	mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);

	while (iter && ((mem_needed - GSCAN_BATCH_RESULT_HDR_LEN)  > 0)) {
		scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
		nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
		nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
		num_results_iter =
		    (mem_needed - GSCAN_BATCH_RESULT_HDR_LEN)/sizeof(wifi_gscan_result_t);

		if ((iter->tot_count - iter->tot_consumed) < num_results_iter)
			num_results_iter = iter->tot_count - iter->tot_consumed;

		nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
		if (num_results_iter) {
			ptr = &iter->results[iter->tot_consumed];
			iter->tot_consumed += num_results_iter;
			nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
			 num_results_iter * sizeof(wifi_gscan_result_t), ptr);
		}
		nla_nest_end(skb, scan_hdr);
		mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
		    (num_results_iter * sizeof(wifi_gscan_result_t));
		iter = iter->next;
	}

	dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
	dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));

	return rtw_cfg80211_vendor_cmd_reply(skb);
}