1daeccac2SArend van Spriel // SPDX-License-Identifier: ISC
2daeccac2SArend van Spriel /*
3daeccac2SArend van Spriel * Copyright (c) 2014 Broadcom Corporation
405491d2cSKalle Valo */
505491d2cSKalle Valo
605491d2cSKalle Valo
705491d2cSKalle Valo #include <linux/types.h>
805491d2cSKalle Valo #include <linux/netdevice.h>
905491d2cSKalle Valo #include <linux/etherdevice.h>
1005491d2cSKalle Valo #include <brcmu_utils.h>
1105491d2cSKalle Valo
1205491d2cSKalle Valo #include "core.h"
1305491d2cSKalle Valo #include "debug.h"
1405491d2cSKalle Valo #include "bus.h"
1505491d2cSKalle Valo #include "proto.h"
1605491d2cSKalle Valo #include "flowring.h"
1705491d2cSKalle Valo #include "msgbuf.h"
1805491d2cSKalle Valo #include "common.h"
1905491d2cSKalle Valo
2005491d2cSKalle Valo
2105491d2cSKalle Valo #define BRCMF_FLOWRING_HIGH 1024
2205491d2cSKalle Valo #define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
2305491d2cSKalle Valo #define BRCMF_FLOWRING_INVALID_IFIDX 0xff
2405491d2cSKalle Valo
2519c8f421SHante Meuleman #define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
2605491d2cSKalle Valo #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
2705491d2cSKalle Valo
2805491d2cSKalle Valo static const u8 brcmf_flowring_prio2fifo[] = {
2905491d2cSKalle Valo 0,
3005491d2cSKalle Valo 1,
31f5da2a37SPramod Prakash 1,
32f5da2a37SPramod Prakash 0,
3305491d2cSKalle Valo 2,
3405491d2cSKalle Valo 2,
3505491d2cSKalle Valo 3,
3605491d2cSKalle Valo 3
3705491d2cSKalle Valo };
3805491d2cSKalle Valo
39f8793c26SArend Van Spriel static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
40f8793c26SArend Van Spriel
4105491d2cSKalle Valo
4205491d2cSKalle Valo static bool
brcmf_flowring_is_tdls_mac(struct brcmf_flowring * flow,u8 mac[ETH_ALEN])4305491d2cSKalle Valo brcmf_flowring_is_tdls_mac(struct brcmf_flowring *flow, u8 mac[ETH_ALEN])
4405491d2cSKalle Valo {
4505491d2cSKalle Valo struct brcmf_flowring_tdls_entry *search;
4605491d2cSKalle Valo
4705491d2cSKalle Valo search = flow->tdls_entry;
4805491d2cSKalle Valo
4905491d2cSKalle Valo while (search) {
5005491d2cSKalle Valo if (memcmp(search->mac, mac, ETH_ALEN) == 0)
5105491d2cSKalle Valo return true;
5205491d2cSKalle Valo search = search->next;
5305491d2cSKalle Valo }
5405491d2cSKalle Valo
5505491d2cSKalle Valo return false;
5605491d2cSKalle Valo }
5705491d2cSKalle Valo
5805491d2cSKalle Valo
brcmf_flowring_lookup(struct brcmf_flowring * flow,u8 da[ETH_ALEN],u8 prio,u8 ifidx)5905491d2cSKalle Valo u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
6005491d2cSKalle Valo u8 prio, u8 ifidx)
6105491d2cSKalle Valo {
6205491d2cSKalle Valo struct brcmf_flowring_hash *hash;
6319c8f421SHante Meuleman u16 hash_idx;
6405491d2cSKalle Valo u32 i;
6505491d2cSKalle Valo bool found;
6605491d2cSKalle Valo bool sta;
6705491d2cSKalle Valo u8 fifo;
6805491d2cSKalle Valo u8 *mac;
6905491d2cSKalle Valo
7005491d2cSKalle Valo fifo = brcmf_flowring_prio2fifo[prio];
7105491d2cSKalle Valo sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
7205491d2cSKalle Valo mac = da;
7305491d2cSKalle Valo if ((!sta) && (is_multicast_ether_addr(da))) {
7405491d2cSKalle Valo mac = (u8 *)ALLFFMAC;
7505491d2cSKalle Valo fifo = 0;
7605491d2cSKalle Valo }
7705491d2cSKalle Valo if ((sta) && (flow->tdls_active) &&
7805491d2cSKalle Valo (brcmf_flowring_is_tdls_mac(flow, da))) {
7905491d2cSKalle Valo sta = false;
8005491d2cSKalle Valo }
8105491d2cSKalle Valo hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
8205491d2cSKalle Valo BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
8319c8f421SHante Meuleman hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
8405491d2cSKalle Valo found = false;
8505491d2cSKalle Valo hash = flow->hash;
8605491d2cSKalle Valo for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
8705491d2cSKalle Valo if ((sta || (memcmp(hash[hash_idx].mac, mac, ETH_ALEN) == 0)) &&
8805491d2cSKalle Valo (hash[hash_idx].fifo == fifo) &&
8905491d2cSKalle Valo (hash[hash_idx].ifidx == ifidx)) {
9005491d2cSKalle Valo found = true;
9105491d2cSKalle Valo break;
9205491d2cSKalle Valo }
9305491d2cSKalle Valo hash_idx++;
9419c8f421SHante Meuleman hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
9505491d2cSKalle Valo }
9605491d2cSKalle Valo if (found)
9705491d2cSKalle Valo return hash[hash_idx].flowid;
9805491d2cSKalle Valo
9905491d2cSKalle Valo return BRCMF_FLOWRING_INVALID_ID;
10005491d2cSKalle Valo }
10105491d2cSKalle Valo
10205491d2cSKalle Valo
brcmf_flowring_create(struct brcmf_flowring * flow,u8 da[ETH_ALEN],u8 prio,u8 ifidx)10305491d2cSKalle Valo u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
10405491d2cSKalle Valo u8 prio, u8 ifidx)
10505491d2cSKalle Valo {
10605491d2cSKalle Valo struct brcmf_flowring_ring *ring;
10705491d2cSKalle Valo struct brcmf_flowring_hash *hash;
10819c8f421SHante Meuleman u16 hash_idx;
10905491d2cSKalle Valo u32 i;
11005491d2cSKalle Valo bool found;
11105491d2cSKalle Valo u8 fifo;
11205491d2cSKalle Valo bool sta;
11305491d2cSKalle Valo u8 *mac;
11405491d2cSKalle Valo
11505491d2cSKalle Valo fifo = brcmf_flowring_prio2fifo[prio];
11605491d2cSKalle Valo sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
11705491d2cSKalle Valo mac = da;
11805491d2cSKalle Valo if ((!sta) && (is_multicast_ether_addr(da))) {
11905491d2cSKalle Valo mac = (u8 *)ALLFFMAC;
12005491d2cSKalle Valo fifo = 0;
12105491d2cSKalle Valo }
12205491d2cSKalle Valo if ((sta) && (flow->tdls_active) &&
12305491d2cSKalle Valo (brcmf_flowring_is_tdls_mac(flow, da))) {
12405491d2cSKalle Valo sta = false;
12505491d2cSKalle Valo }
12605491d2cSKalle Valo hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
12705491d2cSKalle Valo BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
12819c8f421SHante Meuleman hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
12905491d2cSKalle Valo found = false;
13005491d2cSKalle Valo hash = flow->hash;
13105491d2cSKalle Valo for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
13205491d2cSKalle Valo if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) &&
13305491d2cSKalle Valo (is_zero_ether_addr(hash[hash_idx].mac))) {
13405491d2cSKalle Valo found = true;
13505491d2cSKalle Valo break;
13605491d2cSKalle Valo }
13705491d2cSKalle Valo hash_idx++;
13819c8f421SHante Meuleman hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
13905491d2cSKalle Valo }
14005491d2cSKalle Valo if (found) {
14105491d2cSKalle Valo for (i = 0; i < flow->nrofrings; i++) {
14205491d2cSKalle Valo if (flow->rings[i] == NULL)
14305491d2cSKalle Valo break;
14405491d2cSKalle Valo }
14505491d2cSKalle Valo if (i == flow->nrofrings)
14605491d2cSKalle Valo return -ENOMEM;
14705491d2cSKalle Valo
14805491d2cSKalle Valo ring = kzalloc(sizeof(*ring), GFP_ATOMIC);
14905491d2cSKalle Valo if (!ring)
15005491d2cSKalle Valo return -ENOMEM;
15105491d2cSKalle Valo
15205491d2cSKalle Valo memcpy(hash[hash_idx].mac, mac, ETH_ALEN);
15305491d2cSKalle Valo hash[hash_idx].fifo = fifo;
15405491d2cSKalle Valo hash[hash_idx].ifidx = ifidx;
15505491d2cSKalle Valo hash[hash_idx].flowid = i;
15605491d2cSKalle Valo
15705491d2cSKalle Valo ring->hash_id = hash_idx;
15805491d2cSKalle Valo ring->status = RING_CLOSED;
15905491d2cSKalle Valo skb_queue_head_init(&ring->skblist);
16005491d2cSKalle Valo flow->rings[i] = ring;
16105491d2cSKalle Valo
16205491d2cSKalle Valo return i;
16305491d2cSKalle Valo }
16405491d2cSKalle Valo return BRCMF_FLOWRING_INVALID_ID;
16505491d2cSKalle Valo }
16605491d2cSKalle Valo
16705491d2cSKalle Valo
brcmf_flowring_tid(struct brcmf_flowring * flow,u16 flowid)16819c8f421SHante Meuleman u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
16905491d2cSKalle Valo {
17005491d2cSKalle Valo struct brcmf_flowring_ring *ring;
17105491d2cSKalle Valo
17205491d2cSKalle Valo ring = flow->rings[flowid];
17305491d2cSKalle Valo
17405491d2cSKalle Valo return flow->hash[ring->hash_id].fifo;
17505491d2cSKalle Valo }
17605491d2cSKalle Valo
17705491d2cSKalle Valo
brcmf_flowring_block(struct brcmf_flowring * flow,u16 flowid,bool blocked)17819c8f421SHante Meuleman static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
17905491d2cSKalle Valo bool blocked)
18005491d2cSKalle Valo {
18105491d2cSKalle Valo struct brcmf_flowring_ring *ring;
18205491d2cSKalle Valo struct brcmf_bus *bus_if;
18305491d2cSKalle Valo struct brcmf_pub *drvr;
18405491d2cSKalle Valo struct brcmf_if *ifp;
18505491d2cSKalle Valo bool currently_blocked;
18605491d2cSKalle Valo int i;
18705491d2cSKalle Valo u8 ifidx;
18805491d2cSKalle Valo unsigned long flags;
18905491d2cSKalle Valo
19005491d2cSKalle Valo spin_lock_irqsave(&flow->block_lock, flags);
19105491d2cSKalle Valo
19205491d2cSKalle Valo ring = flow->rings[flowid];
19305491d2cSKalle Valo if (ring->blocked == blocked) {
19405491d2cSKalle Valo spin_unlock_irqrestore(&flow->block_lock, flags);
19505491d2cSKalle Valo return;
19605491d2cSKalle Valo }
19705491d2cSKalle Valo ifidx = brcmf_flowring_ifidx_get(flow, flowid);
19805491d2cSKalle Valo
19905491d2cSKalle Valo currently_blocked = false;
20005491d2cSKalle Valo for (i = 0; i < flow->nrofrings; i++) {
20105491d2cSKalle Valo if ((flow->rings[i]) && (i != flowid)) {
20205491d2cSKalle Valo ring = flow->rings[i];
20305491d2cSKalle Valo if ((ring->status == RING_OPEN) &&
20405491d2cSKalle Valo (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
20505491d2cSKalle Valo if (ring->blocked) {
20605491d2cSKalle Valo currently_blocked = true;
20705491d2cSKalle Valo break;
20805491d2cSKalle Valo }
20905491d2cSKalle Valo }
21005491d2cSKalle Valo }
21105491d2cSKalle Valo }
21205491d2cSKalle Valo flow->rings[flowid]->blocked = blocked;
21305491d2cSKalle Valo if (currently_blocked) {
21405491d2cSKalle Valo spin_unlock_irqrestore(&flow->block_lock, flags);
21505491d2cSKalle Valo return;
21605491d2cSKalle Valo }
21705491d2cSKalle Valo
21805491d2cSKalle Valo bus_if = dev_get_drvdata(flow->dev);
21905491d2cSKalle Valo drvr = bus_if->drvr;
22005491d2cSKalle Valo ifp = brcmf_get_ifp(drvr, ifidx);
22105491d2cSKalle Valo brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
22205491d2cSKalle Valo
22305491d2cSKalle Valo spin_unlock_irqrestore(&flow->block_lock, flags);
22405491d2cSKalle Valo }
22505491d2cSKalle Valo
22605491d2cSKalle Valo
brcmf_flowring_delete(struct brcmf_flowring * flow,u16 flowid)22719c8f421SHante Meuleman void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
22805491d2cSKalle Valo {
2297f00ee2bSRafał Miłecki struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
23005491d2cSKalle Valo struct brcmf_flowring_ring *ring;
2317f00ee2bSRafał Miłecki struct brcmf_if *ifp;
23219c8f421SHante Meuleman u16 hash_idx;
2337f00ee2bSRafał Miłecki u8 ifidx;
23405491d2cSKalle Valo struct sk_buff *skb;
23505491d2cSKalle Valo
23605491d2cSKalle Valo ring = flow->rings[flowid];
23705491d2cSKalle Valo if (!ring)
23805491d2cSKalle Valo return;
2397f00ee2bSRafał Miłecki
2407f00ee2bSRafał Miłecki ifidx = brcmf_flowring_ifidx_get(flow, flowid);
2417f00ee2bSRafał Miłecki ifp = brcmf_get_ifp(bus_if->drvr, ifidx);
2427f00ee2bSRafał Miłecki
24305491d2cSKalle Valo brcmf_flowring_block(flow, flowid, false);
24405491d2cSKalle Valo hash_idx = ring->hash_id;
24505491d2cSKalle Valo flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
24605491d2cSKalle Valo eth_zero_addr(flow->hash[hash_idx].mac);
24705491d2cSKalle Valo flow->rings[flowid] = NULL;
24805491d2cSKalle Valo
24905491d2cSKalle Valo skb = skb_dequeue(&ring->skblist);
25005491d2cSKalle Valo while (skb) {
2517f00ee2bSRafał Miłecki brcmf_txfinalize(ifp, skb, false);
25205491d2cSKalle Valo skb = skb_dequeue(&ring->skblist);
25305491d2cSKalle Valo }
25405491d2cSKalle Valo
25505491d2cSKalle Valo kfree(ring);
25605491d2cSKalle Valo }
25705491d2cSKalle Valo
25805491d2cSKalle Valo
brcmf_flowring_enqueue(struct brcmf_flowring * flow,u16 flowid,struct sk_buff * skb)25919c8f421SHante Meuleman u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
26005491d2cSKalle Valo struct sk_buff *skb)
26105491d2cSKalle Valo {
26205491d2cSKalle Valo struct brcmf_flowring_ring *ring;
26305491d2cSKalle Valo
26405491d2cSKalle Valo ring = flow->rings[flowid];
26505491d2cSKalle Valo
26605491d2cSKalle Valo skb_queue_tail(&ring->skblist, skb);
26705491d2cSKalle Valo
26805491d2cSKalle Valo if (!ring->blocked &&
26905491d2cSKalle Valo (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
27005491d2cSKalle Valo brcmf_flowring_block(flow, flowid, true);
27105491d2cSKalle Valo brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
27205491d2cSKalle Valo /* To prevent (work around) possible race condition, check
27305491d2cSKalle Valo * queue len again. It is also possible to use locking to
27405491d2cSKalle Valo * protect, but that is undesirable for every enqueue and
27505491d2cSKalle Valo * dequeue. This simple check will solve a possible race
27605491d2cSKalle Valo * condition if it occurs.
27705491d2cSKalle Valo */
27805491d2cSKalle Valo if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
27905491d2cSKalle Valo brcmf_flowring_block(flow, flowid, false);
28005491d2cSKalle Valo }
28105491d2cSKalle Valo return skb_queue_len(&ring->skblist);
28205491d2cSKalle Valo }
28305491d2cSKalle Valo
28405491d2cSKalle Valo
brcmf_flowring_dequeue(struct brcmf_flowring * flow,u16 flowid)28519c8f421SHante Meuleman struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
28605491d2cSKalle Valo {
28705491d2cSKalle Valo struct brcmf_flowring_ring *ring;
28805491d2cSKalle Valo struct sk_buff *skb;
28905491d2cSKalle Valo
29005491d2cSKalle Valo ring = flow->rings[flowid];
29105491d2cSKalle Valo if (ring->status != RING_OPEN)
29205491d2cSKalle Valo return NULL;
29305491d2cSKalle Valo
29405491d2cSKalle Valo skb = skb_dequeue(&ring->skblist);
29505491d2cSKalle Valo
29605491d2cSKalle Valo if (ring->blocked &&
29705491d2cSKalle Valo (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
29805491d2cSKalle Valo brcmf_flowring_block(flow, flowid, false);
29905491d2cSKalle Valo brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
30005491d2cSKalle Valo }
30105491d2cSKalle Valo
30205491d2cSKalle Valo return skb;
30305491d2cSKalle Valo }
30405491d2cSKalle Valo
30505491d2cSKalle Valo
brcmf_flowring_reinsert(struct brcmf_flowring * flow,u16 flowid,struct sk_buff * skb)30619c8f421SHante Meuleman void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
30705491d2cSKalle Valo struct sk_buff *skb)
30805491d2cSKalle Valo {
30905491d2cSKalle Valo struct brcmf_flowring_ring *ring;
31005491d2cSKalle Valo
31105491d2cSKalle Valo ring = flow->rings[flowid];
31205491d2cSKalle Valo
31305491d2cSKalle Valo skb_queue_head(&ring->skblist, skb);
31405491d2cSKalle Valo }
31505491d2cSKalle Valo
31605491d2cSKalle Valo
brcmf_flowring_qlen(struct brcmf_flowring * flow,u16 flowid)31719c8f421SHante Meuleman u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
31805491d2cSKalle Valo {
31905491d2cSKalle Valo struct brcmf_flowring_ring *ring;
32005491d2cSKalle Valo
32105491d2cSKalle Valo ring = flow->rings[flowid];
32205491d2cSKalle Valo if (!ring)
32305491d2cSKalle Valo return 0;
32405491d2cSKalle Valo
32505491d2cSKalle Valo if (ring->status != RING_OPEN)
32605491d2cSKalle Valo return 0;
32705491d2cSKalle Valo
32805491d2cSKalle Valo return skb_queue_len(&ring->skblist);
32905491d2cSKalle Valo }
33005491d2cSKalle Valo
33105491d2cSKalle Valo
brcmf_flowring_open(struct brcmf_flowring * flow,u16 flowid)33219c8f421SHante Meuleman void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
33305491d2cSKalle Valo {
33405491d2cSKalle Valo struct brcmf_flowring_ring *ring;
33505491d2cSKalle Valo
33605491d2cSKalle Valo ring = flow->rings[flowid];
33705491d2cSKalle Valo if (!ring) {
33805491d2cSKalle Valo brcmf_err("Ring NULL, for flowid %d\n", flowid);
33905491d2cSKalle Valo return;
34005491d2cSKalle Valo }
34105491d2cSKalle Valo
34205491d2cSKalle Valo ring->status = RING_OPEN;
34305491d2cSKalle Valo }
34405491d2cSKalle Valo
34505491d2cSKalle Valo
brcmf_flowring_ifidx_get(struct brcmf_flowring * flow,u16 flowid)34619c8f421SHante Meuleman u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
34705491d2cSKalle Valo {
34805491d2cSKalle Valo struct brcmf_flowring_ring *ring;
34919c8f421SHante Meuleman u16 hash_idx;
35005491d2cSKalle Valo
35105491d2cSKalle Valo ring = flow->rings[flowid];
35205491d2cSKalle Valo hash_idx = ring->hash_id;
35305491d2cSKalle Valo
35405491d2cSKalle Valo return flow->hash[hash_idx].ifidx;
35505491d2cSKalle Valo }
35605491d2cSKalle Valo
35705491d2cSKalle Valo
brcmf_flowring_attach(struct device * dev,u16 nrofrings)35805491d2cSKalle Valo struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
35905491d2cSKalle Valo {
36005491d2cSKalle Valo struct brcmf_flowring *flow;
36105491d2cSKalle Valo u32 i;
36205491d2cSKalle Valo
36305491d2cSKalle Valo flow = kzalloc(sizeof(*flow), GFP_KERNEL);
36405491d2cSKalle Valo if (flow) {
36505491d2cSKalle Valo flow->dev = dev;
36605491d2cSKalle Valo flow->nrofrings = nrofrings;
36705491d2cSKalle Valo spin_lock_init(&flow->block_lock);
36805491d2cSKalle Valo for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
36905491d2cSKalle Valo flow->addr_mode[i] = ADDR_INDIRECT;
37005491d2cSKalle Valo for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
37105491d2cSKalle Valo flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
37205491d2cSKalle Valo flow->rings = kcalloc(nrofrings, sizeof(*flow->rings),
37305491d2cSKalle Valo GFP_KERNEL);
37405491d2cSKalle Valo if (!flow->rings) {
37505491d2cSKalle Valo kfree(flow);
37605491d2cSKalle Valo flow = NULL;
37705491d2cSKalle Valo }
37805491d2cSKalle Valo }
37905491d2cSKalle Valo
38005491d2cSKalle Valo return flow;
38105491d2cSKalle Valo }
38205491d2cSKalle Valo
38305491d2cSKalle Valo
brcmf_flowring_detach(struct brcmf_flowring * flow)38405491d2cSKalle Valo void brcmf_flowring_detach(struct brcmf_flowring *flow)
38505491d2cSKalle Valo {
38605491d2cSKalle Valo struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
38705491d2cSKalle Valo struct brcmf_pub *drvr = bus_if->drvr;
38805491d2cSKalle Valo struct brcmf_flowring_tdls_entry *search;
38905491d2cSKalle Valo struct brcmf_flowring_tdls_entry *remove;
39019c8f421SHante Meuleman u16 flowid;
39105491d2cSKalle Valo
39205491d2cSKalle Valo for (flowid = 0; flowid < flow->nrofrings; flowid++) {
39305491d2cSKalle Valo if (flow->rings[flowid])
39405491d2cSKalle Valo brcmf_msgbuf_delete_flowring(drvr, flowid);
39505491d2cSKalle Valo }
39605491d2cSKalle Valo
39705491d2cSKalle Valo search = flow->tdls_entry;
39805491d2cSKalle Valo while (search) {
39905491d2cSKalle Valo remove = search;
40005491d2cSKalle Valo search = search->next;
40105491d2cSKalle Valo kfree(remove);
40205491d2cSKalle Valo }
40305491d2cSKalle Valo kfree(flow->rings);
40405491d2cSKalle Valo kfree(flow);
40505491d2cSKalle Valo }
40605491d2cSKalle Valo
40705491d2cSKalle Valo
brcmf_flowring_configure_addr_mode(struct brcmf_flowring * flow,int ifidx,enum proto_addr_mode addr_mode)40805491d2cSKalle Valo void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
40905491d2cSKalle Valo enum proto_addr_mode addr_mode)
41005491d2cSKalle Valo {
41105491d2cSKalle Valo struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
41205491d2cSKalle Valo struct brcmf_pub *drvr = bus_if->drvr;
41305491d2cSKalle Valo u32 i;
41419c8f421SHante Meuleman u16 flowid;
41505491d2cSKalle Valo
41605491d2cSKalle Valo if (flow->addr_mode[ifidx] != addr_mode) {
41705491d2cSKalle Valo for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
41805491d2cSKalle Valo if (flow->hash[i].ifidx == ifidx) {
41905491d2cSKalle Valo flowid = flow->hash[i].flowid;
42005491d2cSKalle Valo if (flow->rings[flowid]->status != RING_OPEN)
42105491d2cSKalle Valo continue;
42205491d2cSKalle Valo brcmf_msgbuf_delete_flowring(drvr, flowid);
42305491d2cSKalle Valo }
42405491d2cSKalle Valo }
42505491d2cSKalle Valo flow->addr_mode[ifidx] = addr_mode;
42605491d2cSKalle Valo }
42705491d2cSKalle Valo }
42805491d2cSKalle Valo
42905491d2cSKalle Valo
brcmf_flowring_delete_peer(struct brcmf_flowring * flow,int ifidx,u8 peer[ETH_ALEN])43005491d2cSKalle Valo void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
43105491d2cSKalle Valo u8 peer[ETH_ALEN])
43205491d2cSKalle Valo {
43305491d2cSKalle Valo struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
43405491d2cSKalle Valo struct brcmf_pub *drvr = bus_if->drvr;
43505491d2cSKalle Valo struct brcmf_flowring_hash *hash;
43605491d2cSKalle Valo struct brcmf_flowring_tdls_entry *prev;
43705491d2cSKalle Valo struct brcmf_flowring_tdls_entry *search;
43805491d2cSKalle Valo u32 i;
43919c8f421SHante Meuleman u16 flowid;
44005491d2cSKalle Valo bool sta;
44105491d2cSKalle Valo
44205491d2cSKalle Valo sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
44305491d2cSKalle Valo
44405491d2cSKalle Valo search = flow->tdls_entry;
44505491d2cSKalle Valo prev = NULL;
44605491d2cSKalle Valo while (search) {
44705491d2cSKalle Valo if (memcmp(search->mac, peer, ETH_ALEN) == 0) {
44805491d2cSKalle Valo sta = false;
44905491d2cSKalle Valo break;
45005491d2cSKalle Valo }
45105491d2cSKalle Valo prev = search;
45205491d2cSKalle Valo search = search->next;
45305491d2cSKalle Valo }
45405491d2cSKalle Valo
45505491d2cSKalle Valo hash = flow->hash;
45605491d2cSKalle Valo for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
45705491d2cSKalle Valo if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
45805491d2cSKalle Valo (hash[i].ifidx == ifidx)) {
45905491d2cSKalle Valo flowid = flow->hash[i].flowid;
460*09be7546SWright Feng if (flow->rings[flowid]->status == RING_OPEN)
46105491d2cSKalle Valo brcmf_msgbuf_delete_flowring(drvr, flowid);
46205491d2cSKalle Valo }
46305491d2cSKalle Valo }
46405491d2cSKalle Valo
46505491d2cSKalle Valo if (search) {
46605491d2cSKalle Valo if (prev)
46705491d2cSKalle Valo prev->next = search->next;
46805491d2cSKalle Valo else
46905491d2cSKalle Valo flow->tdls_entry = search->next;
47005491d2cSKalle Valo kfree(search);
47105491d2cSKalle Valo if (flow->tdls_entry == NULL)
47205491d2cSKalle Valo flow->tdls_active = false;
47305491d2cSKalle Valo }
47405491d2cSKalle Valo }
47505491d2cSKalle Valo
47605491d2cSKalle Valo
brcmf_flowring_add_tdls_peer(struct brcmf_flowring * flow,int ifidx,u8 peer[ETH_ALEN])47705491d2cSKalle Valo void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx,
47805491d2cSKalle Valo u8 peer[ETH_ALEN])
47905491d2cSKalle Valo {
48005491d2cSKalle Valo struct brcmf_flowring_tdls_entry *tdls_entry;
48105491d2cSKalle Valo struct brcmf_flowring_tdls_entry *search;
48205491d2cSKalle Valo
48305491d2cSKalle Valo tdls_entry = kzalloc(sizeof(*tdls_entry), GFP_ATOMIC);
48405491d2cSKalle Valo if (tdls_entry == NULL)
48505491d2cSKalle Valo return;
48605491d2cSKalle Valo
48705491d2cSKalle Valo memcpy(tdls_entry->mac, peer, ETH_ALEN);
48805491d2cSKalle Valo tdls_entry->next = NULL;
48905491d2cSKalle Valo if (flow->tdls_entry == NULL) {
49005491d2cSKalle Valo flow->tdls_entry = tdls_entry;
49105491d2cSKalle Valo } else {
49205491d2cSKalle Valo search = flow->tdls_entry;
49305491d2cSKalle Valo if (memcmp(search->mac, peer, ETH_ALEN) == 0)
494bc981641SArend Van Spriel goto free_entry;
49505491d2cSKalle Valo while (search->next) {
49605491d2cSKalle Valo search = search->next;
49705491d2cSKalle Valo if (memcmp(search->mac, peer, ETH_ALEN) == 0)
498bc981641SArend Van Spriel goto free_entry;
49905491d2cSKalle Valo }
50005491d2cSKalle Valo search->next = tdls_entry;
50105491d2cSKalle Valo }
50205491d2cSKalle Valo
50305491d2cSKalle Valo flow->tdls_active = true;
504bc981641SArend Van Spriel return;
505bc981641SArend Van Spriel
506bc981641SArend Van Spriel free_entry:
507bc981641SArend Van Spriel kfree(tdls_entry);
50805491d2cSKalle Valo }
509