|
@@ -908,8 +908,20 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
|
|
return NULL;
|
|
return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
|
|
|
|
|
- struct sk_buff *skb)
|
|
|
|
|
|
|
+/* Use one of 2 strategies:
|
|
|
|
|
+ *
|
|
|
|
|
+ * 1. New (real broadcast):
|
|
|
|
|
+ * use dedicated broadcast vring
|
|
|
|
|
+ * 2. Old (pseudo-DMS):
|
|
|
|
|
+ * Find 1-st vring and return it;
|
|
|
|
|
+ * duplicate skb and send it to other active vrings;
|
|
|
|
|
+ * in all cases override dest address to unicast peer's address
|
|
|
|
|
+ * Use old strategy when new is not supported yet:
|
|
|
|
|
+ * - for PBSS
|
|
|
|
|
+ * - for secure link
|
|
|
|
|
+ */
|
|
|
|
|
+static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
|
|
|
|
|
+ struct sk_buff *skb)
|
|
|
{
|
|
{
|
|
|
struct vring *v;
|
|
struct vring *v;
|
|
|
int i = wil->bcast_vring;
|
|
int i = wil->bcast_vring;
|
|
@@ -923,6 +935,93 @@ static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
|
|
|
return v;
|
|
return v;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void wil_set_da_for_vring(struct wil6210_priv *wil,
|
|
|
|
|
+ struct sk_buff *skb, int vring_index)
|
|
|
|
|
+{
|
|
|
|
|
+ struct ethhdr *eth = (void *)skb->data;
|
|
|
|
|
+ int cid = wil->vring2cid_tid[vring_index][0];
|
|
|
|
|
+
|
|
|
|
|
+ ether_addr_copy(eth->h_dest, wil->sta[cid].addr);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
|
|
|
|
|
+ struct sk_buff *skb)
|
|
|
|
|
+{
|
|
|
|
|
+ struct vring *v, *v2;
|
|
|
|
|
+ struct sk_buff *skb2;
|
|
|
|
|
+ int i;
|
|
|
|
|
+ u8 cid;
|
|
|
|
|
+ struct ethhdr *eth = (void *)skb->data;
|
|
|
|
|
+ char *src = eth->h_source;
|
|
|
|
|
+
|
|
|
|
|
+ /* find 1-st vring eligible for data */
|
|
|
|
|
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
|
|
|
|
+ v = &wil->vring_tx[i];
|
|
|
|
|
+ if (!v->va)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ cid = wil->vring2cid_tid[i][0];
|
|
|
|
|
+ if (cid >= WIL6210_MAX_CID) /* skip BCAST */
|
|
|
|
|
+ continue;
|
|
|
|
|
+ if (!wil->sta[cid].data_port_open)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ /* don't Tx back to source when re-routing Rx->Tx at the AP */
|
|
|
|
|
+ if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN))
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ goto found;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ wil_dbg_txrx(wil, "Tx while no vrings active?\n");
|
|
|
|
|
+
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+found:
|
|
|
|
|
+ wil_dbg_txrx(wil, "BCAST -> ring %d\n", i);
|
|
|
|
|
+ wil_set_da_for_vring(wil, skb, i);
|
|
|
|
|
+
|
|
|
|
|
+ /* find other active vrings and duplicate skb for each */
|
|
|
|
|
+ for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
|
|
|
|
|
+ v2 = &wil->vring_tx[i];
|
|
|
|
|
+ if (!v2->va)
|
|
|
|
|
+ continue;
|
|
|
|
|
+ cid = wil->vring2cid_tid[i][0];
|
|
|
|
|
+ if (cid >= WIL6210_MAX_CID) /* skip BCAST */
|
|
|
|
|
+ continue;
|
|
|
|
|
+ if (!wil->sta[cid].data_port_open)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN))
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ skb2 = skb_copy(skb, GFP_ATOMIC);
|
|
|
|
|
+ if (skb2) {
|
|
|
|
|
+ wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
|
|
|
|
|
+ wil_set_da_for_vring(wil, skb2, i);
|
|
|
|
|
+ wil_tx_vring(wil, v2, skb2);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ wil_err(wil, "skb_copy failed\n");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return v;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
|
|
|
|
|
+ struct sk_buff *skb)
|
|
|
|
|
+{
|
|
|
|
|
+ struct wireless_dev *wdev = wil->wdev;
|
|
|
|
|
+
|
|
|
|
|
+ if (wdev->iftype != NL80211_IFTYPE_AP)
|
|
|
|
|
+ return wil_find_tx_bcast_2(wil, skb);
|
|
|
|
|
+
|
|
|
|
|
+ if (wil->privacy)
|
|
|
|
|
+ return wil_find_tx_bcast_2(wil, skb);
|
|
|
|
|
+
|
|
|
|
|
+ return wil_find_tx_bcast_1(wil, skb);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
|
|
static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
|
|
|
int vring_index)
|
|
int vring_index)
|
|
|
{
|
|
{
|