1b4c3e9b5SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2b4c3e9b5SBjoern A. Zeeb /*
3b4c3e9b5SBjoern A. Zeeb * Copyright (c) 2014 Broadcom Corporation
4b4c3e9b5SBjoern A. Zeeb */
5b4c3e9b5SBjoern A. Zeeb
6b4c3e9b5SBjoern A. Zeeb
7b4c3e9b5SBjoern A. Zeeb #include <linux/types.h>
8b4c3e9b5SBjoern A. Zeeb #include <linux/netdevice.h>
9b4c3e9b5SBjoern A. Zeeb #include <linux/etherdevice.h>
10b4c3e9b5SBjoern A. Zeeb #include <brcmu_utils.h>
11b4c3e9b5SBjoern A. Zeeb
12b4c3e9b5SBjoern A. Zeeb #include "core.h"
13b4c3e9b5SBjoern A. Zeeb #include "debug.h"
14b4c3e9b5SBjoern A. Zeeb #include "bus.h"
15b4c3e9b5SBjoern A. Zeeb #include "proto.h"
16b4c3e9b5SBjoern A. Zeeb #include "flowring.h"
17b4c3e9b5SBjoern A. Zeeb #include "msgbuf.h"
18b4c3e9b5SBjoern A. Zeeb #include "common.h"
19b4c3e9b5SBjoern A. Zeeb
20b4c3e9b5SBjoern A. Zeeb
21b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_HIGH 1024
22b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
23b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_INVALID_IFIDX 0xff
24b4c3e9b5SBjoern A. Zeeb
25b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
26b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
27b4c3e9b5SBjoern A. Zeeb
28b4c3e9b5SBjoern A. Zeeb static const u8 brcmf_flowring_prio2fifo[] = {
29b4c3e9b5SBjoern A. Zeeb 0,
30b4c3e9b5SBjoern A. Zeeb 1,
31b4c3e9b5SBjoern A. Zeeb 1,
32b4c3e9b5SBjoern A. Zeeb 0,
33b4c3e9b5SBjoern A. Zeeb 2,
34b4c3e9b5SBjoern A. Zeeb 2,
35b4c3e9b5SBjoern A. Zeeb 3,
36b4c3e9b5SBjoern A. Zeeb 3
37b4c3e9b5SBjoern A. Zeeb };
38b4c3e9b5SBjoern A. Zeeb
39b4c3e9b5SBjoern A. Zeeb static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
40b4c3e9b5SBjoern A. Zeeb
41b4c3e9b5SBjoern A. Zeeb
42b4c3e9b5SBjoern A. Zeeb static bool
brcmf_flowring_is_tdls_mac(struct brcmf_flowring * flow,u8 mac[ETH_ALEN])43b4c3e9b5SBjoern A. Zeeb brcmf_flowring_is_tdls_mac(struct brcmf_flowring *flow, u8 mac[ETH_ALEN])
44b4c3e9b5SBjoern A. Zeeb {
45b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_tdls_entry *search;
46b4c3e9b5SBjoern A. Zeeb
47b4c3e9b5SBjoern A. Zeeb search = flow->tdls_entry;
48b4c3e9b5SBjoern A. Zeeb
49b4c3e9b5SBjoern A. Zeeb while (search) {
50b4c3e9b5SBjoern A. Zeeb if (memcmp(search->mac, mac, ETH_ALEN) == 0)
51b4c3e9b5SBjoern A. Zeeb return true;
52b4c3e9b5SBjoern A. Zeeb search = search->next;
53b4c3e9b5SBjoern A. Zeeb }
54b4c3e9b5SBjoern A. Zeeb
55b4c3e9b5SBjoern A. Zeeb return false;
56b4c3e9b5SBjoern A. Zeeb }
57b4c3e9b5SBjoern A. Zeeb
58b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_lookup(struct brcmf_flowring * flow,u8 da[ETH_ALEN],u8 prio,u8 ifidx)59b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
60b4c3e9b5SBjoern A. Zeeb u8 prio, u8 ifidx)
61b4c3e9b5SBjoern A. Zeeb {
62b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_hash *hash;
63b4c3e9b5SBjoern A. Zeeb u16 hash_idx;
64b4c3e9b5SBjoern A. Zeeb u32 i;
65b4c3e9b5SBjoern A. Zeeb bool found;
66b4c3e9b5SBjoern A. Zeeb bool sta;
67b4c3e9b5SBjoern A. Zeeb u8 fifo;
68*902136e0SBjoern A. Zeeb #if defined(__linux__)
69b4c3e9b5SBjoern A. Zeeb u8 *mac;
70*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
71*902136e0SBjoern A. Zeeb const u8 *mac;
72*902136e0SBjoern A. Zeeb #endif
73b4c3e9b5SBjoern A. Zeeb
74b4c3e9b5SBjoern A. Zeeb fifo = brcmf_flowring_prio2fifo[prio];
75b4c3e9b5SBjoern A. Zeeb sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
76b4c3e9b5SBjoern A. Zeeb mac = da;
77b4c3e9b5SBjoern A. Zeeb if ((!sta) && (is_multicast_ether_addr(da))) {
78*902136e0SBjoern A. Zeeb #if defined(__linux__)
79b4c3e9b5SBjoern A. Zeeb mac = (u8 *)ALLFFMAC;
80*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
81*902136e0SBjoern A. Zeeb mac = ALLFFMAC;
82*902136e0SBjoern A. Zeeb #endif
83b4c3e9b5SBjoern A. Zeeb fifo = 0;
84b4c3e9b5SBjoern A. Zeeb }
85b4c3e9b5SBjoern A. Zeeb if ((sta) && (flow->tdls_active) &&
86b4c3e9b5SBjoern A. Zeeb (brcmf_flowring_is_tdls_mac(flow, da))) {
87b4c3e9b5SBjoern A. Zeeb sta = false;
88b4c3e9b5SBjoern A. Zeeb }
89b4c3e9b5SBjoern A. Zeeb hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
90b4c3e9b5SBjoern A. Zeeb BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
91b4c3e9b5SBjoern A. Zeeb hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
92b4c3e9b5SBjoern A. Zeeb found = false;
93b4c3e9b5SBjoern A. Zeeb hash = flow->hash;
94b4c3e9b5SBjoern A. Zeeb for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
95b4c3e9b5SBjoern A. Zeeb if ((sta || (memcmp(hash[hash_idx].mac, mac, ETH_ALEN) == 0)) &&
96b4c3e9b5SBjoern A. Zeeb (hash[hash_idx].fifo == fifo) &&
97b4c3e9b5SBjoern A. Zeeb (hash[hash_idx].ifidx == ifidx)) {
98b4c3e9b5SBjoern A. Zeeb found = true;
99b4c3e9b5SBjoern A. Zeeb break;
100b4c3e9b5SBjoern A. Zeeb }
101b4c3e9b5SBjoern A. Zeeb hash_idx++;
102b4c3e9b5SBjoern A. Zeeb hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
103b4c3e9b5SBjoern A. Zeeb }
104b4c3e9b5SBjoern A. Zeeb if (found)
105b4c3e9b5SBjoern A. Zeeb return hash[hash_idx].flowid;
106b4c3e9b5SBjoern A. Zeeb
107b4c3e9b5SBjoern A. Zeeb return BRCMF_FLOWRING_INVALID_ID;
108b4c3e9b5SBjoern A. Zeeb }
109b4c3e9b5SBjoern A. Zeeb
110b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_create(struct brcmf_flowring * flow,u8 da[ETH_ALEN],u8 prio,u8 ifidx)111b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
112b4c3e9b5SBjoern A. Zeeb u8 prio, u8 ifidx)
113b4c3e9b5SBjoern A. Zeeb {
114b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
115b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_hash *hash;
116b4c3e9b5SBjoern A. Zeeb u16 hash_idx;
117b4c3e9b5SBjoern A. Zeeb u32 i;
118b4c3e9b5SBjoern A. Zeeb bool found;
119b4c3e9b5SBjoern A. Zeeb u8 fifo;
120b4c3e9b5SBjoern A. Zeeb bool sta;
121*902136e0SBjoern A. Zeeb #if defined(__linux__)
122b4c3e9b5SBjoern A. Zeeb u8 *mac;
123*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
124*902136e0SBjoern A. Zeeb const u8 *mac;
125*902136e0SBjoern A. Zeeb #endif
126b4c3e9b5SBjoern A. Zeeb
127b4c3e9b5SBjoern A. Zeeb fifo = brcmf_flowring_prio2fifo[prio];
128b4c3e9b5SBjoern A. Zeeb sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
129b4c3e9b5SBjoern A. Zeeb mac = da;
130b4c3e9b5SBjoern A. Zeeb if ((!sta) && (is_multicast_ether_addr(da))) {
131*902136e0SBjoern A. Zeeb #if defined(__linux__)
132b4c3e9b5SBjoern A. Zeeb mac = (u8 *)ALLFFMAC;
133*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
134*902136e0SBjoern A. Zeeb mac = ALLFFMAC;
135*902136e0SBjoern A. Zeeb #endif
136b4c3e9b5SBjoern A. Zeeb fifo = 0;
137b4c3e9b5SBjoern A. Zeeb }
138b4c3e9b5SBjoern A. Zeeb if ((sta) && (flow->tdls_active) &&
139b4c3e9b5SBjoern A. Zeeb (brcmf_flowring_is_tdls_mac(flow, da))) {
140b4c3e9b5SBjoern A. Zeeb sta = false;
141b4c3e9b5SBjoern A. Zeeb }
142b4c3e9b5SBjoern A. Zeeb hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
143b4c3e9b5SBjoern A. Zeeb BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
144b4c3e9b5SBjoern A. Zeeb hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
145b4c3e9b5SBjoern A. Zeeb found = false;
146b4c3e9b5SBjoern A. Zeeb hash = flow->hash;
147b4c3e9b5SBjoern A. Zeeb for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
148b4c3e9b5SBjoern A. Zeeb if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) &&
149b4c3e9b5SBjoern A. Zeeb (is_zero_ether_addr(hash[hash_idx].mac))) {
150b4c3e9b5SBjoern A. Zeeb found = true;
151b4c3e9b5SBjoern A. Zeeb break;
152b4c3e9b5SBjoern A. Zeeb }
153b4c3e9b5SBjoern A. Zeeb hash_idx++;
154b4c3e9b5SBjoern A. Zeeb hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
155b4c3e9b5SBjoern A. Zeeb }
156b4c3e9b5SBjoern A. Zeeb if (found) {
157b4c3e9b5SBjoern A. Zeeb for (i = 0; i < flow->nrofrings; i++) {
158b4c3e9b5SBjoern A. Zeeb if (flow->rings[i] == NULL)
159b4c3e9b5SBjoern A. Zeeb break;
160b4c3e9b5SBjoern A. Zeeb }
161b4c3e9b5SBjoern A. Zeeb if (i == flow->nrofrings)
162b4c3e9b5SBjoern A. Zeeb return -ENOMEM;
163b4c3e9b5SBjoern A. Zeeb
164b4c3e9b5SBjoern A. Zeeb ring = kzalloc(sizeof(*ring), GFP_ATOMIC);
165b4c3e9b5SBjoern A. Zeeb if (!ring)
166b4c3e9b5SBjoern A. Zeeb return -ENOMEM;
167b4c3e9b5SBjoern A. Zeeb
168b4c3e9b5SBjoern A. Zeeb memcpy(hash[hash_idx].mac, mac, ETH_ALEN);
169b4c3e9b5SBjoern A. Zeeb hash[hash_idx].fifo = fifo;
170b4c3e9b5SBjoern A. Zeeb hash[hash_idx].ifidx = ifidx;
171b4c3e9b5SBjoern A. Zeeb hash[hash_idx].flowid = i;
172b4c3e9b5SBjoern A. Zeeb
173b4c3e9b5SBjoern A. Zeeb ring->hash_id = hash_idx;
174b4c3e9b5SBjoern A. Zeeb ring->status = RING_CLOSED;
175b4c3e9b5SBjoern A. Zeeb skb_queue_head_init(&ring->skblist);
176b4c3e9b5SBjoern A. Zeeb flow->rings[i] = ring;
177b4c3e9b5SBjoern A. Zeeb
178b4c3e9b5SBjoern A. Zeeb return i;
179b4c3e9b5SBjoern A. Zeeb }
180b4c3e9b5SBjoern A. Zeeb return BRCMF_FLOWRING_INVALID_ID;
181b4c3e9b5SBjoern A. Zeeb }
182b4c3e9b5SBjoern A. Zeeb
183b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_tid(struct brcmf_flowring * flow,u16 flowid)184b4c3e9b5SBjoern A. Zeeb u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
185b4c3e9b5SBjoern A. Zeeb {
186b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
187b4c3e9b5SBjoern A. Zeeb
188b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
189b4c3e9b5SBjoern A. Zeeb
190b4c3e9b5SBjoern A. Zeeb return flow->hash[ring->hash_id].fifo;
191b4c3e9b5SBjoern A. Zeeb }
192b4c3e9b5SBjoern A. Zeeb
193b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_block(struct brcmf_flowring * flow,u16 flowid,bool blocked)194b4c3e9b5SBjoern A. Zeeb static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
195b4c3e9b5SBjoern A. Zeeb bool blocked)
196b4c3e9b5SBjoern A. Zeeb {
197b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
198b4c3e9b5SBjoern A. Zeeb struct brcmf_bus *bus_if;
199b4c3e9b5SBjoern A. Zeeb struct brcmf_pub *drvr;
200b4c3e9b5SBjoern A. Zeeb struct brcmf_if *ifp;
201b4c3e9b5SBjoern A. Zeeb bool currently_blocked;
202b4c3e9b5SBjoern A. Zeeb int i;
203b4c3e9b5SBjoern A. Zeeb u8 ifidx;
204b4c3e9b5SBjoern A. Zeeb unsigned long flags;
205b4c3e9b5SBjoern A. Zeeb
206b4c3e9b5SBjoern A. Zeeb spin_lock_irqsave(&flow->block_lock, flags);
207b4c3e9b5SBjoern A. Zeeb
208b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
209b4c3e9b5SBjoern A. Zeeb if (ring->blocked == blocked) {
210b4c3e9b5SBjoern A. Zeeb spin_unlock_irqrestore(&flow->block_lock, flags);
211b4c3e9b5SBjoern A. Zeeb return;
212b4c3e9b5SBjoern A. Zeeb }
213b4c3e9b5SBjoern A. Zeeb ifidx = brcmf_flowring_ifidx_get(flow, flowid);
214b4c3e9b5SBjoern A. Zeeb
215b4c3e9b5SBjoern A. Zeeb currently_blocked = false;
216b4c3e9b5SBjoern A. Zeeb for (i = 0; i < flow->nrofrings; i++) {
217b4c3e9b5SBjoern A. Zeeb if ((flow->rings[i]) && (i != flowid)) {
218b4c3e9b5SBjoern A. Zeeb ring = flow->rings[i];
219b4c3e9b5SBjoern A. Zeeb if ((ring->status == RING_OPEN) &&
220b4c3e9b5SBjoern A. Zeeb (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
221b4c3e9b5SBjoern A. Zeeb if (ring->blocked) {
222b4c3e9b5SBjoern A. Zeeb currently_blocked = true;
223b4c3e9b5SBjoern A. Zeeb break;
224b4c3e9b5SBjoern A. Zeeb }
225b4c3e9b5SBjoern A. Zeeb }
226b4c3e9b5SBjoern A. Zeeb }
227b4c3e9b5SBjoern A. Zeeb }
228b4c3e9b5SBjoern A. Zeeb flow->rings[flowid]->blocked = blocked;
229b4c3e9b5SBjoern A. Zeeb if (currently_blocked) {
230b4c3e9b5SBjoern A. Zeeb spin_unlock_irqrestore(&flow->block_lock, flags);
231b4c3e9b5SBjoern A. Zeeb return;
232b4c3e9b5SBjoern A. Zeeb }
233b4c3e9b5SBjoern A. Zeeb
234b4c3e9b5SBjoern A. Zeeb bus_if = dev_get_drvdata(flow->dev);
235b4c3e9b5SBjoern A. Zeeb drvr = bus_if->drvr;
236b4c3e9b5SBjoern A. Zeeb ifp = brcmf_get_ifp(drvr, ifidx);
237b4c3e9b5SBjoern A. Zeeb brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
238b4c3e9b5SBjoern A. Zeeb
239b4c3e9b5SBjoern A. Zeeb spin_unlock_irqrestore(&flow->block_lock, flags);
240b4c3e9b5SBjoern A. Zeeb }
241b4c3e9b5SBjoern A. Zeeb
242b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_delete(struct brcmf_flowring * flow,u16 flowid)243b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
244b4c3e9b5SBjoern A. Zeeb {
245b4c3e9b5SBjoern A. Zeeb struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
246b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
247b4c3e9b5SBjoern A. Zeeb struct brcmf_if *ifp;
248b4c3e9b5SBjoern A. Zeeb u16 hash_idx;
249b4c3e9b5SBjoern A. Zeeb u8 ifidx;
250b4c3e9b5SBjoern A. Zeeb struct sk_buff *skb;
251b4c3e9b5SBjoern A. Zeeb
252b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
253b4c3e9b5SBjoern A. Zeeb if (!ring)
254b4c3e9b5SBjoern A. Zeeb return;
255b4c3e9b5SBjoern A. Zeeb
256b4c3e9b5SBjoern A. Zeeb ifidx = brcmf_flowring_ifidx_get(flow, flowid);
257b4c3e9b5SBjoern A. Zeeb ifp = brcmf_get_ifp(bus_if->drvr, ifidx);
258b4c3e9b5SBjoern A. Zeeb
259b4c3e9b5SBjoern A. Zeeb brcmf_flowring_block(flow, flowid, false);
260b4c3e9b5SBjoern A. Zeeb hash_idx = ring->hash_id;
261b4c3e9b5SBjoern A. Zeeb flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
262b4c3e9b5SBjoern A. Zeeb eth_zero_addr(flow->hash[hash_idx].mac);
263b4c3e9b5SBjoern A. Zeeb flow->rings[flowid] = NULL;
264b4c3e9b5SBjoern A. Zeeb
265b4c3e9b5SBjoern A. Zeeb skb = skb_dequeue(&ring->skblist);
266b4c3e9b5SBjoern A. Zeeb while (skb) {
267b4c3e9b5SBjoern A. Zeeb brcmf_txfinalize(ifp, skb, false);
268b4c3e9b5SBjoern A. Zeeb skb = skb_dequeue(&ring->skblist);
269b4c3e9b5SBjoern A. Zeeb }
270b4c3e9b5SBjoern A. Zeeb
271b4c3e9b5SBjoern A. Zeeb kfree(ring);
272b4c3e9b5SBjoern A. Zeeb }
273b4c3e9b5SBjoern A. Zeeb
274b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_enqueue(struct brcmf_flowring * flow,u16 flowid,struct sk_buff * skb)275b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
276b4c3e9b5SBjoern A. Zeeb struct sk_buff *skb)
277b4c3e9b5SBjoern A. Zeeb {
278b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
279b4c3e9b5SBjoern A. Zeeb
280b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
281b4c3e9b5SBjoern A. Zeeb
282b4c3e9b5SBjoern A. Zeeb skb_queue_tail(&ring->skblist, skb);
283b4c3e9b5SBjoern A. Zeeb
284b4c3e9b5SBjoern A. Zeeb if (!ring->blocked &&
285b4c3e9b5SBjoern A. Zeeb (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
286b4c3e9b5SBjoern A. Zeeb brcmf_flowring_block(flow, flowid, true);
287b4c3e9b5SBjoern A. Zeeb brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
288b4c3e9b5SBjoern A. Zeeb /* To prevent (work around) possible race condition, check
289b4c3e9b5SBjoern A. Zeeb * queue len again. It is also possible to use locking to
290b4c3e9b5SBjoern A. Zeeb * protect, but that is undesirable for every enqueue and
291b4c3e9b5SBjoern A. Zeeb * dequeue. This simple check will solve a possible race
292b4c3e9b5SBjoern A. Zeeb * condition if it occurs.
293b4c3e9b5SBjoern A. Zeeb */
294b4c3e9b5SBjoern A. Zeeb if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
295b4c3e9b5SBjoern A. Zeeb brcmf_flowring_block(flow, flowid, false);
296b4c3e9b5SBjoern A. Zeeb }
297b4c3e9b5SBjoern A. Zeeb return skb_queue_len(&ring->skblist);
298b4c3e9b5SBjoern A. Zeeb }
299b4c3e9b5SBjoern A. Zeeb
300b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_dequeue(struct brcmf_flowring * flow,u16 flowid)301b4c3e9b5SBjoern A. Zeeb struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
302b4c3e9b5SBjoern A. Zeeb {
303b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
304b4c3e9b5SBjoern A. Zeeb struct sk_buff *skb;
305b4c3e9b5SBjoern A. Zeeb
306b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
307b4c3e9b5SBjoern A. Zeeb if (ring->status != RING_OPEN)
308b4c3e9b5SBjoern A. Zeeb return NULL;
309b4c3e9b5SBjoern A. Zeeb
310b4c3e9b5SBjoern A. Zeeb skb = skb_dequeue(&ring->skblist);
311b4c3e9b5SBjoern A. Zeeb
312b4c3e9b5SBjoern A. Zeeb if (ring->blocked &&
313b4c3e9b5SBjoern A. Zeeb (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
314b4c3e9b5SBjoern A. Zeeb brcmf_flowring_block(flow, flowid, false);
315b4c3e9b5SBjoern A. Zeeb brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
316b4c3e9b5SBjoern A. Zeeb }
317b4c3e9b5SBjoern A. Zeeb
318b4c3e9b5SBjoern A. Zeeb return skb;
319b4c3e9b5SBjoern A. Zeeb }
320b4c3e9b5SBjoern A. Zeeb
321b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_reinsert(struct brcmf_flowring * flow,u16 flowid,struct sk_buff * skb)322b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
323b4c3e9b5SBjoern A. Zeeb struct sk_buff *skb)
324b4c3e9b5SBjoern A. Zeeb {
325b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
326b4c3e9b5SBjoern A. Zeeb
327b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
328b4c3e9b5SBjoern A. Zeeb
329b4c3e9b5SBjoern A. Zeeb skb_queue_head(&ring->skblist, skb);
330b4c3e9b5SBjoern A. Zeeb }
331b4c3e9b5SBjoern A. Zeeb
332b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_qlen(struct brcmf_flowring * flow,u16 flowid)333b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
334b4c3e9b5SBjoern A. Zeeb {
335b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
336b4c3e9b5SBjoern A. Zeeb
337b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
338b4c3e9b5SBjoern A. Zeeb if (!ring)
339b4c3e9b5SBjoern A. Zeeb return 0;
340b4c3e9b5SBjoern A. Zeeb
341b4c3e9b5SBjoern A. Zeeb if (ring->status != RING_OPEN)
342b4c3e9b5SBjoern A. Zeeb return 0;
343b4c3e9b5SBjoern A. Zeeb
344b4c3e9b5SBjoern A. Zeeb return skb_queue_len(&ring->skblist);
345b4c3e9b5SBjoern A. Zeeb }
346b4c3e9b5SBjoern A. Zeeb
347b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_open(struct brcmf_flowring * flow,u16 flowid)348b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
349b4c3e9b5SBjoern A. Zeeb {
350b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
351b4c3e9b5SBjoern A. Zeeb
352b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
353b4c3e9b5SBjoern A. Zeeb if (!ring) {
354b4c3e9b5SBjoern A. Zeeb brcmf_err("Ring NULL, for flowid %d\n", flowid);
355b4c3e9b5SBjoern A. Zeeb return;
356b4c3e9b5SBjoern A. Zeeb }
357b4c3e9b5SBjoern A. Zeeb
358b4c3e9b5SBjoern A. Zeeb ring->status = RING_OPEN;
359b4c3e9b5SBjoern A. Zeeb }
360b4c3e9b5SBjoern A. Zeeb
361b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_ifidx_get(struct brcmf_flowring * flow,u16 flowid)362b4c3e9b5SBjoern A. Zeeb u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
363b4c3e9b5SBjoern A. Zeeb {
364b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_ring *ring;
365b4c3e9b5SBjoern A. Zeeb u16 hash_idx;
366b4c3e9b5SBjoern A. Zeeb
367b4c3e9b5SBjoern A. Zeeb ring = flow->rings[flowid];
368b4c3e9b5SBjoern A. Zeeb hash_idx = ring->hash_id;
369b4c3e9b5SBjoern A. Zeeb
370b4c3e9b5SBjoern A. Zeeb return flow->hash[hash_idx].ifidx;
371b4c3e9b5SBjoern A. Zeeb }
372b4c3e9b5SBjoern A. Zeeb
373b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_attach(struct device * dev,u16 nrofrings)374b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
375b4c3e9b5SBjoern A. Zeeb {
376b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring *flow;
377b4c3e9b5SBjoern A. Zeeb u32 i;
378b4c3e9b5SBjoern A. Zeeb
379b4c3e9b5SBjoern A. Zeeb flow = kzalloc(sizeof(*flow), GFP_KERNEL);
380b4c3e9b5SBjoern A. Zeeb if (flow) {
381b4c3e9b5SBjoern A. Zeeb flow->dev = dev;
382b4c3e9b5SBjoern A. Zeeb flow->nrofrings = nrofrings;
383b4c3e9b5SBjoern A. Zeeb spin_lock_init(&flow->block_lock);
384b4c3e9b5SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
385b4c3e9b5SBjoern A. Zeeb flow->addr_mode[i] = ADDR_INDIRECT;
386b4c3e9b5SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
387b4c3e9b5SBjoern A. Zeeb flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
388b4c3e9b5SBjoern A. Zeeb flow->rings = kcalloc(nrofrings, sizeof(*flow->rings),
389b4c3e9b5SBjoern A. Zeeb GFP_KERNEL);
390b4c3e9b5SBjoern A. Zeeb if (!flow->rings) {
391b4c3e9b5SBjoern A. Zeeb kfree(flow);
392b4c3e9b5SBjoern A. Zeeb flow = NULL;
393b4c3e9b5SBjoern A. Zeeb }
394b4c3e9b5SBjoern A. Zeeb }
395b4c3e9b5SBjoern A. Zeeb
396b4c3e9b5SBjoern A. Zeeb return flow;
397b4c3e9b5SBjoern A. Zeeb }
398b4c3e9b5SBjoern A. Zeeb
399b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_detach(struct brcmf_flowring * flow)400b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_detach(struct brcmf_flowring *flow)
401b4c3e9b5SBjoern A. Zeeb {
402b4c3e9b5SBjoern A. Zeeb struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
403b4c3e9b5SBjoern A. Zeeb struct brcmf_pub *drvr = bus_if->drvr;
404b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_tdls_entry *search;
405b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_tdls_entry *remove;
406b4c3e9b5SBjoern A. Zeeb u16 flowid;
407b4c3e9b5SBjoern A. Zeeb
408b4c3e9b5SBjoern A. Zeeb for (flowid = 0; flowid < flow->nrofrings; flowid++) {
409b4c3e9b5SBjoern A. Zeeb if (flow->rings[flowid])
410b4c3e9b5SBjoern A. Zeeb brcmf_msgbuf_delete_flowring(drvr, flowid);
411b4c3e9b5SBjoern A. Zeeb }
412b4c3e9b5SBjoern A. Zeeb
413b4c3e9b5SBjoern A. Zeeb search = flow->tdls_entry;
414b4c3e9b5SBjoern A. Zeeb while (search) {
415b4c3e9b5SBjoern A. Zeeb remove = search;
416b4c3e9b5SBjoern A. Zeeb search = search->next;
417b4c3e9b5SBjoern A. Zeeb kfree(remove);
418b4c3e9b5SBjoern A. Zeeb }
419b4c3e9b5SBjoern A. Zeeb kfree(flow->rings);
420b4c3e9b5SBjoern A. Zeeb kfree(flow);
421b4c3e9b5SBjoern A. Zeeb }
422b4c3e9b5SBjoern A. Zeeb
423b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_configure_addr_mode(struct brcmf_flowring * flow,int ifidx,enum proto_addr_mode addr_mode)424b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
425b4c3e9b5SBjoern A. Zeeb enum proto_addr_mode addr_mode)
426b4c3e9b5SBjoern A. Zeeb {
427b4c3e9b5SBjoern A. Zeeb struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
428b4c3e9b5SBjoern A. Zeeb struct brcmf_pub *drvr = bus_if->drvr;
429b4c3e9b5SBjoern A. Zeeb u32 i;
430b4c3e9b5SBjoern A. Zeeb u16 flowid;
431b4c3e9b5SBjoern A. Zeeb
432b4c3e9b5SBjoern A. Zeeb if (flow->addr_mode[ifidx] != addr_mode) {
433b4c3e9b5SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
434b4c3e9b5SBjoern A. Zeeb if (flow->hash[i].ifidx == ifidx) {
435b4c3e9b5SBjoern A. Zeeb flowid = flow->hash[i].flowid;
436b4c3e9b5SBjoern A. Zeeb if (flow->rings[flowid]->status != RING_OPEN)
437b4c3e9b5SBjoern A. Zeeb continue;
438b4c3e9b5SBjoern A. Zeeb brcmf_msgbuf_delete_flowring(drvr, flowid);
439b4c3e9b5SBjoern A. Zeeb }
440b4c3e9b5SBjoern A. Zeeb }
441b4c3e9b5SBjoern A. Zeeb flow->addr_mode[ifidx] = addr_mode;
442b4c3e9b5SBjoern A. Zeeb }
443b4c3e9b5SBjoern A. Zeeb }
444b4c3e9b5SBjoern A. Zeeb
445b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_delete_peer(struct brcmf_flowring * flow,int ifidx,u8 peer[ETH_ALEN])446b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
447*902136e0SBjoern A. Zeeb #if defined(__linux__)
448b4c3e9b5SBjoern A. Zeeb u8 peer[ETH_ALEN])
449*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
450*902136e0SBjoern A. Zeeb const u8 peer[ETH_ALEN])
451*902136e0SBjoern A. Zeeb #endif
452b4c3e9b5SBjoern A. Zeeb {
453b4c3e9b5SBjoern A. Zeeb struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
454b4c3e9b5SBjoern A. Zeeb struct brcmf_pub *drvr = bus_if->drvr;
455b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_hash *hash;
456b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_tdls_entry *prev;
457b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_tdls_entry *search;
458b4c3e9b5SBjoern A. Zeeb u32 i;
459b4c3e9b5SBjoern A. Zeeb u16 flowid;
460b4c3e9b5SBjoern A. Zeeb bool sta;
461b4c3e9b5SBjoern A. Zeeb
462b4c3e9b5SBjoern A. Zeeb sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
463b4c3e9b5SBjoern A. Zeeb
464b4c3e9b5SBjoern A. Zeeb search = flow->tdls_entry;
465b4c3e9b5SBjoern A. Zeeb prev = NULL;
466b4c3e9b5SBjoern A. Zeeb while (search) {
467b4c3e9b5SBjoern A. Zeeb if (memcmp(search->mac, peer, ETH_ALEN) == 0) {
468b4c3e9b5SBjoern A. Zeeb sta = false;
469b4c3e9b5SBjoern A. Zeeb break;
470b4c3e9b5SBjoern A. Zeeb }
471b4c3e9b5SBjoern A. Zeeb prev = search;
472b4c3e9b5SBjoern A. Zeeb search = search->next;
473b4c3e9b5SBjoern A. Zeeb }
474b4c3e9b5SBjoern A. Zeeb
475b4c3e9b5SBjoern A. Zeeb hash = flow->hash;
476b4c3e9b5SBjoern A. Zeeb for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
477b4c3e9b5SBjoern A. Zeeb if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
478b4c3e9b5SBjoern A. Zeeb (hash[i].ifidx == ifidx)) {
479b4c3e9b5SBjoern A. Zeeb flowid = flow->hash[i].flowid;
480b4c3e9b5SBjoern A. Zeeb if (flow->rings[flowid]->status == RING_OPEN)
481b4c3e9b5SBjoern A. Zeeb brcmf_msgbuf_delete_flowring(drvr, flowid);
482b4c3e9b5SBjoern A. Zeeb }
483b4c3e9b5SBjoern A. Zeeb }
484b4c3e9b5SBjoern A. Zeeb
485b4c3e9b5SBjoern A. Zeeb if (search) {
486b4c3e9b5SBjoern A. Zeeb if (prev)
487b4c3e9b5SBjoern A. Zeeb prev->next = search->next;
488b4c3e9b5SBjoern A. Zeeb else
489b4c3e9b5SBjoern A. Zeeb flow->tdls_entry = search->next;
490b4c3e9b5SBjoern A. Zeeb kfree(search);
491b4c3e9b5SBjoern A. Zeeb if (flow->tdls_entry == NULL)
492b4c3e9b5SBjoern A. Zeeb flow->tdls_active = false;
493b4c3e9b5SBjoern A. Zeeb }
494b4c3e9b5SBjoern A. Zeeb }
495b4c3e9b5SBjoern A. Zeeb
496b4c3e9b5SBjoern A. Zeeb
brcmf_flowring_add_tdls_peer(struct brcmf_flowring * flow,int ifidx,u8 peer[ETH_ALEN])497b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx,
498*902136e0SBjoern A. Zeeb #if defined(__linux__)
499b4c3e9b5SBjoern A. Zeeb u8 peer[ETH_ALEN])
500*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
501*902136e0SBjoern A. Zeeb const u8 peer[ETH_ALEN])
502*902136e0SBjoern A. Zeeb #endif
503b4c3e9b5SBjoern A. Zeeb {
504b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_tdls_entry *tdls_entry;
505b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring_tdls_entry *search;
506b4c3e9b5SBjoern A. Zeeb
507b4c3e9b5SBjoern A. Zeeb tdls_entry = kzalloc(sizeof(*tdls_entry), GFP_ATOMIC);
508b4c3e9b5SBjoern A. Zeeb if (tdls_entry == NULL)
509b4c3e9b5SBjoern A. Zeeb return;
510b4c3e9b5SBjoern A. Zeeb
511b4c3e9b5SBjoern A. Zeeb memcpy(tdls_entry->mac, peer, ETH_ALEN);
512b4c3e9b5SBjoern A. Zeeb tdls_entry->next = NULL;
513b4c3e9b5SBjoern A. Zeeb if (flow->tdls_entry == NULL) {
514b4c3e9b5SBjoern A. Zeeb flow->tdls_entry = tdls_entry;
515b4c3e9b5SBjoern A. Zeeb } else {
516b4c3e9b5SBjoern A. Zeeb search = flow->tdls_entry;
517b4c3e9b5SBjoern A. Zeeb if (memcmp(search->mac, peer, ETH_ALEN) == 0)
518b4c3e9b5SBjoern A. Zeeb goto free_entry;
519b4c3e9b5SBjoern A. Zeeb while (search->next) {
520b4c3e9b5SBjoern A. Zeeb search = search->next;
521b4c3e9b5SBjoern A. Zeeb if (memcmp(search->mac, peer, ETH_ALEN) == 0)
522b4c3e9b5SBjoern A. Zeeb goto free_entry;
523b4c3e9b5SBjoern A. Zeeb }
524b4c3e9b5SBjoern A. Zeeb search->next = tdls_entry;
525b4c3e9b5SBjoern A. Zeeb }
526b4c3e9b5SBjoern A. Zeeb
527b4c3e9b5SBjoern A. Zeeb flow->tdls_active = true;
528b4c3e9b5SBjoern A. Zeeb return;
529b4c3e9b5SBjoern A. Zeeb
530b4c3e9b5SBjoern A. Zeeb free_entry:
531b4c3e9b5SBjoern A. Zeeb kfree(tdls_entry);
532b4c3e9b5SBjoern A. Zeeb }
533