brintos

brintos / linux-shallow public Read only

0
0
Text · 16.8 KiB · ca4fecc Raw
677 lines · c
1// SPDX-License-Identifier: ISC2/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */3 4#include <linux/random.h>5#include "mt76.h"6 7const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {8	[MT76_TM_ATTR_RESET] = { .type = NLA_FLAG },9	[MT76_TM_ATTR_STATE] = { .type = NLA_U8 },10	[MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },11	[MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },12	[MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },13	[MT76_TM_ATTR_TX_RATE_NSS] = { .type = NLA_U8 },14	[MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 },15	[MT76_TM_ATTR_TX_RATE_SGI] = { .type = NLA_U8 },16	[MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 },17	[MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 },18	[MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 },19	[MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 },20	[MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 },21	[MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },22	[MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED },23	[MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 },24	[MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 },25	[MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },26	[MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },27	[MT76_TM_ATTR_DRV_DATA] = { .type = NLA_NESTED },28};29EXPORT_SYMBOL_GPL(mt76_tm_policy);30 31void mt76_testmode_tx_pending(struct mt76_phy *phy)32{33	struct mt76_testmode_data *td = &phy->test;34	struct mt76_dev *dev = phy->dev;35	struct mt76_wcid *wcid = &dev->global_wcid;36	struct sk_buff *skb = td->tx_skb;37	struct mt76_queue *q;38	u16 tx_queued_limit;39	int qid;40 41	if (!skb || !td->tx_pending)42		return;43 44	qid = skb_get_queue_mapping(skb);45	q = phy->q_tx[qid];46 47	tx_queued_limit = td->tx_queued_limit ? td->tx_queued_limit : 1000;48 49	spin_lock_bh(&q->lock);50 51	while (td->tx_pending > 0 &&52	       td->tx_queued - td->tx_done < tx_queued_limit &&53	       q->queued < q->ndesc / 2) {54		int ret;55 56		ret = dev->queue_ops->tx_queue_skb(phy, q, qid, skb_get(skb),57						   wcid, NULL);58		if (ret < 0)59			break;60 61		td->tx_pending--;62		td->tx_queued++;63	}64 65	dev->queue_ops->kick(dev, q);66 67	spin_unlock_bh(&q->lock);68}69 70static u3271mt76_testmode_max_mpdu_len(struct mt76_phy *phy, u8 tx_rate_mode)72{73	switch (tx_rate_mode) {74	case MT76_TM_TX_MODE_HT:75		return IEEE80211_MAX_MPDU_LEN_HT_7935;76	case MT76_TM_TX_MODE_VHT:77	case MT76_TM_TX_MODE_HE_SU:78	case MT76_TM_TX_MODE_HE_EXT_SU:79	case MT76_TM_TX_MODE_HE_TB:80	case MT76_TM_TX_MODE_HE_MU:81		if (phy->sband_5g.sband.vht_cap.cap &82		    IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991)83			return IEEE80211_MAX_MPDU_LEN_VHT_7991;84		return IEEE80211_MAX_MPDU_LEN_VHT_11454;85	case MT76_TM_TX_MODE_CCK:86	case MT76_TM_TX_MODE_OFDM:87	default:88		return IEEE80211_MAX_FRAME_LEN;89	}90}91 92static void93mt76_testmode_free_skb(struct mt76_phy *phy)94{95	struct mt76_testmode_data *td = &phy->test;96 97	dev_kfree_skb(td->tx_skb);98	td->tx_skb = NULL;99}100 101int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len)102{103#define MT_TXP_MAX_LEN	4095104	u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |105		 IEEE80211_FCTL_FROMDS;106	struct mt76_testmode_data *td = &phy->test;107	struct sk_buff **frag_tail, *head;108	struct ieee80211_tx_info *info;109	struct ieee80211_hdr *hdr;110	u32 max_len, head_len;111	int nfrags, i;112 113	max_len = mt76_testmode_max_mpdu_len(phy, td->tx_rate_mode);114	if (len > max_len)115		len = max_len;116	else if (len < sizeof(struct ieee80211_hdr))117		len = sizeof(struct ieee80211_hdr);118 119	nfrags = len / MT_TXP_MAX_LEN;120	head_len = nfrags ? MT_TXP_MAX_LEN : len;121 122	if (len > IEEE80211_MAX_FRAME_LEN)123		fc |= IEEE80211_STYPE_QOS_DATA;124 125	head = alloc_skb(head_len, GFP_KERNEL);126	if (!head)127		return -ENOMEM;128 129	hdr = __skb_put_zero(head, sizeof(*hdr));130	hdr->frame_control = cpu_to_le16(fc);131	memcpy(hdr->addr1, td->addr[0], ETH_ALEN);132	memcpy(hdr->addr2, td->addr[1], ETH_ALEN);133	memcpy(hdr->addr3, td->addr[2], ETH_ALEN);134	skb_set_queue_mapping(head, IEEE80211_AC_BE);135	get_random_bytes(__skb_put(head, head_len - sizeof(*hdr)),136			 head_len - sizeof(*hdr));137 138	info = IEEE80211_SKB_CB(head);139	info->flags = IEEE80211_TX_CTL_INJECTED |140		      IEEE80211_TX_CTL_NO_ACK |141		      IEEE80211_TX_CTL_NO_PS_BUFFER;142 143	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx);144	frag_tail = &skb_shinfo(head)->frag_list;145 146	for (i = 0; i < nfrags; i++) {147		struct sk_buff *frag;148		u16 frag_len;149 150		if (i == nfrags - 1)151			frag_len = len % MT_TXP_MAX_LEN;152		else153			frag_len = MT_TXP_MAX_LEN;154 155		frag = alloc_skb(frag_len, GFP_KERNEL);156		if (!frag) {157			mt76_testmode_free_skb(phy);158			dev_kfree_skb(head);159			return -ENOMEM;160		}161 162		get_random_bytes(__skb_put(frag, frag_len), frag_len);163		head->len += frag->len;164		head->data_len += frag->len;165 166		*frag_tail = frag;167		frag_tail = &(*frag_tail)->next;168	}169 170	mt76_testmode_free_skb(phy);171	td->tx_skb = head;172 173	return 0;174}175EXPORT_SYMBOL(mt76_testmode_alloc_skb);176 177static int178mt76_testmode_tx_init(struct mt76_phy *phy)179{180	struct mt76_testmode_data *td = &phy->test;181	struct ieee80211_tx_info *info;182	struct ieee80211_tx_rate *rate;183	u8 max_nss = hweight8(phy->antenna_mask);184	int ret;185 186	ret = mt76_testmode_alloc_skb(phy, td->tx_mpdu_len);187	if (ret)188		return ret;189 190	if (td->tx_rate_mode > MT76_TM_TX_MODE_VHT)191		goto out;192 193	if (td->tx_antenna_mask)194		max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask));195 196	info = IEEE80211_SKB_CB(td->tx_skb);197	rate = &info->control.rates[0];198	rate->count = 1;199	rate->idx = td->tx_rate_idx;200 201	switch (td->tx_rate_mode) {202	case MT76_TM_TX_MODE_CCK:203		if (phy->chandef.chan->band != NL80211_BAND_2GHZ)204			return -EINVAL;205 206		if (rate->idx > 4)207			return -EINVAL;208		break;209	case MT76_TM_TX_MODE_OFDM:210		if (phy->chandef.chan->band != NL80211_BAND_2GHZ)211			break;212 213		if (rate->idx > 8)214			return -EINVAL;215 216		rate->idx += 4;217		break;218	case MT76_TM_TX_MODE_HT:219		if (rate->idx > 8 * max_nss &&220			!(rate->idx == 32 &&221			  phy->chandef.width >= NL80211_CHAN_WIDTH_40))222			return -EINVAL;223 224		rate->flags |= IEEE80211_TX_RC_MCS;225		break;226	case MT76_TM_TX_MODE_VHT:227		if (rate->idx > 9)228			return -EINVAL;229 230		if (td->tx_rate_nss > max_nss)231			return -EINVAL;232 233		ieee80211_rate_set_vht(rate, td->tx_rate_idx, td->tx_rate_nss);234		rate->flags |= IEEE80211_TX_RC_VHT_MCS;235		break;236	default:237		break;238	}239 240	if (td->tx_rate_sgi)241		rate->flags |= IEEE80211_TX_RC_SHORT_GI;242 243	if (td->tx_rate_ldpc)244		info->flags |= IEEE80211_TX_CTL_LDPC;245 246	if (td->tx_rate_stbc)247		info->flags |= IEEE80211_TX_CTL_STBC;248 249	if (td->tx_rate_mode >= MT76_TM_TX_MODE_HT) {250		switch (phy->chandef.width) {251		case NL80211_CHAN_WIDTH_40:252			rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;253			break;254		case NL80211_CHAN_WIDTH_80:255			rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;256			break;257		case NL80211_CHAN_WIDTH_80P80:258		case NL80211_CHAN_WIDTH_160:259			rate->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH;260			break;261		default:262			break;263		}264	}265out:266	return 0;267}268 269static void270mt76_testmode_tx_start(struct mt76_phy *phy)271{272	struct mt76_testmode_data *td = &phy->test;273	struct mt76_dev *dev = phy->dev;274 275	td->tx_queued = 0;276	td->tx_done = 0;277	td->tx_pending = td->tx_count;278	mt76_worker_schedule(&dev->tx_worker);279}280 281static void282mt76_testmode_tx_stop(struct mt76_phy *phy)283{284	struct mt76_testmode_data *td = &phy->test;285	struct mt76_dev *dev = phy->dev;286 287	mt76_worker_disable(&dev->tx_worker);288 289	td->tx_pending = 0;290 291	mt76_worker_enable(&dev->tx_worker);292 293	wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued,294			   MT76_TM_TIMEOUT * HZ);295 296	mt76_testmode_free_skb(phy);297}298 299static inline void300mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx)301{302	td->param_set[idx / 32] |= BIT(idx % 32);303}304 305static inline bool306mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx)307{308	return td->param_set[idx / 32] & BIT(idx % 32);309}310 311static void312mt76_testmode_init_defaults(struct mt76_phy *phy)313{314	struct mt76_testmode_data *td = &phy->test;315 316	if (td->tx_mpdu_len > 0)317		return;318 319	td->tx_mpdu_len = 1024;320	td->tx_count = 1;321	td->tx_rate_mode = MT76_TM_TX_MODE_OFDM;322	td->tx_rate_nss = 1;323 324	memcpy(td->addr[0], phy->macaddr, ETH_ALEN);325	memcpy(td->addr[1], phy->macaddr, ETH_ALEN);326	memcpy(td->addr[2], phy->macaddr, ETH_ALEN);327}328 329static int330__mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state)331{332	enum mt76_testmode_state prev_state = phy->test.state;333	struct mt76_dev *dev = phy->dev;334	int err;335 336	if (prev_state == MT76_TM_STATE_TX_FRAMES)337		mt76_testmode_tx_stop(phy);338 339	if (state == MT76_TM_STATE_TX_FRAMES) {340		err = mt76_testmode_tx_init(phy);341		if (err)342			return err;343	}344 345	err = dev->test_ops->set_state(phy, state);346	if (err) {347		if (state == MT76_TM_STATE_TX_FRAMES)348			mt76_testmode_tx_stop(phy);349 350		return err;351	}352 353	if (state == MT76_TM_STATE_TX_FRAMES)354		mt76_testmode_tx_start(phy);355	else if (state == MT76_TM_STATE_RX_FRAMES) {356		memset(&phy->test.rx_stats, 0, sizeof(phy->test.rx_stats));357	}358 359	phy->test.state = state;360 361	return 0;362}363 364int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state)365{366	struct mt76_testmode_data *td = &phy->test;367	struct ieee80211_hw *hw = phy->hw;368 369	if (state == td->state && state == MT76_TM_STATE_OFF)370		return 0;371 372	if (state > MT76_TM_STATE_OFF &&373	    (!test_bit(MT76_STATE_RUNNING, &phy->state) ||374	     !(hw->conf.flags & IEEE80211_CONF_MONITOR)))375		return -ENOTCONN;376 377	if (state != MT76_TM_STATE_IDLE &&378	    td->state != MT76_TM_STATE_IDLE) {379		int ret;380 381		ret = __mt76_testmode_set_state(phy, MT76_TM_STATE_IDLE);382		if (ret)383			return ret;384	}385 386	return __mt76_testmode_set_state(phy, state);387 388}389EXPORT_SYMBOL(mt76_testmode_set_state);390 391static int392mt76_tm_get_u8(struct nlattr *attr, u8 *dest, u8 min, u8 max)393{394	u8 val;395 396	if (!attr)397		return 0;398 399	val = nla_get_u8(attr);400	if (val < min || val > max)401		return -EINVAL;402 403	*dest = val;404	return 0;405}406 407int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,408		      void *data, int len)409{410	struct mt76_phy *phy = hw->priv;411	struct mt76_dev *dev = phy->dev;412	struct mt76_testmode_data *td = &phy->test;413	struct nlattr *tb[NUM_MT76_TM_ATTRS];414	u32 state;415	int err;416	int i;417 418	if (!dev->test_ops)419		return -EOPNOTSUPP;420 421	err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,422				   mt76_tm_policy, NULL);423	if (err)424		return err;425 426	err = -EINVAL;427 428	mutex_lock(&dev->mutex);429 430	if (tb[MT76_TM_ATTR_RESET]) {431		mt76_testmode_set_state(phy, MT76_TM_STATE_OFF);432		memset(td, 0, sizeof(*td));433	}434 435	mt76_testmode_init_defaults(phy);436 437	if (tb[MT76_TM_ATTR_TX_COUNT])438		td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]);439 440	if (tb[MT76_TM_ATTR_TX_RATE_IDX])441		td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]);442 443	if (mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_MODE], &td->tx_rate_mode,444			   0, MT76_TM_TX_MODE_MAX) ||445	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss,446			   1, hweight8(phy->antenna_mask)) ||447	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 2) ||448	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) ||449	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_STBC], &td->tx_rate_stbc, 0, 1) ||450	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_LTF], &td->tx_ltf, 0, 2) ||451	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA],452			   &td->tx_antenna_mask, 0, 0xff) ||453	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_SPE_IDX], &td->tx_spe_idx, 0, 27) ||454	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE],455			   &td->tx_duty_cycle, 0, 99) ||456	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],457			   &td->tx_power_control, 0, 1))458		goto out;459 460	if (tb[MT76_TM_ATTR_TX_LENGTH]) {461		u32 val = nla_get_u32(tb[MT76_TM_ATTR_TX_LENGTH]);462 463		if (val > mt76_testmode_max_mpdu_len(phy, td->tx_rate_mode) ||464		    val < sizeof(struct ieee80211_hdr))465			goto out;466 467		td->tx_mpdu_len = val;468	}469 470	if (tb[MT76_TM_ATTR_TX_IPG])471		td->tx_ipg = nla_get_u32(tb[MT76_TM_ATTR_TX_IPG]);472 473	if (tb[MT76_TM_ATTR_TX_TIME])474		td->tx_time = nla_get_u32(tb[MT76_TM_ATTR_TX_TIME]);475 476	if (tb[MT76_TM_ATTR_FREQ_OFFSET])477		td->freq_offset = nla_get_u32(tb[MT76_TM_ATTR_FREQ_OFFSET]);478 479	if (tb[MT76_TM_ATTR_STATE]) {480		state = nla_get_u32(tb[MT76_TM_ATTR_STATE]);481		if (state > MT76_TM_STATE_MAX)482			goto out;483	} else {484		state = td->state;485	}486 487	if (tb[MT76_TM_ATTR_TX_POWER]) {488		struct nlattr *cur;489		int idx = 0;490		int rem;491 492		nla_for_each_nested(cur, tb[MT76_TM_ATTR_TX_POWER], rem) {493			if (nla_len(cur) != 1 ||494			    idx >= ARRAY_SIZE(td->tx_power))495				goto out;496 497			td->tx_power[idx++] = nla_get_u8(cur);498		}499	}500 501	if (tb[MT76_TM_ATTR_MAC_ADDRS]) {502		struct nlattr *cur;503		int idx = 0;504		int rem;505 506		nla_for_each_nested(cur, tb[MT76_TM_ATTR_MAC_ADDRS], rem) {507			if (nla_len(cur) != ETH_ALEN || idx >= 3)508				goto out;509 510			memcpy(td->addr[idx], nla_data(cur), ETH_ALEN);511			idx++;512		}513	}514 515	if (dev->test_ops->set_params) {516		err = dev->test_ops->set_params(phy, tb, state);517		if (err)518			goto out;519	}520 521	for (i = MT76_TM_ATTR_STATE; i < ARRAY_SIZE(tb); i++)522		if (tb[i])523			mt76_testmode_param_set(td, i);524 525	err = 0;526	if (tb[MT76_TM_ATTR_STATE])527		err = mt76_testmode_set_state(phy, state);528 529out:530	mutex_unlock(&dev->mutex);531 532	return err;533}534EXPORT_SYMBOL(mt76_testmode_cmd);535 536static int537mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg)538{539	struct mt76_testmode_data *td = &phy->test;540	struct mt76_dev *dev = phy->dev;541	u64 rx_packets = 0;542	u64 rx_fcs_error = 0;543	int i;544 545	if (dev->test_ops->dump_stats) {546		int ret;547 548		ret = dev->test_ops->dump_stats(phy, msg);549		if (ret)550			return ret;551	}552 553	for (i = 0; i < ARRAY_SIZE(td->rx_stats.packets); i++) {554		rx_packets += td->rx_stats.packets[i];555		rx_fcs_error += td->rx_stats.fcs_error[i];556	}557 558	if (nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_PENDING, td->tx_pending) ||559	    nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_QUEUED, td->tx_queued) ||560	    nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_DONE, td->tx_done) ||561	    nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets,562			      MT76_TM_STATS_ATTR_PAD) ||563	    nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error,564			      MT76_TM_STATS_ATTR_PAD))565		return -EMSGSIZE;566 567	return 0;568}569 570int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,571		       struct netlink_callback *cb, void *data, int len)572{573	struct mt76_phy *phy = hw->priv;574	struct mt76_dev *dev = phy->dev;575	struct mt76_testmode_data *td = &phy->test;576	struct nlattr *tb[NUM_MT76_TM_ATTRS] = {};577	int err = 0;578	void *a;579	int i;580 581	if (!dev->test_ops)582		return -EOPNOTSUPP;583 584	if (cb->args[2]++ > 0)585		return -ENOENT;586 587	if (data) {588		err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,589					   mt76_tm_policy, NULL);590		if (err)591			return err;592	}593 594	mutex_lock(&dev->mutex);595 596	if (tb[MT76_TM_ATTR_STATS]) {597		err = -EINVAL;598 599		a = nla_nest_start(msg, MT76_TM_ATTR_STATS);600		if (a) {601			err = mt76_testmode_dump_stats(phy, msg);602			nla_nest_end(msg, a);603		}604 605		goto out;606	}607 608	mt76_testmode_init_defaults(phy);609 610	err = -EMSGSIZE;611	if (nla_put_u32(msg, MT76_TM_ATTR_STATE, td->state))612		goto out;613 614	if (dev->test_mtd.name &&615	    (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) ||616	     nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset)))617		goto out;618 619	if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||620	    nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, td->tx_mpdu_len) ||621	    nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) ||622	    nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, td->tx_rate_nss) ||623	    nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) ||624	    nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||625	    nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) ||626	    nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||627	    (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&628	     nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||629	    (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&630	     nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) ||631	    (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_SPE_IDX) &&632	     nla_put_u8(msg, MT76_TM_ATTR_TX_SPE_IDX, td->tx_spe_idx)) ||633	    (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_DUTY_CYCLE) &&634	     nla_put_u8(msg, MT76_TM_ATTR_TX_DUTY_CYCLE, td->tx_duty_cycle)) ||635	    (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_IPG) &&636	     nla_put_u32(msg, MT76_TM_ATTR_TX_IPG, td->tx_ipg)) ||637	    (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_TIME) &&638	     nla_put_u32(msg, MT76_TM_ATTR_TX_TIME, td->tx_time)) ||639	    (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) &&640	     nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) ||641	    (mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) &&642	     nla_put_u8(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset)))643		goto out;644 645	if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) {646		a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER);647		if (!a)648			goto out;649 650		for (i = 0; i < ARRAY_SIZE(td->tx_power); i++)651			if (nla_put_u8(msg, i, td->tx_power[i]))652				goto out;653 654		nla_nest_end(msg, a);655	}656 657	if (mt76_testmode_param_present(td, MT76_TM_ATTR_MAC_ADDRS)) {658		a = nla_nest_start(msg, MT76_TM_ATTR_MAC_ADDRS);659		if (!a)660			goto out;661 662		for (i = 0; i < 3; i++)663			if (nla_put(msg, i, ETH_ALEN, td->addr[i]))664				goto out;665 666		nla_nest_end(msg, a);667	}668 669	err = 0;670 671out:672	mutex_unlock(&dev->mutex);673 674	return err;675}676EXPORT_SYMBOL(mt76_testmode_dump);677