0001
0002
0003
0004
0005
0006
0007 #include <linux/types.h>
0008 #include <linux/netdevice.h>
0009 #include <linux/etherdevice.h>
0010 #include <brcmu_utils.h>
0011
0012 #include "core.h"
0013 #include "debug.h"
0014 #include "bus.h"
0015 #include "proto.h"
0016 #include "flowring.h"
0017 #include "msgbuf.h"
0018 #include "common.h"
0019
0020
0021 #define BRCMF_FLOWRING_HIGH 1024
0022 #define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
0023 #define BRCMF_FLOWRING_INVALID_IFIDX 0xff
0024
0025 #define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
0026 #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
0027
0028 static const u8 brcmf_flowring_prio2fifo[] = {
0029 0,
0030 1,
0031 1,
0032 0,
0033 2,
0034 2,
0035 3,
0036 3
0037 };
0038
0039 static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
0040
0041
0042 static bool
0043 brcmf_flowring_is_tdls_mac(struct brcmf_flowring *flow, u8 mac[ETH_ALEN])
0044 {
0045 struct brcmf_flowring_tdls_entry *search;
0046
0047 search = flow->tdls_entry;
0048
0049 while (search) {
0050 if (memcmp(search->mac, mac, ETH_ALEN) == 0)
0051 return true;
0052 search = search->next;
0053 }
0054
0055 return false;
0056 }
0057
0058
0059 u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
0060 u8 prio, u8 ifidx)
0061 {
0062 struct brcmf_flowring_hash *hash;
0063 u16 hash_idx;
0064 u32 i;
0065 bool found;
0066 bool sta;
0067 u8 fifo;
0068 u8 *mac;
0069
0070 fifo = brcmf_flowring_prio2fifo[prio];
0071 sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
0072 mac = da;
0073 if ((!sta) && (is_multicast_ether_addr(da))) {
0074 mac = (u8 *)ALLFFMAC;
0075 fifo = 0;
0076 }
0077 if ((sta) && (flow->tdls_active) &&
0078 (brcmf_flowring_is_tdls_mac(flow, da))) {
0079 sta = false;
0080 }
0081 hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
0082 BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
0083 hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
0084 found = false;
0085 hash = flow->hash;
0086 for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
0087 if ((sta || (memcmp(hash[hash_idx].mac, mac, ETH_ALEN) == 0)) &&
0088 (hash[hash_idx].fifo == fifo) &&
0089 (hash[hash_idx].ifidx == ifidx)) {
0090 found = true;
0091 break;
0092 }
0093 hash_idx++;
0094 hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
0095 }
0096 if (found)
0097 return hash[hash_idx].flowid;
0098
0099 return BRCMF_FLOWRING_INVALID_ID;
0100 }
0101
0102
0103 u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
0104 u8 prio, u8 ifidx)
0105 {
0106 struct brcmf_flowring_ring *ring;
0107 struct brcmf_flowring_hash *hash;
0108 u16 hash_idx;
0109 u32 i;
0110 bool found;
0111 u8 fifo;
0112 bool sta;
0113 u8 *mac;
0114
0115 fifo = brcmf_flowring_prio2fifo[prio];
0116 sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
0117 mac = da;
0118 if ((!sta) && (is_multicast_ether_addr(da))) {
0119 mac = (u8 *)ALLFFMAC;
0120 fifo = 0;
0121 }
0122 if ((sta) && (flow->tdls_active) &&
0123 (brcmf_flowring_is_tdls_mac(flow, da))) {
0124 sta = false;
0125 }
0126 hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
0127 BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
0128 hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
0129 found = false;
0130 hash = flow->hash;
0131 for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
0132 if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) &&
0133 (is_zero_ether_addr(hash[hash_idx].mac))) {
0134 found = true;
0135 break;
0136 }
0137 hash_idx++;
0138 hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
0139 }
0140 if (found) {
0141 for (i = 0; i < flow->nrofrings; i++) {
0142 if (flow->rings[i] == NULL)
0143 break;
0144 }
0145 if (i == flow->nrofrings)
0146 return -ENOMEM;
0147
0148 ring = kzalloc(sizeof(*ring), GFP_ATOMIC);
0149 if (!ring)
0150 return -ENOMEM;
0151
0152 memcpy(hash[hash_idx].mac, mac, ETH_ALEN);
0153 hash[hash_idx].fifo = fifo;
0154 hash[hash_idx].ifidx = ifidx;
0155 hash[hash_idx].flowid = i;
0156
0157 ring->hash_id = hash_idx;
0158 ring->status = RING_CLOSED;
0159 skb_queue_head_init(&ring->skblist);
0160 flow->rings[i] = ring;
0161
0162 return i;
0163 }
0164 return BRCMF_FLOWRING_INVALID_ID;
0165 }
0166
0167
0168 u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
0169 {
0170 struct brcmf_flowring_ring *ring;
0171
0172 ring = flow->rings[flowid];
0173
0174 return flow->hash[ring->hash_id].fifo;
0175 }
0176
0177
0178 static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
0179 bool blocked)
0180 {
0181 struct brcmf_flowring_ring *ring;
0182 struct brcmf_bus *bus_if;
0183 struct brcmf_pub *drvr;
0184 struct brcmf_if *ifp;
0185 bool currently_blocked;
0186 int i;
0187 u8 ifidx;
0188 unsigned long flags;
0189
0190 spin_lock_irqsave(&flow->block_lock, flags);
0191
0192 ring = flow->rings[flowid];
0193 if (ring->blocked == blocked) {
0194 spin_unlock_irqrestore(&flow->block_lock, flags);
0195 return;
0196 }
0197 ifidx = brcmf_flowring_ifidx_get(flow, flowid);
0198
0199 currently_blocked = false;
0200 for (i = 0; i < flow->nrofrings; i++) {
0201 if ((flow->rings[i]) && (i != flowid)) {
0202 ring = flow->rings[i];
0203 if ((ring->status == RING_OPEN) &&
0204 (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
0205 if (ring->blocked) {
0206 currently_blocked = true;
0207 break;
0208 }
0209 }
0210 }
0211 }
0212 flow->rings[flowid]->blocked = blocked;
0213 if (currently_blocked) {
0214 spin_unlock_irqrestore(&flow->block_lock, flags);
0215 return;
0216 }
0217
0218 bus_if = dev_get_drvdata(flow->dev);
0219 drvr = bus_if->drvr;
0220 ifp = brcmf_get_ifp(drvr, ifidx);
0221 brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
0222
0223 spin_unlock_irqrestore(&flow->block_lock, flags);
0224 }
0225
0226
0227 void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
0228 {
0229 struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
0230 struct brcmf_flowring_ring *ring;
0231 struct brcmf_if *ifp;
0232 u16 hash_idx;
0233 u8 ifidx;
0234 struct sk_buff *skb;
0235
0236 ring = flow->rings[flowid];
0237 if (!ring)
0238 return;
0239
0240 ifidx = brcmf_flowring_ifidx_get(flow, flowid);
0241 ifp = brcmf_get_ifp(bus_if->drvr, ifidx);
0242
0243 brcmf_flowring_block(flow, flowid, false);
0244 hash_idx = ring->hash_id;
0245 flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
0246 eth_zero_addr(flow->hash[hash_idx].mac);
0247 flow->rings[flowid] = NULL;
0248
0249 skb = skb_dequeue(&ring->skblist);
0250 while (skb) {
0251 brcmf_txfinalize(ifp, skb, false);
0252 skb = skb_dequeue(&ring->skblist);
0253 }
0254
0255 kfree(ring);
0256 }
0257
0258
0259 u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
0260 struct sk_buff *skb)
0261 {
0262 struct brcmf_flowring_ring *ring;
0263
0264 ring = flow->rings[flowid];
0265
0266 skb_queue_tail(&ring->skblist, skb);
0267
0268 if (!ring->blocked &&
0269 (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
0270 brcmf_flowring_block(flow, flowid, true);
0271 brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
0272
0273
0274
0275
0276
0277
0278 if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
0279 brcmf_flowring_block(flow, flowid, false);
0280 }
0281 return skb_queue_len(&ring->skblist);
0282 }
0283
0284
0285 struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
0286 {
0287 struct brcmf_flowring_ring *ring;
0288 struct sk_buff *skb;
0289
0290 ring = flow->rings[flowid];
0291 if (ring->status != RING_OPEN)
0292 return NULL;
0293
0294 skb = skb_dequeue(&ring->skblist);
0295
0296 if (ring->blocked &&
0297 (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
0298 brcmf_flowring_block(flow, flowid, false);
0299 brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
0300 }
0301
0302 return skb;
0303 }
0304
0305
0306 void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
0307 struct sk_buff *skb)
0308 {
0309 struct brcmf_flowring_ring *ring;
0310
0311 ring = flow->rings[flowid];
0312
0313 skb_queue_head(&ring->skblist, skb);
0314 }
0315
0316
0317 u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
0318 {
0319 struct brcmf_flowring_ring *ring;
0320
0321 ring = flow->rings[flowid];
0322 if (!ring)
0323 return 0;
0324
0325 if (ring->status != RING_OPEN)
0326 return 0;
0327
0328 return skb_queue_len(&ring->skblist);
0329 }
0330
0331
0332 void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
0333 {
0334 struct brcmf_flowring_ring *ring;
0335
0336 ring = flow->rings[flowid];
0337 if (!ring) {
0338 brcmf_err("Ring NULL, for flowid %d\n", flowid);
0339 return;
0340 }
0341
0342 ring->status = RING_OPEN;
0343 }
0344
0345
0346 u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
0347 {
0348 struct brcmf_flowring_ring *ring;
0349 u16 hash_idx;
0350
0351 ring = flow->rings[flowid];
0352 hash_idx = ring->hash_id;
0353
0354 return flow->hash[hash_idx].ifidx;
0355 }
0356
0357
0358 struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
0359 {
0360 struct brcmf_flowring *flow;
0361 u32 i;
0362
0363 flow = kzalloc(sizeof(*flow), GFP_KERNEL);
0364 if (flow) {
0365 flow->dev = dev;
0366 flow->nrofrings = nrofrings;
0367 spin_lock_init(&flow->block_lock);
0368 for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
0369 flow->addr_mode[i] = ADDR_INDIRECT;
0370 for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
0371 flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
0372 flow->rings = kcalloc(nrofrings, sizeof(*flow->rings),
0373 GFP_KERNEL);
0374 if (!flow->rings) {
0375 kfree(flow);
0376 flow = NULL;
0377 }
0378 }
0379
0380 return flow;
0381 }
0382
0383
0384 void brcmf_flowring_detach(struct brcmf_flowring *flow)
0385 {
0386 struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
0387 struct brcmf_pub *drvr = bus_if->drvr;
0388 struct brcmf_flowring_tdls_entry *search;
0389 struct brcmf_flowring_tdls_entry *remove;
0390 u16 flowid;
0391
0392 for (flowid = 0; flowid < flow->nrofrings; flowid++) {
0393 if (flow->rings[flowid])
0394 brcmf_msgbuf_delete_flowring(drvr, flowid);
0395 }
0396
0397 search = flow->tdls_entry;
0398 while (search) {
0399 remove = search;
0400 search = search->next;
0401 kfree(remove);
0402 }
0403 kfree(flow->rings);
0404 kfree(flow);
0405 }
0406
0407
0408 void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
0409 enum proto_addr_mode addr_mode)
0410 {
0411 struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
0412 struct brcmf_pub *drvr = bus_if->drvr;
0413 u32 i;
0414 u16 flowid;
0415
0416 if (flow->addr_mode[ifidx] != addr_mode) {
0417 for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
0418 if (flow->hash[i].ifidx == ifidx) {
0419 flowid = flow->hash[i].flowid;
0420 if (flow->rings[flowid]->status != RING_OPEN)
0421 continue;
0422 flow->rings[flowid]->status = RING_CLOSING;
0423 brcmf_msgbuf_delete_flowring(drvr, flowid);
0424 }
0425 }
0426 flow->addr_mode[ifidx] = addr_mode;
0427 }
0428 }
0429
0430
0431 void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
0432 u8 peer[ETH_ALEN])
0433 {
0434 struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
0435 struct brcmf_pub *drvr = bus_if->drvr;
0436 struct brcmf_flowring_hash *hash;
0437 struct brcmf_flowring_tdls_entry *prev;
0438 struct brcmf_flowring_tdls_entry *search;
0439 u32 i;
0440 u16 flowid;
0441 bool sta;
0442
0443 sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
0444
0445 search = flow->tdls_entry;
0446 prev = NULL;
0447 while (search) {
0448 if (memcmp(search->mac, peer, ETH_ALEN) == 0) {
0449 sta = false;
0450 break;
0451 }
0452 prev = search;
0453 search = search->next;
0454 }
0455
0456 hash = flow->hash;
0457 for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
0458 if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
0459 (hash[i].ifidx == ifidx)) {
0460 flowid = flow->hash[i].flowid;
0461 if (flow->rings[flowid]->status == RING_OPEN) {
0462 flow->rings[flowid]->status = RING_CLOSING;
0463 brcmf_msgbuf_delete_flowring(drvr, flowid);
0464 }
0465 }
0466 }
0467
0468 if (search) {
0469 if (prev)
0470 prev->next = search->next;
0471 else
0472 flow->tdls_entry = search->next;
0473 kfree(search);
0474 if (flow->tdls_entry == NULL)
0475 flow->tdls_active = false;
0476 }
0477 }
0478
0479
0480 void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx,
0481 u8 peer[ETH_ALEN])
0482 {
0483 struct brcmf_flowring_tdls_entry *tdls_entry;
0484 struct brcmf_flowring_tdls_entry *search;
0485
0486 tdls_entry = kzalloc(sizeof(*tdls_entry), GFP_ATOMIC);
0487 if (tdls_entry == NULL)
0488 return;
0489
0490 memcpy(tdls_entry->mac, peer, ETH_ALEN);
0491 tdls_entry->next = NULL;
0492 if (flow->tdls_entry == NULL) {
0493 flow->tdls_entry = tdls_entry;
0494 } else {
0495 search = flow->tdls_entry;
0496 if (memcmp(search->mac, peer, ETH_ALEN) == 0)
0497 goto free_entry;
0498 while (search->next) {
0499 search = search->next;
0500 if (memcmp(search->mac, peer, ETH_ALEN) == 0)
0501 goto free_entry;
0502 }
0503 search->next = tdls_entry;
0504 }
0505
0506 flow->tdls_active = true;
0507 return;
0508
0509 free_entry:
0510 kfree(tdls_entry);
0511 }