brintos

brintos / linux-shallow public Read only

0
0
Text · 19.3 KiB · eae93ef Raw
759 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2021 pureLiFi4 */5 6#include <linux/netdevice.h>7#include <linux/etherdevice.h>8#include <linux/slab.h>9#include <linux/usb.h>10#include <linux/jiffies.h>11#include <net/ieee80211_radiotap.h>12 13#include "chip.h"14#include "mac.h"15#include "usb.h"16 17static const struct ieee80211_rate plfxlc_rates[] = {18	{ .bitrate = 10,19		.hw_value = PURELIFI_CCK_RATE_1M,20		.flags = 0 },21	{ .bitrate = 20,22		.hw_value = PURELIFI_CCK_RATE_2M,23		.hw_value_short = PURELIFI_CCK_RATE_2M24			| PURELIFI_CCK_PREA_SHORT,25		.flags = IEEE80211_RATE_SHORT_PREAMBLE },26	{ .bitrate = 55,27		.hw_value = PURELIFI_CCK_RATE_5_5M,28		.hw_value_short = PURELIFI_CCK_RATE_5_5M29			| PURELIFI_CCK_PREA_SHORT,30		.flags = IEEE80211_RATE_SHORT_PREAMBLE },31	{ .bitrate = 110,32		.hw_value = PURELIFI_CCK_RATE_11M,33		.hw_value_short = PURELIFI_CCK_RATE_11M34			| PURELIFI_CCK_PREA_SHORT,35		.flags = IEEE80211_RATE_SHORT_PREAMBLE },36	{ .bitrate = 60,37		.hw_value = PURELIFI_OFDM_RATE_6M,38		.flags = 0 },39	{ .bitrate = 90,40		.hw_value = PURELIFI_OFDM_RATE_9M,41		.flags = 0 },42	{ .bitrate = 120,43		.hw_value = PURELIFI_OFDM_RATE_12M,44		.flags = 0 },45	{ .bitrate = 180,46		.hw_value = PURELIFI_OFDM_RATE_18M,47		.flags = 0 },48	{ .bitrate = 240,49		.hw_value = PURELIFI_OFDM_RATE_24M,50		.flags = 0 },51	{ .bitrate = 360,52		.hw_value = PURELIFI_OFDM_RATE_36M,53		.flags = 0 },54	{ .bitrate = 480,55		.hw_value = PURELIFI_OFDM_RATE_48M,56		.flags = 0 },57	{ .bitrate = 540,58		.hw_value = PURELIFI_OFDM_RATE_54M,59		.flags = 0 }60};61 62static const struct ieee80211_channel plfxlc_channels[] = {63	{ .center_freq = 2412, .hw_value = 1 },64	{ .center_freq = 2417, .hw_value = 2 },65	{ .center_freq = 2422, .hw_value = 3 },66	{ .center_freq = 2427, .hw_value = 4 },67	{ .center_freq = 2432, .hw_value = 5 },68	{ .center_freq = 2437, .hw_value = 6 },69	{ .center_freq = 2442, .hw_value = 7 },70	{ .center_freq = 2447, .hw_value = 8 },71	{ .center_freq = 2452, .hw_value = 9 },72	{ .center_freq = 2457, .hw_value = 10 },73	{ .center_freq = 2462, .hw_value = 11 },74	{ .center_freq = 2467, .hw_value = 12 },75	{ .center_freq = 2472, .hw_value = 13 },76	{ .center_freq = 2484, .hw_value = 14 },77};78 79int plfxlc_mac_preinit_hw(struct ieee80211_hw *hw, const u8 *hw_address)80{81	SET_IEEE80211_PERM_ADDR(hw, hw_address);82	return 0;83}84 85int plfxlc_mac_init_hw(struct ieee80211_hw *hw)86{87	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);88	struct plfxlc_chip *chip = &mac->chip;89	int r;90 91	r = plfxlc_chip_init_hw(chip);92	if (r) {93		dev_warn(plfxlc_mac_dev(mac), "init hw failed (%d)\n", r);94		return r;95	}96 97	dev_dbg(plfxlc_mac_dev(mac), "irq_disabled (%d)\n", irqs_disabled());98	regulatory_hint(hw->wiphy, "00");99	return r;100}101 102void plfxlc_mac_release(struct plfxlc_mac *mac)103{104	plfxlc_chip_release(&mac->chip);105	lockdep_assert_held(&mac->lock);106}107 108int plfxlc_op_start(struct ieee80211_hw *hw)109{110	plfxlc_hw_mac(hw)->chip.usb.initialized = 1;111	return 0;112}113 114void plfxlc_op_stop(struct ieee80211_hw *hw, bool suspend)115{116	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);117 118	clear_bit(PURELIFI_DEVICE_RUNNING, &mac->flags);119}120 121int plfxlc_restore_settings(struct plfxlc_mac *mac)122{123	int beacon_interval, beacon_period;124	struct sk_buff *beacon;125 126	spin_lock_irq(&mac->lock);127	beacon_interval = mac->beacon.interval;128	beacon_period = mac->beacon.period;129	spin_unlock_irq(&mac->lock);130 131	if (mac->type != NL80211_IFTYPE_ADHOC)132		return 0;133 134	if (mac->vif) {135		beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0);136		if (beacon) {137			/*beacon is hardcoded in firmware */138			kfree_skb(beacon);139			/* Returned skb is used only once and lowlevel140			 * driver is responsible for freeing it.141			 */142		}143	}144 145	plfxlc_set_beacon_interval(&mac->chip, beacon_interval,146				   beacon_period, mac->type);147 148	spin_lock_irq(&mac->lock);149	mac->beacon.last_update = jiffies;150	spin_unlock_irq(&mac->lock);151 152	return 0;153}154 155static void plfxlc_mac_tx_status(struct ieee80211_hw *hw,156				 struct sk_buff *skb,157				 int ackssi,158				 struct tx_status *tx_status)159{160	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);161	int success = 1;162 163	ieee80211_tx_info_clear_status(info);164	if (tx_status)165		success = !tx_status->failure;166 167	if (success)168		info->flags |= IEEE80211_TX_STAT_ACK;169	else170		info->flags &= ~IEEE80211_TX_STAT_ACK;171 172	info->status.ack_signal = 50;173	ieee80211_tx_status_irqsafe(hw, skb);174}175 176void plfxlc_mac_tx_to_dev(struct sk_buff *skb, int error)177{178	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);179	struct ieee80211_hw *hw = info->rate_driver_data[0];180	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);181	struct sk_buff_head *q = NULL;182 183	ieee80211_tx_info_clear_status(info);184	skb_pull(skb, sizeof(struct plfxlc_ctrlset));185 186	if (unlikely(error ||187		     (info->flags & IEEE80211_TX_CTL_NO_ACK))) {188		ieee80211_tx_status_irqsafe(hw, skb);189		return;190	}191 192	q = &mac->ack_wait_queue;193 194	skb_queue_tail(q, skb);195	while (skb_queue_len(q)/* > PURELIFI_MAC_MAX_ACK_WAITERS*/) {196		plfxlc_mac_tx_status(hw, skb_dequeue(q),197				     mac->ack_pending ?198				     mac->ack_signal : 0,199				     NULL);200		mac->ack_pending = 0;201	}202}203 204static int plfxlc_fill_ctrlset(struct plfxlc_mac *mac, struct sk_buff *skb)205{206	unsigned int frag_len = skb->len;207	struct plfxlc_ctrlset *cs;208	u32 temp_payload_len = 0;209	unsigned int tmp;210	u32 temp_len = 0;211 212	if (skb_headroom(skb) < sizeof(struct plfxlc_ctrlset)) {213		dev_dbg(plfxlc_mac_dev(mac), "Not enough hroom(1)\n");214		return 1;215	}216 217	cs = (void *)skb_push(skb, sizeof(struct plfxlc_ctrlset));218	temp_payload_len = frag_len;219	temp_len = temp_payload_len +220		  sizeof(struct plfxlc_ctrlset) -221		  sizeof(cs->id) - sizeof(cs->len);222 223	/* Data packet lengths must be multiple of four bytes and must224	 * not be a multiple of 512 bytes. First, it is attempted to225	 * append the data packet in the tailroom of the skb. In rare226	 * occasions, the tailroom is too small. In this case, the227	 * content of the packet is shifted into the headroom of the skb228	 * by memcpy. Headroom is allocated at startup (below in this229	 * file). Therefore, there will be always enough headroom. The230	 * call skb_headroom is an additional safety which might be231	 * dropped.232	 */233	/* check if 32 bit aligned and align data */234	tmp = skb->len & 3;235	if (tmp) {236		if (skb_tailroom(skb) < (3 - tmp)) {237			if (skb_headroom(skb) >= 4 - tmp) {238				u8 len;239				u8 *src_pt;240				u8 *dest_pt;241 242				len = skb->len;243				src_pt = skb->data;244				dest_pt = skb_push(skb, 4 - tmp);245				memmove(dest_pt, src_pt, len);246			} else {247				return -ENOBUFS;248			}249		} else {250			skb_put(skb, 4 - tmp);251		}252		temp_len += 4 - tmp;253	}254 255	/* check if not multiple of 512 and align data */256	tmp = skb->len & 0x1ff;257	if (!tmp) {258		if (skb_tailroom(skb) < 4) {259			if (skb_headroom(skb) >= 4) {260				u8 len = skb->len;261				u8 *src_pt = skb->data;262				u8 *dest_pt = skb_push(skb, 4);263 264				memmove(dest_pt, src_pt, len);265			} else {266				/* should never happen because267				 * sufficient headroom was reserved268				 */269				return -ENOBUFS;270			}271		} else {272			skb_put(skb, 4);273		}274		temp_len += 4;275	}276 277	cs->id = cpu_to_be32(USB_REQ_DATA_TX);278	cs->len = cpu_to_be32(temp_len);279	cs->payload_len_nw = cpu_to_be32(temp_payload_len);280 281	return 0;282}283 284static void plfxlc_op_tx(struct ieee80211_hw *hw,285			 struct ieee80211_tx_control *control,286			 struct sk_buff *skb)287{288	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);289	struct plfxlc_header *plhdr = (void *)skb->data;290	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);291	struct plfxlc_usb *usb = &mac->chip.usb;292	unsigned long flags;293	int r;294 295	r = plfxlc_fill_ctrlset(mac, skb);296	if (r)297		goto fail;298 299	info->rate_driver_data[0] = hw;300 301	if (plhdr->frametype  == IEEE80211_FTYPE_DATA) {302		u8 *dst_mac = plhdr->dmac;303		u8 sidx;304		bool found = false;305		struct plfxlc_usb_tx *tx = &usb->tx;306 307		for (sidx = 0; sidx < MAX_STA_NUM; sidx++) {308			if (!(tx->station[sidx].flag & STATION_CONNECTED_FLAG))309				continue;310			if (memcmp(tx->station[sidx].mac, dst_mac, ETH_ALEN))311				continue;312			found = true;313			break;314		}315 316		/* Default to broadcast address for unknown MACs */317		if (!found)318			sidx = STA_BROADCAST_INDEX;319 320		/* Stop OS from sending packets, if the queue is half full */321		if (skb_queue_len(&tx->station[sidx].data_list) > 60)322			ieee80211_stop_queues(plfxlc_usb_to_hw(usb));323 324		/* Schedule packet for transmission if queue is not full */325		if (skb_queue_len(&tx->station[sidx].data_list) > 256)326			goto fail;327		skb_queue_tail(&tx->station[sidx].data_list, skb);328		plfxlc_send_packet_from_data_queue(usb);329 330	} else {331		spin_lock_irqsave(&usb->tx.lock, flags);332		r = plfxlc_usb_wreq_async(&mac->chip.usb, skb->data, skb->len,333					  USB_REQ_DATA_TX, plfxlc_tx_urb_complete, skb);334		spin_unlock_irqrestore(&usb->tx.lock, flags);335		if (r)336			goto fail;337	}338	return;339 340fail:341	dev_kfree_skb(skb);342}343 344static int plfxlc_filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,345			     struct ieee80211_rx_status *stats)346{347	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);348	struct sk_buff_head *q;349	int i, position = 0;350	unsigned long flags;351	struct sk_buff *skb;352	bool found = false;353 354	if (!ieee80211_is_ack(rx_hdr->frame_control))355		return 0;356 357	dev_dbg(plfxlc_mac_dev(mac), "ACK Received\n");358 359	/* code based on zy driver, this logic may need fix */360	q = &mac->ack_wait_queue;361	spin_lock_irqsave(&q->lock, flags);362 363	skb_queue_walk(q, skb) {364		struct ieee80211_hdr *tx_hdr;365 366		position++;367 368		if (mac->ack_pending && skb_queue_is_first(q, skb))369			continue;370		if (mac->ack_pending == 0)371			break;372 373		tx_hdr = (struct ieee80211_hdr *)skb->data;374		if (likely(ether_addr_equal(tx_hdr->addr2, rx_hdr->addr1))) {375			found = 1;376			break;377		}378	}379 380	if (found) {381		for (i = 1; i < position; i++)382			skb = __skb_dequeue(q);383		if (i == position) {384			plfxlc_mac_tx_status(hw, skb,385					     mac->ack_pending ?386					     mac->ack_signal : 0,387					     NULL);388			mac->ack_pending = 0;389		}390 391		mac->ack_pending = skb_queue_len(q) ? 1 : 0;392		mac->ack_signal = stats->signal;393	}394 395	spin_unlock_irqrestore(&q->lock, flags);396	return 1;397}398 399int plfxlc_mac_rx(struct ieee80211_hw *hw, const u8 *buffer,400		  unsigned int length)401{402	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);403	struct ieee80211_rx_status stats;404	const struct rx_status *status;405	unsigned int payload_length;406	struct plfxlc_usb_tx *tx;407	struct sk_buff *skb;408	int need_padding;409	__le16 fc;410	int sidx;411 412	/* Packet blockade during disabled interface. */413	if (!mac->vif)414		return 0;415 416	status = (struct rx_status *)buffer;417 418	memset(&stats, 0, sizeof(stats));419 420	stats.flag     = 0;421	stats.freq     = 2412;422	stats.band     = NL80211_BAND_LC;423	mac->rssi      = -15 * be16_to_cpu(status->rssi) / 10;424 425	stats.signal   = mac->rssi;426 427	if (status->rate_idx > 7)428		stats.rate_idx = 0;429	else430		stats.rate_idx = status->rate_idx;431 432	mac->crc_errors = be64_to_cpu(status->crc_error_count);433 434	/* TODO bad frame check for CRC error*/435	if (plfxlc_filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) &&436	    !mac->pass_ctrl)437		return 0;438 439	buffer += sizeof(struct rx_status);440	payload_length = get_unaligned_be32(buffer);441 442	if (payload_length > 1560) {443		dev_err(plfxlc_mac_dev(mac), " > MTU %u\n", payload_length);444		return 0;445	}446	buffer += sizeof(u32);447 448	fc = get_unaligned((__le16 *)buffer);449	need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);450 451	tx = &mac->chip.usb.tx;452 453	for (sidx = 0; sidx < MAX_STA_NUM - 1; sidx++) {454		if (memcmp(&buffer[10], tx->station[sidx].mac, ETH_ALEN))455			continue;456		if (tx->station[sidx].flag & STATION_CONNECTED_FLAG) {457			tx->station[sidx].flag |= STATION_HEARTBEAT_FLAG;458			break;459		}460	}461 462	if (sidx == MAX_STA_NUM - 1) {463		for (sidx = 0; sidx < MAX_STA_NUM - 1; sidx++) {464			if (tx->station[sidx].flag & STATION_CONNECTED_FLAG)465				continue;466			memcpy(tx->station[sidx].mac, &buffer[10], ETH_ALEN);467			tx->station[sidx].flag |= STATION_CONNECTED_FLAG;468			tx->station[sidx].flag |= STATION_HEARTBEAT_FLAG;469			break;470		}471	}472 473	switch (buffer[0]) {474	case IEEE80211_STYPE_PROBE_REQ:475		dev_dbg(plfxlc_mac_dev(mac), "Probe request\n");476		break;477	case IEEE80211_STYPE_ASSOC_REQ:478		dev_dbg(plfxlc_mac_dev(mac), "Association request\n");479		break;480	case IEEE80211_STYPE_AUTH:481		dev_dbg(plfxlc_mac_dev(mac), "Authentication req\n");482		break;483	case IEEE80211_FTYPE_DATA:484		dev_dbg(plfxlc_mac_dev(mac), "802.11 data frame\n");485		break;486	}487 488	skb = dev_alloc_skb(payload_length + (need_padding ? 2 : 0));489	if (!skb)490		return -ENOMEM;491 492	if (need_padding)493		/* Make sure that the payload data is 4 byte aligned. */494		skb_reserve(skb, 2);495 496	skb_put_data(skb, buffer, payload_length);497	memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));498	ieee80211_rx_irqsafe(hw, skb);499	return 0;500}501 502static int plfxlc_op_add_interface(struct ieee80211_hw *hw,503				   struct ieee80211_vif *vif)504{505	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);506	static const char * const iftype80211[] = {507		[NL80211_IFTYPE_STATION]	= "Station",508		[NL80211_IFTYPE_ADHOC]		= "Adhoc"509	};510 511	if (mac->type != NL80211_IFTYPE_UNSPECIFIED)512		return -EOPNOTSUPP;513 514	if (vif->type == NL80211_IFTYPE_ADHOC ||515	    vif->type == NL80211_IFTYPE_STATION) {516		dev_dbg(plfxlc_mac_dev(mac), "%s %s\n", __func__,517			iftype80211[vif->type]);518		mac->type = vif->type;519		mac->vif = vif;520		return 0;521	}522	dev_dbg(plfxlc_mac_dev(mac), "unsupported iftype\n");523	return -EOPNOTSUPP;524}525 526static void plfxlc_op_remove_interface(struct ieee80211_hw *hw,527				       struct ieee80211_vif *vif)528{529	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);530 531	mac->type = NL80211_IFTYPE_UNSPECIFIED;532	mac->vif = NULL;533}534 535static int plfxlc_op_config(struct ieee80211_hw *hw, u32 changed)536{537	return 0;538}539 540#define SUPPORTED_FIF_FLAGS \541	(FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \542	 FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)543static void plfxlc_op_configure_filter(struct ieee80211_hw *hw,544				       unsigned int changed_flags,545				       unsigned int *new_flags,546				       u64 multicast)547{548	struct plfxlc_mc_hash hash = {549		.low = multicast,550		.high = multicast >> 32,551	};552	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);553	unsigned long flags;554 555	/* Only deal with supported flags */556	*new_flags &= SUPPORTED_FIF_FLAGS;557 558	/* If multicast parameter559	 * (as returned by plfxlc_op_prepare_multicast)560	 * has changed, no bit in changed_flags is set. To handle this561	 * situation, we do not return if changed_flags is 0. If we do so,562	 * we will have some issue with IPv6 which uses multicast for link563	 * layer address resolution.564	 */565	if (*new_flags & (FIF_ALLMULTI))566		plfxlc_mc_add_all(&hash);567 568	spin_lock_irqsave(&mac->lock, flags);569	mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL);570	mac->pass_ctrl = !!(*new_flags & FIF_CONTROL);571	mac->multicast_hash = hash;572	spin_unlock_irqrestore(&mac->lock, flags);573 574	/* no handling required for FIF_OTHER_BSS as we don't currently575	 * do BSSID filtering576	 */577	/* FIXME: in future it would be nice to enable the probe response578	 * filter (so that the driver doesn't see them) until579	 * FIF_BCN_PRBRESP_PROMISC is set. however due to atomicity here, we'd580	 * have to schedule work to enable prbresp reception, which might581	 * happen too late. For now we'll just listen and forward them all the582	 * time.583	 */584}585 586static void plfxlc_op_bss_info_changed(struct ieee80211_hw *hw,587				       struct ieee80211_vif *vif,588				       struct ieee80211_bss_conf *bss_conf,589				       u64 changes)590{591	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);592	int associated;593 594	dev_dbg(plfxlc_mac_dev(mac), "changes: %llx\n", changes);595 596	if (mac->type != NL80211_IFTYPE_ADHOC) { /* for STATION */597		associated = is_valid_ether_addr(bss_conf->bssid);598		goto exit_all;599	}600	/* for ADHOC */601	associated = true;602	if (changes & BSS_CHANGED_BEACON) {603		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif, 0);604 605		if (beacon) {606			/*beacon is hardcoded in firmware */607			kfree_skb(beacon);608			/*Returned skb is used only once and609			 * low-level driver is610			 * responsible for freeing it.611			 */612		}613	}614 615	if (changes & BSS_CHANGED_BEACON_ENABLED) {616		u16 interval = 0;617		u8 period = 0;618 619		if (bss_conf->enable_beacon) {620			period = bss_conf->dtim_period;621			interval = bss_conf->beacon_int;622		}623 624		spin_lock_irq(&mac->lock);625		mac->beacon.period = period;626		mac->beacon.interval = interval;627		mac->beacon.last_update = jiffies;628		spin_unlock_irq(&mac->lock);629 630		plfxlc_set_beacon_interval(&mac->chip, interval,631					   period, mac->type);632	}633exit_all:634	spin_lock_irq(&mac->lock);635	mac->associated = associated;636	spin_unlock_irq(&mac->lock);637}638 639static int plfxlc_get_stats(struct ieee80211_hw *hw,640			    struct ieee80211_low_level_stats *stats)641{642	stats->dot11ACKFailureCount = 0;643	stats->dot11RTSFailureCount = 0;644	stats->dot11FCSErrorCount   = 0;645	stats->dot11RTSSuccessCount = 0;646	return 0;647}648 649static const char et_strings[][ETH_GSTRING_LEN] = {650	"phy_rssi",651	"phy_rx_crc_err"652};653 654static int plfxlc_get_et_sset_count(struct ieee80211_hw *hw,655				    struct ieee80211_vif *vif, int sset)656{657	if (sset == ETH_SS_STATS)658		return ARRAY_SIZE(et_strings);659 660	return 0;661}662 663static void plfxlc_get_et_strings(struct ieee80211_hw *hw,664				  struct ieee80211_vif *vif,665				  u32 sset, u8 *data)666{667	if (sset == ETH_SS_STATS)668		memcpy(data, et_strings, sizeof(et_strings));669}670 671static void plfxlc_get_et_stats(struct ieee80211_hw *hw,672				struct ieee80211_vif *vif,673				struct ethtool_stats *stats, u64 *data)674{675	struct plfxlc_mac *mac = plfxlc_hw_mac(hw);676 677	data[0] = mac->rssi;678	data[1] = mac->crc_errors;679}680 681static int plfxlc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)682{683	return 0;684}685 686static const struct ieee80211_ops plfxlc_ops = {687	.add_chanctx = ieee80211_emulate_add_chanctx,688	.remove_chanctx = ieee80211_emulate_remove_chanctx,689	.change_chanctx = ieee80211_emulate_change_chanctx,690	.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,691	.tx = plfxlc_op_tx,692	.wake_tx_queue = ieee80211_handle_wake_tx_queue,693	.start = plfxlc_op_start,694	.stop = plfxlc_op_stop,695	.add_interface = plfxlc_op_add_interface,696	.remove_interface = plfxlc_op_remove_interface,697	.set_rts_threshold = plfxlc_set_rts_threshold,698	.config = plfxlc_op_config,699	.configure_filter = plfxlc_op_configure_filter,700	.bss_info_changed = plfxlc_op_bss_info_changed,701	.get_stats = plfxlc_get_stats,702	.get_et_sset_count = plfxlc_get_et_sset_count,703	.get_et_stats = plfxlc_get_et_stats,704	.get_et_strings = plfxlc_get_et_strings,705};706 707struct ieee80211_hw *plfxlc_mac_alloc_hw(struct usb_interface *intf)708{709	struct ieee80211_hw *hw;710	struct plfxlc_mac *mac;711 712	hw = ieee80211_alloc_hw(sizeof(struct plfxlc_mac), &plfxlc_ops);713	if (!hw) {714		dev_dbg(&intf->dev, "out of memory\n");715		return NULL;716	}717	set_wiphy_dev(hw->wiphy, &intf->dev);718 719	mac = plfxlc_hw_mac(hw);720	memset(mac, 0, sizeof(*mac));721	spin_lock_init(&mac->lock);722	mac->hw = hw;723 724	mac->type = NL80211_IFTYPE_UNSPECIFIED;725 726	memcpy(mac->channels, plfxlc_channels, sizeof(plfxlc_channels));727	memcpy(mac->rates, plfxlc_rates, sizeof(plfxlc_rates));728	mac->band.n_bitrates = ARRAY_SIZE(plfxlc_rates);729	mac->band.bitrates = mac->rates;730	mac->band.n_channels = ARRAY_SIZE(plfxlc_channels);731	mac->band.channels = mac->channels;732	hw->wiphy->bands[NL80211_BAND_LC] = &mac->band;733	hw->conf.chandef.width = NL80211_CHAN_WIDTH_20;734 735	ieee80211_hw_set(hw, RX_INCLUDES_FCS);736	ieee80211_hw_set(hw, SIGNAL_DBM);737	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);738	ieee80211_hw_set(hw, MFP_CAPABLE);739 740	hw->wiphy->interface_modes =741		BIT(NL80211_IFTYPE_STATION) |742		BIT(NL80211_IFTYPE_ADHOC);743	hw->max_signal = 100;744	hw->queues = 1;745	/* 4 for 32 bit alignment if no tailroom */746	hw->extra_tx_headroom = sizeof(struct plfxlc_ctrlset) + 4;747	/* Tell mac80211 that we support multi rate retries */748	hw->max_rates = IEEE80211_TX_MAX_RATES;749	hw->max_rate_tries = 18;   /* 9 rates * 2 retries/rate */750 751	skb_queue_head_init(&mac->ack_wait_queue);752	mac->ack_pending = 0;753 754	plfxlc_chip_init(&mac->chip, hw, intf);755 756	SET_IEEE80211_DEV(hw, &intf->dev);757	return hw;758}759