Exemple #1
0
static struct nlattr *
find_dump_kind(const struct nlmsghdr *n)
{
	struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
	struct nlattr *nla[TCAA_MAX + 1];
	struct nlattr *kind;

	if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX, NULL) < 0)
		return NULL;
	tb1 = nla[TCA_ACT_TAB];
	if (tb1 == NULL)
		return NULL;

	if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1),
		      NLMSG_ALIGN(nla_len(tb1)), NULL) < 0)
		return NULL;

	if (tb[1] == NULL)
		return NULL;
	if (nla_parse(tb2, TCA_ACT_MAX, nla_data(tb[1]),
		      nla_len(tb[1]), NULL) < 0)
		return NULL;
	kind = tb2[TCA_ACT_KIND];

	return kind;
}
Exemple #2
0
static int display_rx_statcs(struct nl_msg *msg, void *arg)
{
	struct nlattr *tb[NL80211_ATTR_MAX + 1];
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
	struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
	struct wl1271_radio_rx_statcs *prms;

	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		genlmsg_attrlen(gnlh, 0), NULL);

	if (!tb[NL80211_ATTR_TESTDATA]) {
		fprintf(stderr, "no data!\n");
		return NL_SKIP;
	}

	nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
		nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);

	prms =
		(struct wl1271_radio_rx_statcs *)
			nla_data(td[WL1271_TM_ATTR_DATA]);

	printf("\n\tTotal number of pkts\t- %d\n\tAccepted pkts\t\t- %d\n\t"
		"FCS error pkts\t\t- %d\n\tAddress mismatch pkts\t- %d\n\t"
		"Average SNR\t\t- % d dBm\n\tAverage RSSI\t\t- % d dBm\n\n",
		prms->base_pkt_id, prms->rx_path_statcs.nbr_rx_valid_pkts,
		prms->rx_path_statcs.nbr_rx_fcs_err_pkts,
		prms->rx_path_statcs.nbr_rx_plcp_err_pkts,
		(signed short)prms->rx_path_statcs.ave_snr/8,
		(signed short)prms->rx_path_statcs.ave_rssi/8);

	return NL_SKIP;
}
Exemple #3
0
static int calib_valid_handler(struct nl_msg *msg, void *arg)
{
	struct nlattr *tb[NL80211_ATTR_MAX + 1];
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
	struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
	struct wl1271_cmd_cal_p2g *prms;
#if 0
	int i; unsigned char *pc;
#endif
	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		genlmsg_attrlen(gnlh, 0), NULL);

	if (!tb[NL80211_ATTR_TESTDATA]) {
		fprintf(stderr, "no data!\n");
		return NL_SKIP;
	}

	nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
		nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);

	prms = (struct wl1271_cmd_cal_p2g *)nla_data(td[WL1271_TM_ATTR_DATA]);

	if (prms->radio_status) {
		fprintf(stderr, "Fail to calibrate ith radio status (%d)\n",
			(signed short)prms->radio_status);
		return 2;
	}
#if 0
	printf("%s> id %04x status %04x\ntest id %02x ver %08x len %04x=%d\n",
		__func__,
		prms->header.id, prms->header.status, prms->test.id,
		prms->ver, prms->len, prms->len);

		pc = (unsigned char *)prms->buf;
		printf("++++++++++++++++++++++++\n");
		for (i = 0; i < prms->len; i++) {
			if (i%0xf == 0)
				printf("\n");

			printf("%02x ", *(unsigned char *)pc);
			pc += 1;
		}
		printf("++++++++++++++++++++++++\n");
#endif
	if (prepare_nvs_file(prms, arg)) {
		fprintf(stderr, "Fail to prepare calibrated NVS file\n");
		return 2;
	}
#if 0
	printf("\n\tThe NVS file (%s) is ready\n\tCopy it to %s and "
		"reboot the system\n\n",
		NEW_NVS_NAME, CURRENT_NVS_NAME);
#endif
	return NL_SKIP;
}
// valid interface callback handler
static int iface_handler(struct nl_msg *msg, void *arg)
{
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];

	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);

	if (tb_msg[NL80211_ATTR_WIPHY])
	{
		char wiphy[IFNAMSIZ];
		sprintf(wiphy, "phy%d", nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]));

		// If selected physical interface matches the result, search for a monitor interface and copy the name
		if(strcmp(phy_name, wiphy) == 0)
		{
			if (tb_msg[NL80211_ATTR_IFTYPE] && tb_msg[NL80211_ATTR_IFNAME])
			{
				// If the interface type is monitor
				if(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]) == 6)
					strcpy(IF_name, nla_get_string(tb_msg[NL80211_ATTR_IFNAME]));
			}
		}
	}

	return NL_SKIP;
}
Exemple #5
0
static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
				 unsigned int len)
{
	struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
	struct z_stream_s *stream = &ctx->decomp_stream;
	struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
	int ret = 0;

	ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
	if (ret)
		return ret;

	zlib_decomp_exit(ctx);

	ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
				 ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
				 : DEF_WBITS;

	stream->workspace = vzalloc(zlib_inflate_workspacesize());
	if (!stream->workspace)
		return -ENOMEM;

	ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
	if (ret != Z_OK) {
		vfree(stream->workspace);
		stream->workspace = NULL;
		return -EINVAL;
	}

	return 0;
}
Exemple #6
0
static int nl80211_subscribe_cb(struct nl_msg *msg, void *arg)
{
	struct nl80211_group_conveyor *cv = arg;

	struct nlattr **attr = nl80211_parse(msg);
	struct nlattr *mgrpinfo[CTRL_ATTR_MCAST_GRP_MAX + 1];
	struct nlattr *mgrp;
	int mgrpidx;

	if (!attr[CTRL_ATTR_MCAST_GROUPS])
		return NL_SKIP;

	nla_for_each_nested(mgrp, attr[CTRL_ATTR_MCAST_GROUPS], mgrpidx)
	{
		nla_parse(mgrpinfo, CTRL_ATTR_MCAST_GRP_MAX,
		          nla_data(mgrp), nla_len(mgrp), NULL);

		if (mgrpinfo[CTRL_ATTR_MCAST_GRP_ID] &&
		    mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME] &&
		    !strncmp(nla_data(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME]),
		             cv->name, nla_len(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME])))
		{
			cv->id = nla_get_u32(mgrpinfo[CTRL_ATTR_MCAST_GRP_ID]);
			break;
		}
	}
Exemple #7
0
int mac80211_get_coverageclass(char *interface) {
	struct nlattr *tb[NL80211_ATTR_MAX + 1];
	struct nl_msg *msg;
	struct genlmsghdr *gnlh;
	int phy;
	unsigned char coverage=0;

	phy = mac80211_get_phyidx_by_vifname(interface);
	if (phy == -1) return 0;

	msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy);
	if (unl_genl_request_single(&unl, msg, &msg) < 0)
		return 0;
	if (!msg) return 0;
	gnlh=nlmsg_data(nlmsg_hdr(msg));
	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		  genlmsg_attrlen(gnlh, 0), NULL);
	if (tb[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
		coverage = nla_get_u8(tb[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
		/* See handle_distance() for an explanation where the '450' comes from */
		// printf("\tCoverage class: %d (up to %dm)\n", coverage, 450 * coverage);
	}
	// printf ("%d\n", coverage);
	nlmsg_free(msg);
	return coverage;
nla_put_failure:
	nlmsg_free(msg);
	return 0;
}
static int nl80211_iface_info_handler (struct nl_msg *msg, void *arg)
{
	struct nl80211_iface_info *info = arg;
	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
	struct nlattr *tb[NL80211_ATTR_MAX + 1];
                
	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
		return NL_SKIP;

	if (!tb[NL80211_ATTR_IFTYPE])
		return NL_SKIP;

	switch (nla_get_u32 (tb[NL80211_ATTR_IFTYPE])) {
	case NL80211_IFTYPE_ADHOC:
		info->mode = NM_802_11_MODE_ADHOC;
		break;
	case NL80211_IFTYPE_AP:
		info->mode = NM_802_11_MODE_AP;
		break;
	case NL80211_IFTYPE_STATION:
		info->mode = NM_802_11_MODE_INFRA;
		break;
	}
                          
	return NL_SKIP;
}
int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
{
	struct ath6kl *ar = wiphy_priv(wiphy);
	struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1];
        int err, buf_len;
	void *buf;

	err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len,
			ath6kl_tm_policy);
         
	if (err)
		return err;

	if (!tb[ATH6KL_TM_ATTR_CMD])
		return -EINVAL;

	switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) {
	case ATH6KL_TM_CMD_TCMD:
		if (!tb[ATH6KL_TM_ATTR_DATA])
			return -EINVAL;

		buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
		buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);

		ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len);

		return 0;

		break;
	default:
		return -EOPNOTSUPP;
	}
}
/* ----------------GET CMD WITH INT ARG REPLY-------------------- */
static int print_reply_rx_count_data(struct nl_msg *msg, void *arg)
{
	struct nlattr *tb_msg[NLNPI_ATTR_MAX + 1];
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
	unsigned int count[3];

	nla_parse(tb_msg, NLNPI_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		  genlmsg_attrlen(gnlh, 0), NULL);

	if (tb_msg[NLNPI_ATTR_REPLY_DATA]) {
		if (nla_len(tb_msg[NLNPI_ATTR_REPLY_DATA]) == 12) {
			memcpy(count, nla_data(tb_msg[NLNPI_ATTR_REPLY_DATA]),
			       sizeof(count));
			printf
			    ("ret: reg value: rx_end_count=%d rx_err_end_count=%d fcs_fail_count=%d :end\n",
			     count[0], count[1], count[2]);
		} else {
			printf("ret: Invild len %d :end\n",
			       nla_len(tb_msg[NLNPI_ATTR_REPLY_DATA]));
		}
	} else {
		printf("ret: Failed to get result! :end\n");
	}

	return NL_SKIP;
}
int LLStatsCommand::handleResponse(WifiEvent &reply)
{
    ALOGI("Got a LLStats message from Driver");
    unsigned i=0;
    u32 status;
    WifiVendorCommand::handleResponse(reply);

    // Parse the vendordata and get the attribute

    switch(mSubcmd)
    {
        case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR:
            {
                struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
                nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
                        (struct nlattr *)mVendorData,
                        mDataLen, NULL);
                ALOGI("Resp mask : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]));
                ALOGI("STOP resp : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP]));
                mClearRspParams.stats_clear_rsp_mask = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]);
                mClearRspParams.stop_rsp = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP]);
                break;
            }
        default :
            ALOGE("%s: Wrong LLStats subcmd received %d", __func__, mSubcmd);
    }
    return NL_SKIP;
}
static void get_wifi_iface_stats(wifi_iface_stat *stats, struct nlattr **tb_vendor)
{
    struct nlattr *wmmInfo;
    wifi_wmm_ac_stat *pWmmStats;
    int i=0, rem;

    stats->beacon_rx       = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX]);
    stats->mgmt_rx         = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX]);
    stats->mgmt_action_rx  = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX]);
    stats->mgmt_action_tx  = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX]);
    stats->rssi_mgmt       = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT]);
    stats->rssi_data       = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA]);
    stats->rssi_ack        = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK]);

    ALOGI("STATS IFACE: beaconRx : %u ", stats->beacon_rx);
    ALOGI("STATS IFACE: mgmtRx %u ", stats->mgmt_rx);
    ALOGI("STATS IFACE: mgmtActionRx  %u ", stats->mgmt_action_rx);
    ALOGI("STATS IFACE: mgmtActionTx %u ", stats->mgmt_action_tx);
    ALOGI("STATS IFACE: rssiMgmt %u ", stats->rssi_mgmt);
    ALOGI("STATS IFACE: rssiData %u ", stats->rssi_data);
    ALOGI("STATS IFACE: rssiAck  %u ", stats->rssi_ack);
    for (wmmInfo = (struct nlattr *) nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO]), rem = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO]);
            nla_ok(wmmInfo, rem);
            wmmInfo = nla_next(wmmInfo, &(rem)))
    {
        struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1];
        pWmmStats = (wifi_wmm_ac_stat *) ((u8 *)stats->ac + (i * sizeof(wifi_wmm_ac_stat)));
        nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(wmmInfo), nla_len(wmmInfo), NULL);
        get_wifi_wmm_ac_stat(pWmmStats, tb2);
    }
}
static void get_wifi_peer_info(wifi_peer_info *stats, struct nlattr **tb_vendor)
{
    u32 i = 0, len = 0;
    int rem;
    wifi_rate_stat * pRateStats;
    struct nlattr *rateInfo;
    stats->type                   = (wifi_peer_type)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE]);
    len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS]);
    len = ((sizeof(stats->peer_mac_address) <= len) ? sizeof(stats->peer_mac_address) : len);
    memcpy((void *)&stats->peer_mac_address[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS]),
            len);
    stats->capabilities           = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES]);

    stats->num_rate               = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]);

    ALOGI("STATS PEER_ALL : numPeers %u", stats->type);
    ALOGI("STATS PEER_ALL : peerMacAddress  %0x:%0x:%0x:%0x:%0x:%0x ",
            stats->peer_mac_address[0], stats->peer_mac_address[1],
            stats->peer_mac_address[2],stats->peer_mac_address[3],
            stats->peer_mac_address[4],stats->peer_mac_address[5]);
    ALOGI("STATS PEER_ALL : capabilities %0x", stats->capabilities);
    ALOGI("STATS PEER_ALL :  numRate %u", stats->num_rate);
    for (rateInfo = (struct nlattr *) nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO]), rem = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO]);
            nla_ok(rateInfo, rem);
            rateInfo = nla_next(rateInfo, &(rem)))
    {
        struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1];
        pRateStats = (wifi_rate_stat *) ((u8 *)stats->rate_stats + (i++ * sizeof(wifi_rate_stat)));

        nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(rateInfo), nla_len(rateInfo), NULL);
        get_wifi_rate_stat(pRateStats, tb2);
    }
}
Exemple #14
0
static int dump_mgmt_frame(struct nl_msg *msg, void *arg)
{
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];

	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		  genlmsg_attrlen(gnlh, 0), NULL);

	if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
		uint32_t freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
		printf("freq %u MHz\n", freq);
	}

	if (tb_msg[NL80211_ATTR_RX_SIGNAL_DBM]) {
		/* nl80211_send_mgmt sends signed dBm value as u32 */
		int dbm = nla_get_u32(tb_msg[NL80211_ATTR_RX_SIGNAL_DBM]);
		printf("rssi %d dBm\n", dbm);
	}

	if (tb_msg[NL80211_ATTR_FRAME]) {
		int len = nla_len(tb_msg[NL80211_ATTR_FRAME]);
		uint8_t *data = nla_data(tb_msg[NL80211_ATTR_FRAME]);
		iw_hexdump("mgmt", data, len);
	}

	return 0;
}
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
{
	struct wl1271 *wl = hw->priv;
	struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
	int err;

	err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
	if (err)
		return err;

	if (!tb[WL1271_TM_ATTR_CMD_ID])
		return -EINVAL;

	switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
	case WL1271_TM_CMD_TEST:
		return wl1271_tm_cmd_test(wl, tb);
	case WL1271_TM_CMD_INTERROGATE:
		return wl1271_tm_cmd_interrogate(wl, tb);
	case WL1271_TM_CMD_CONFIGURE:
		return wl1271_tm_cmd_configure(wl, tb);
	case WL1271_TM_CMD_SET_PLT_MODE:
		return wl1271_tm_cmd_set_plt_mode(wl, tb);
	case WL1271_TM_CMD_RECOVER:
		return wl1271_tm_cmd_recover(wl, tb);
	case WL1271_TM_CMD_GET_MAC:
		return wl12xx_tm_cmd_get_mac(wl, tb);
	default:
		return -EOPNOTSUPP;
	}
}
Exemple #16
0
static int ac_kmod_valid_handler(struct nl_msg* msg, void* data) {
	struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1];
	struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg));

	nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);

	return ac_kmod_event_handler(gnlh, tb_msg, data);
}
Exemple #17
0
/* Process one complete nfnetlink message. */
static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	const struct nfnl_callback *nc;
	const struct nfnetlink_subsystem *ss;
	int type, err;

#if 0
	if (security_netlink_recv(skb, CAP_NET_ADMIN))
		return -EPERM;
#endif	

	/* All the messages must at least contain nfgenmsg */
	if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg)))
		return 0;

	type = nlh->nlmsg_type;
replay:
	ss = nfnetlink_get_subsys(type);
	if (!ss) {
#ifdef CONFIG_MODULES
		nfnl_unlock();
		request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
		nfnl_lock();
		ss = nfnetlink_get_subsys(type);
		if (!ss)
#endif
			return -EINVAL;
	}

	nc = nfnetlink_find_client(type, ss);
	if (!nc)
		return -EINVAL;

	{
		int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
		u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
		u_int16_t attr_count = ss->cb[cb_id].attr_count;
		struct nlattr *cda[attr_count+1];

		if (likely(nlh->nlmsg_len >= min_len)) {
			struct nlattr *attr = (void *)nlh + NLMSG_ALIGN(min_len);
			int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);

			err = nla_parse(cda, attr_count, attr, attrlen,
					ss->cb[cb_id].policy);
			if (err < 0)
				return err;
		} else
			return -EINVAL;

		err = nc->call(nfnl, skb, nlh, (struct nfattr **)cda);
		if (err == -EAGAIN)
			goto replay;
		return err;
	}
}
int SoftapController::linkDumpCbHandler(struct nl_msg *msg, void *arg)
{
	struct nlattr *tb[NL80211_ATTR_MAX + 1];
	struct genlmsghdr *gnlh = (genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
	struct nlattr *bss[NL80211_BSS_MAX + 1];
	int *sta_freq = (int *)arg;

	// bah - cpp doesn't support C99 named initializers. do it manually
	memset(&link_bss_policy, 0, sizeof(link_bss_policy));
	link_bss_policy[NL80211_BSS_TSF].type = NLA_U64;
	link_bss_policy[NL80211_BSS_FREQUENCY].type = NLA_U32;
	//link_bss_policy[NL80211_BSS_BSSID] = { };
	link_bss_policy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16;
	link_bss_policy[NL80211_BSS_CAPABILITY].type = NLA_U16;
	//link_bss_policy[NL80211_BSS_INFORMATION_ELEMENTS] = { };
	link_bss_policy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32;
	link_bss_policy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8;
	link_bss_policy[NL80211_BSS_STATUS].type = NLA_U32;

	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		  genlmsg_attrlen(gnlh, 0), NULL);

	if (!tb[NL80211_ATTR_BSS]) {
		LOGD("bss info missing!");
		return NL_SKIP;
	}
	if (nla_parse_nested(bss, NL80211_BSS_MAX,
			     tb[NL80211_ATTR_BSS],
			     link_bss_policy)) {
		LOGD("failed to parse nested attributes!");
		return NL_SKIP;
	}

	if (!bss[NL80211_BSS_BSSID])
		return NL_SKIP;

	if (!bss[NL80211_BSS_STATUS])
		return NL_SKIP;

	switch (nla_get_u32(bss[NL80211_BSS_STATUS])) {
	case NL80211_BSS_STATUS_ASSOCIATED:
		break;
	case NL80211_BSS_STATUS_AUTHENTICATED:
	case NL80211_BSS_STATUS_IBSS_JOINED:
	default:
		return NL_SKIP;
	}

	/* only in the assoc case do we want more info from station get */
	if (bss[NL80211_BSS_FREQUENCY]) {
		*sta_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
		LOGD("sta freq: %d", *sta_freq);
	}

	return NL_SKIP;
}
static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
				 struct tipc_nl_compat_msg *msg)
{
	int err;
	struct sk_buff *doit_buf;
	struct sk_buff *trans_buf;
	struct nlattr **attrbuf;
	struct genl_info info;

	trans_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!trans_buf)
		return -ENOMEM;

	attrbuf = kmalloc_array(tipc_genl_family.maxattr + 1,
				sizeof(struct nlattr *),
				GFP_KERNEL);
	if (!attrbuf) {
		err = -ENOMEM;
		goto trans_out;
	}

	doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!doit_buf) {
		err = -ENOMEM;
		goto attrbuf_out;
	}

	memset(&info, 0, sizeof(info));
	info.attrs = attrbuf;

	rtnl_lock();
	err = (*cmd->transcode)(cmd, trans_buf, msg);
	if (err)
		goto doit_out;

	err = nla_parse(attrbuf, tipc_genl_family.maxattr,
			(const struct nlattr *)trans_buf->data,
			trans_buf->len, NULL, NULL);
	if (err)
		goto doit_out;

	doit_buf->sk = msg->dst_sk;

	err = (*cmd->doit)(doit_buf, &info);
doit_out:
	rtnl_unlock();

	kfree_skb(doit_buf);
attrbuf_out:
	kfree(attrbuf);
trans_out:
	kfree_skb(trans_buf);

	return err;
}
Exemple #20
0
static int print_iface_handler(struct nl_msg *msg, void *arg)
{
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
	struct nlattr *tb_msg[NL802154_ATTR_MAX + 1];
	unsigned int *wpan_phy = arg;
	const char *indent = "";

	nla_parse(tb_msg, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		  genlmsg_attrlen(gnlh, 0), NULL);

	if (wpan_phy && tb_msg[NL802154_ATTR_WPAN_PHY]) {
		unsigned int thiswpan_phy = nla_get_u32(tb_msg[NL802154_ATTR_WPAN_PHY]);
		indent = "\t";
		if (*wpan_phy != thiswpan_phy)
			printf("phy#%d\n", thiswpan_phy);
		*wpan_phy = thiswpan_phy;
	}

	if (tb_msg[NL802154_ATTR_IFNAME])
		printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL802154_ATTR_IFNAME]));
	else
		printf("%sUnnamed/non-netdev interface\n", indent);

	if (tb_msg[NL802154_ATTR_IFINDEX])
		printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL802154_ATTR_IFINDEX]));
	if (tb_msg[NL802154_ATTR_WPAN_DEV])
		printf("%s\twpan_dev 0x%llx\n", indent,
		       (unsigned long long)nla_get_u64(tb_msg[NL802154_ATTR_WPAN_DEV]));
	if (tb_msg[NL802154_ATTR_EXTENDED_ADDR])
		printf("%s\textended_addr 0x%016" PRIx64 "\n", indent,
		       le64toh(nla_get_u64(tb_msg[NL802154_ATTR_EXTENDED_ADDR])));
	if (tb_msg[NL802154_ATTR_SHORT_ADDR])
		printf("%s\tshort_addr 0x%04x\n", indent,
		       le16toh(nla_get_u16(tb_msg[NL802154_ATTR_SHORT_ADDR])));
	if (tb_msg[NL802154_ATTR_PAN_ID])
		printf("%s\tpan_id 0x%04x\n", indent,
		       le16toh(nla_get_u16(tb_msg[NL802154_ATTR_PAN_ID])));
	if (tb_msg[NL802154_ATTR_IFTYPE])
		printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL802154_ATTR_IFTYPE])));
	if (tb_msg[NL802154_ATTR_MAX_FRAME_RETRIES])
		printf("%s\tmax_frame_retries %d\n", indent, nla_get_s8(tb_msg[NL802154_ATTR_MAX_FRAME_RETRIES]));
	if (tb_msg[NL802154_ATTR_MIN_BE])
		printf("%s\tmin_be %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MIN_BE]));
	if (tb_msg[NL802154_ATTR_MAX_BE])
		printf("%s\tmax_be %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MAX_BE]));
	if (tb_msg[NL802154_ATTR_MAX_CSMA_BACKOFFS])
		printf("%s\tmax_csma_backoffs %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MAX_CSMA_BACKOFFS]));
	if (tb_msg[NL802154_ATTR_LBT_MODE])
		printf("%s\tlbt %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_LBT_MODE]));
	if (tb_msg[NL802154_ATTR_ACKREQ_DEFAULT])
		printf("%s\tackreq_default %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_ACKREQ_DEFAULT]));

	return NL_SKIP;
}
Exemple #21
0
static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
			       unsigned int len)
{
	struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
	struct z_stream_s *stream = &ctx->comp_stream;
	struct nlattr *tb[ZLIB_COMP_MAX + 1];
	int window_bits, mem_level;
	size_t workspacesize;
	int ret;

	ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
	if (ret)
		return ret;

	zlib_comp_exit(ctx);

		window_bits = tb[ZLIB_COMP_WINDOWBITS]
					? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
					: MAX_WBITS;
		mem_level = tb[ZLIB_COMP_MEMLEVEL]
					? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
					: DEF_MEM_LEVEL;

	workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);

	stream->workspace = vmalloc(workspacesize);
	if (!stream->workspace)
		return -ENOMEM;

	memset(stream->workspace, 0, workspacesize);
	ret = zlib_deflateInit2(stream,
				tb[ZLIB_COMP_LEVEL]
					? nla_get_u32(tb[ZLIB_COMP_LEVEL])
					: Z_DEFAULT_COMPRESSION,
				tb[ZLIB_COMP_METHOD]
					? nla_get_u32(tb[ZLIB_COMP_METHOD])
					: Z_DEFLATED,
				tb[ZLIB_COMP_WINDOWBITS]
					? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
					: MAX_WBITS,
				tb[ZLIB_COMP_MEMLEVEL]
					? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
					: DEF_MEM_LEVEL,
				tb[ZLIB_COMP_STRATEGY]
					? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
					: Z_DEFAULT_STRATEGY);
	if (ret != Z_OK) {
		vfree(stream->workspace);
		stream->workspace = NULL;
		return -EINVAL;
	}

	return 0;
}
Exemple #22
0
/**
 * Parse Generic Netlink message including attributes
 * @arg nlh		Pointer to Netlink message header
 * @arg hdrlen		Length of user header
 * @arg tb		Array to store parsed attributes
 * @arg maxtype		Maximum attribute id expected
 * @arg policy		Attribute validation policy
 *
 * Verifies the validity of the Netlink and Generic Netlink headers using
 * genlmsg_valid_hdr() and calls nla_parse() on the message payload to
 * parse eventual attributes.
 *
 * @par Example:
 * @code
 * struct nlattr *attrs[MY_TYPE_MAX+1];
 *
 * if ((err = genlsmg_parse(nlmsg_nlh(msg), sizeof(struct my_hdr), attrs,
 *                          MY_TYPE_MAX, attr_policy)) < 0)
 * 	// ERROR
 * @endcode
 *
 * @see genlmsg_valid_hdr()
 * @see genlmsg_validate()
 * @see nla_parse()
 *
 * @return 0 on success or a negative error code.
 */
int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
		  int maxtype, struct nla_policy *policy)
{
	struct genlmsghdr *ghdr;

	if (!genlmsg_valid_hdr(nlh, hdrlen))
		return -NLE_MSG_TOOSHORT;

	ghdr = nlmsg_data(nlh);
	return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
			 genlmsg_attrlen(ghdr, hdrlen), policy);
}
static int
parse_reply (struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *n = nlmsg_hdr (msg);
	struct nlattr *tb[XFRMA_MAX + 1];
	struct xfrm_userpolicy_info *xpinfo = NULL;

	if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) {
		g_warning ("msg type %d not NEWPOLICY", n->nlmsg_type);
		return NL_SKIP;
	}

	/* Netlink message header is followed by 'struct xfrm_userpolicy_info' and
	 * then the attributes.
	 */

	if (!nlmsg_valid_hdr (n, sizeof (struct xfrm_userpolicy_info))) {
		g_warning ("msg too short");
		return -NLE_MSG_TOOSHORT;
	}

	xpinfo = nlmsg_data (n);
	if (nla_parse (tb, XFRMA_MAX,
	               nlmsg_attrdata (n, sizeof (struct xfrm_userpolicy_info)),
	               nlmsg_attrlen (n, sizeof (struct xfrm_userpolicy_info)),
	               NULL) < 0) {
		g_warning ("failed to parse attributes");
		return NL_SKIP;
	}

	if (tb[XFRMA_TMPL]) {
		int attrlen = nla_len (tb[XFRMA_TMPL]);
		struct xfrm_user_tmpl *list = nla_data (tb[XFRMA_TMPL]);
		int i;

		xfrm_selector_print (&xpinfo->sel);

		for (i = 0; i < attrlen / sizeof (struct xfrm_user_tmpl); i++) {
			struct xfrm_user_tmpl *tmpl = &list[i];
			char buf[INET6_ADDRSTRLEN];

			g_print ("    tmpl ");

			inet_ntop (tmpl->family, (gpointer) &tmpl->saddr, buf, sizeof (buf));
			g_print ("src %s ", buf);

			inet_ntop (tmpl->family, &tmpl->id.daddr, buf, sizeof (buf));
			g_print ("dst %s\n", buf);
		}
	}

	return NL_OK;
}
Exemple #24
0
int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
{
	struct ath6kl *ar = wiphy_priv(wiphy);
	struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1];
	int err, buf_len, reply_len;
	struct sk_buff *skb;
	void *buf;

	err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len,
			ath6kl_tm_policy);
	if (err)
		return err;

	if (!tb[ATH6KL_TM_ATTR_CMD])
		return -EINVAL;

	switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) {
	case ATH6KL_TM_CMD_TCMD:
		if (!tb[ATH6KL_TM_ATTR_DATA])
			return -EINVAL;

		buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
		buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);

		ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len);

		return 0;

		break;
	case ATH6KL_TM_CMD_RX_REPORT:
		if (!tb[ATH6KL_TM_ATTR_DATA])
			return -EINVAL;

		buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
		buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);

		reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN);
		skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len);
		if (!skb)
			return -ENOMEM;

		err = ath6kl_tm_rx_report(ar, buf, buf_len, skb);
		if (err < 0) {
			kfree_skb(skb);
			return err;
		}

		return cfg80211_testmode_reply(skb);
	default:
		return -EOPNOTSUPP;
	}
}
Exemple #25
0
//scan netlink messages are nested (and may even be multipart) (see nl80211.c line 2591: nl80211_send_bss)
int CNL80211::parseNlScanResult(nl_msg * msg) {
	struct nlattr * attr_buffer[NL80211_ATTR_MAX + 1];
	struct nlmsghdr * msg_hdr = nlmsg_hdr(msg);
	struct genlmsghdr * msg_header = (struct genlmsghdr *) nlmsg_data(msg_hdr);
	struct nlattr * bss_buffer[NL80211_BSS_MAX + 1]; //bss = basic service set
	ScanResult scanresult;
	//This is the struct to check the validity of the attributes. See enum nl80211_bss
	struct nla_policy bss_policy[NL80211_BSS_MAX + 1];
	bss_policy[NL80211_BSS_TSF].type = NLA_U64;
	bss_policy[NL80211_BSS_FREQUENCY].type = NLA_U32;
	bss_policy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16;
	bss_policy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32;
	bss_policy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8;

	if (msg_hdr->nlmsg_flags & NLM_F_MULTI)
		qDebug() << "netlink: Mutlipart message";

	//Parse the complete message
	nla_parse(attr_buffer, NL80211_ATTR_MAX, genlmsg_attrdata(msg_header, 0), genlmsg_attrlen(msg_header, 0), NULL);

	if (!attr_buffer[NL80211_ATTR_BSS]) { //Check if BSS
		return NL_SKIP;
	}
	//Parse the nested attributes. this is where the scan results are
	if (nla_parse_nested(bss_buffer, NL80211_BSS_MAX, attr_buffer[NL80211_ATTR_BSS], bss_policy)) {
		return NL_SKIP;
	}

	if (!bss_buffer[NL80211_BSS_BSSID])
		return NL_SKIP;

	scanresult.bssid = libnutcommon::MacAddress((ether_addr*)(bss_buffer[NL80211_BSS_BSSID]));
	scanresult.signal.bssid = scanresult.bssid;
	
	if (bss_buffer[NL80211_BSS_FREQUENCY])
		scanresult.freq = nla_get_u32(bss_buffer[NL80211_BSS_FREQUENCY]);

	if (bss_buffer[NL80211_BSS_SIGNAL_MBM]) {
		scanresult.signal.type = WSR_RCPI;
		scanresult.signal.quality.value = nla_get_u32(bss_buffer[NL80211_BSS_SIGNAL_MBM])/100;
	}
	if (bss_buffer[NL80211_BSS_SIGNAL_UNSPEC]) {
		scanresult.signal.type = WSR_UNKNOWN;
		scanresult.signal.quality.value = nla_get_u8(bss_buffer[NL80211_BSS_SIGNAL_UNSPEC]);
	}
// 	if (bss_buffer[NL80211_BSS_INFORMATION_ELEMENTS])
// 		print_ies(nla_data(bss_buffer[NL80211_BSS_INFORMATION_ELEMENTS]),
// 			  nla_len(bss_buffer[NL80211_BSS_INFORMATION_ELEMENTS]),
// 			  params->unknown, params->type);
	m_scanResults.push_back(scanresult);
	return NL_SKIP;
}
Exemple #26
0
static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
		      const struct nla_policy *policy, int len)
{
	int nested_len = nla_len(nla) - NLA_ALIGN(len);

	if (nested_len < 0)
		return -EINVAL;
	if (nested_len >= nla_attr_size(0))
		return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len),
				 nested_len, policy);
	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
	return 0;
}
Exemple #27
0
static int cb_kmod_create_iface(struct nl_msg* msg, void* data) {
	struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1];
	struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg));
	uint32_t* ifindex = (uint32_t*)data;

	nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);

	if (tb_msg[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]) {
		*ifindex = nla_get_u32(tb_msg[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]);
	}

	return NL_SKIP;
}
Exemple #28
0
static int event_handler(struct nl_msg *msg, void *arg)
{
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
	int cmd = gnlh->cmd;
	uint8_t *pos;
	int i;

        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);

	switch (gnlh->cmd) {
		case NL80211_CMD_FRAME:
			if (tb[NL80211_ATTR_FRAME] && nla_len(tb[NL80211_ATTR_FRAME])) {
				pos = nla_data(tb[NL80211_ATTR_FRAME]);
				if (*(pos + 24) == 0x20) {
					switch (*(pos + 25)) {
						case MPATH_PREQ:
							printf("Path Request Frame ");
							break;
						case MPATH_PREP:
							printf("Path Reply Frame ");
							break;
						case MPATH_PERR:
							printf("Path Error Frame ");
							break;
					}
					printf("from %02x:%02x:%02x:%02x:%02x:%02x\n",
							*(pos + 10), *(pos + 11),
							*(pos + 12), *(pos + 13),
							*(pos + 14), *(pos + 15));
				}
				printf("----------\n");
				printf("frame hexdump: ");
				for (i=0; i<nla_len(tb[NL80211_ATTR_FRAME]); i++) {
					if (!(i%20)) printf("\n");
					printf("%02x ", *pos++);
				}
				printf("\n----------\n\n");
			}
			break;
		case NL80211_CMD_NEW_STATION:
			printf("NL80211_CMD_NEW_STATION :)\n");
			break;
		default:
			printf("Ignored event\n");
			break;
	}

	return NL_SKIP;
}
Exemple #29
0
int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
		      struct netlink_callback *cb,
		      void *data, int len)
{
	struct nlattr *tb[IWL_TM_ATTR_MAX];
	struct iwl_priv *priv = hw->priv;
	int result;
	u32 cmd;

	if (cb->args[3]) {
		/* offset by 1 since commands start at 0 */
		cmd = cb->args[3] - 1;
	} else {
		result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
				iwl_testmode_gnl_msg_policy);
		if (result) {
			IWL_DEBUG_INFO(priv,
			       "Error parsing the gnl message : %d\n", result);
			return result;
		}

		/* IWL_TM_ATTR_COMMAND is absolutely mandatory */
		if (!tb[IWL_TM_ATTR_COMMAND]) {
			IWL_DEBUG_INFO(priv,
				"Error finding testmode command type\n");
			return -ENOMSG;
		}
		cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
		cb->args[3] = cmd + 1;
	}

	/* in case multiple accesses to the device happens */
	mutex_lock(&priv->shrd->mutex);
	switch (cmd) {
	case IWL_TM_CMD_APP2DEV_READ_TRACE:
		IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
		result = iwl_testmode_trace_dump(hw, tb, skb, cb);
		break;
	case IWL_TM_CMD_APP2DEV_DUMP_SRAM:
		IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n");
		result = iwl_testmode_sram_dump(hw, tb, skb, cb);
		break;
	default:
		result = -EINVAL;
		break;
	}

	mutex_unlock(&priv->shrd->mutex);
	return result;
}
static int protocol_feature_handler(struct nl_msg *msg, void *arg)
{
	u32 *feat = arg;
	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));

	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		  genlmsg_attrlen(gnlh, 0), NULL);

	if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
		*feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);

	return NL_SKIP;
}