📄 wlc_scb.c
字号:
WL_ASSOC(("wlc_scb : state = %x\n", scb->state));}/* * "& ~" operation . * idx = position of the bsscfg in the wlc array of multi ssids. */voidwlc_scb_clearstatebit_bsscfg(struct scb *scb, uint8 state, int idx){ int i; ASSERT(scb); WL_ASSOC(("clear state : %x bsscfg idx : %d\n", state, idx)); /* any clear of a stable state should lead to clear a bit Warning though : this implies that, if we want to switch from associated to authenticated, the clear happens before the set otherwise this bit will be clear in authenticated state. */ if ((state & AUTHENTICATED) || (state & ASSOCIATED) || (state & AUTHORIZED)) { clrbit(&scb->auth_bsscfg, idx); } /* quik hack .. clear first ... */ scb->state &= ~state; for (i = 0; i < SCB_BSSCFG_BITSIZE; i++) { /* reset if needed */ if (scb->auth_bsscfg[i]) { scb->state |= state; break; } }}/* reset all state. */voidwlc_scb_resetstate(struct scb *scb){ WL_ASSOC(("reset state\n")); ASSERT(scb); memset(&scb->auth_bsscfg, 0, SCB_BSSCFG_BITSIZE); scb->state = 0; WL_ASSOC(("wlc_scb : state = %x\n", scb->state));}/* initialize per-scb state utilized by rate selection */voidwlc_scb_rate_init(wlc_info_t *wlc, struct scb *scb){ wlc_rate_init(scb->ratestate, scb->rateset.rates, scb->rateset.count, scb->select_rateset.rates, &scb->select_rateset.count, 0, &scb->txc.txhlen);}voidwlc_scb_reinit(wlc_info_t *wlc){ uint prev_count; const rateset_t *rs; wlcband_t *band; struct scb *scb; struct scb_iter scbiter; /* sanitize any existing scb rates against the current hardware rates */ FOREACHSCB(&scbiter, wlc->scbstate->scb, scb) { prev_count = scb->rateset.count; /* Keep only CCK if gmode == GMODE_LEGACY_B */ band = ((struct scb_info*)scb)->band; if (ISGPHY(band->pi) && (band->gmode == GMODE_LEGACY_B)) { rs = cck_rates; } else { rs = &band->hw_rateset; } wlc_sort_rates(&scb->rateset, rs); /* if the count of rates is different, then the rate state * needs to be reinitialized */ if (scb->rateset.count != prev_count) wlc_scb_rate_init(wlc, scb); }}static INLINE struct scb*_wlc_scbfind(wlc_info_t *wlc, const struct ether_addr *ea, int bandunit){ int index; struct scb_info *scbinfo; /* map any multicast address into the single broadcast scb */ if (ETHER_ISMULTI(ea)) ea = ðer_bcast; index = SCBHASHINDEX(ea->octet); /* search for the scb which corresponds to the remote station ea */ scbinfo = (struct scb_info *)(SCBSTATE_PRIV(wlc->scbstate)->scbhash[bandunit][index]); for (; scbinfo; scbinfo = scbinfo->hashnext) { if (bcmp((char*)ea, (char*)&(scbinfo->scbpub.ea), ETHER_ADDR_LEN) == 0) break; } return (struct scb *)scbinfo;}/* Find station control block corresponding to the remote id */struct scb *wlc_scbfind(wlc_info_t *wlc, const struct ether_addr *ea){ return _wlc_scbfind(wlc, ea, wlc->band->bandunit);}/* * Lookup station control block corresponding to the remote id. * If not found, create a new entry. */static INLINE struct scb *_wlc_scblookup(wlc_info_t *wlc, const struct ether_addr *ea, int bandunit){ int index; struct scb *scb; scb_module_priv_t *scbstate; if ((scb = _wlc_scbfind(wlc, ea, bandunit))) { return (scb); } /* no scb match, allocate one */ if (!(scb = wlc_scballoc(wlc))) { WL_ERROR(("wl%d: wlc_scblookup: out of memory, malloced %d bytes\n", wlc->pub.unit, MALLOCED(wlc->pub.osh))); return (NULL); } /* map any multicast address into the single broadcast scb */ if (ETHER_ISMULTI(ea)) ea = ðer_bcast; scb->ea = *((struct ether_addr*)ea); /* install it in the cache */ scbstate = SCBSTATE_PRIV(wlc->scbstate); scb->bandunit = bandunit; index = SCBHASHINDEX(ea->octet); ((struct scb_info *)scb)->hashnext = (struct scb_info *)scbstate->scbhash[bandunit][index]; scbstate->scbhash[bandunit][index] = scb; /* send ofdm rate probe */ if (!wlc->pub.BSS && wlc->band->gmode && wlc->pub.up) wlc_rateprobe(wlc, (struct ether_addr*)ea, scb, WLC_RATEPROBE_RATE); return (scb);}struct scb *wlc_scblookup(wlc_info_t *wlc, const struct ether_addr *ea){ return (_wlc_scblookup(wlc, ea, wlc->band->bandunit));}struct scb *wlc_scblookupband(wlc_info_t *wlc, const struct ether_addr *ea, int bandunit){ /* assert that the band is the current band, or we are dual band and it is the other band */ ASSERT((bandunit == (int)wlc->band->bandunit) || (NBANDS(wlc) > 1 && bandunit == (int)OTHERBANDUNIT(wlc))); return (_wlc_scblookup(wlc, ea, bandunit));}/* Get scb from band */struct scb *wlc_scbfindband(wlc_info_t *wlc, const struct ether_addr *ea, int bandunit){ /* assert that the band is the current band, or we are dual band and it is the other band */ ASSERT((bandunit == (int)wlc->band->bandunit) || (NBANDS(wlc) > 1 && bandunit == (int)OTHERBANDUNIT(wlc))); return (_wlc_scbfind(wlc, ea, bandunit));}static voidwlc_scb_deauth_sendcomplete(wlc_info_t *wlc, uint txstatus, void *ea_arg){ struct scb *scb; /* Is this scb still around */ if ((scb = wlc_scbfind(wlc, (struct ether_addr*)ea_arg)) == NULL) return; /* As long as it made it, complete the state transition */ wlc_scb_resetstate(scb); /* delete pairwise key on deauthentication */ if (scb->key) { WL_WSEC(("wl%d: %s: deauthenticating sta, deleting pairwise" " key for %s\n", wlc->pub.unit, __FUNCTION__, bcm_ether_ntoa(&scb->ea, eabuf))); wlc_scb_key_delete(wlc, scb); }}/* (de)authorize/(de)authenticate single station * 'enable' TRUE means authorize, FLASE means deauthorize/deauthenticate * 'flag' is AUTHORIZED or AUTHENICATED for the type of operation * 'rc' is the reason code for a deauthenticate packet */voidwlc_scb_set_auth(wlc_info_t *wlc, struct scb *scb, bool enable, uint32 flag, int rc){ void *pkt = NULL; if (enable) { if (flag == AUTHORIZED) { wlc_scb_setstatebit(scb, AUTHORIZED); scb->flags &= ~SCB_DEAUTH; } else { wlc_scb_setstatebit(scb, AUTHENTICATED); } } else { if (flag == AUTHORIZED) { wlc_scb_clearstatebit(scb, AUTHORIZED); } else { if (wlc->pub.up && (SCB_AUTHENTICATED(scb))) { struct ether_addr *bssid; bssid = (scb->flags & SCB_MYAP) ? &wlc->BSSID : &wlc->announce_BSSID; pkt = wlc_senddeauth(wlc, &scb->ea, bssid, scb, (uint16)rc); } if (pkt == NULL || wlc_pkt_callback_register(wlc, wlc_scb_deauth_sendcomplete, (void *)&scb->ea, pkt)) WL_ERROR(("wl%d: wlc_scb_set_auth: could not register callback\n", wlc->pub.unit)); } } WL_ASSOC(("wl%d: %s %s%s\n", wlc->pub.unit, bcm_ether_ntoa(&scb->ea, eabuf), (enable ? "" : "de"), ((flag == AUTHORIZED) ? "authorized" : "authenticated")));}voidwlc_scb_sortrates(struct scb *scb){ struct scb_info *scbinfo = (struct scb_info *)scb; wlc_sort_rates(&scb->rateset, &scbinfo->band->hw_rateset);}voidBCMINITFN(wlc_scblist_validaterates)(wlc_info_t *wlc){ struct scb *scb; struct scb_iter scbiter; FOREACHSCB(&scbiter, wlc->scbstate->scb, scb) { wlc_scb_sortrates(scb); if (scb->rateset.count == 0) { wlc_scbfree(wlc, scb); } }}/* Give then tx_fn, return the feature id from txmod_fns array. * If tx_fn is NULL, 0 will be returned * If entry is not found, it's an ERROR! */static INLINE scb_txmod_twlc_txmod_fid(wlc_info_t *wlc, txmod_tx_fn_t tx_fn){ scb_txmod_t txmod; for (txmod = SCB_START; txmod < SCB_LAST; txmod++) if (tx_fn == wlc->txmod_fns[txmod].tx_fn) return txmod; /* Should not reach here */ ASSERT(txmod < SCB_LAST); return txmod;}/* Add a feature to the path. It should not be already on the path and should be configured * Does not take care of evicting anybody */static voidwlc_txmod_activate(wlc_info_t *wlc, struct scb *scb, scb_txmod_t fid){ /* Numeric value designating this feature's position in tx_path */ static const uint txmod_position[SCB_LAST] = { 0, /* SCB_START */ 1, /* SCB_CRAM */ 1, /* SCB_APPS */ 1, /* SCB_AMSDU */ 2, /* SCB_BA */ 2, /* SCB_AMPDU */ 3, /* SCB_TRANSMIT */ }; uint curr_mod_position; scb_txmod_t prev, next; txmod_info_t curr_mod_info = wlc->txmod_fns[fid]; ASSERT(SCB_TXMOD_CONFIGURED(scb, fid) && !SCB_TXMOD_ACTIVE(scb, fid)); curr_mod_position = txmod_position[fid]; prev = SCB_START; while ((next = wlc_txmod_fid(wlc, scb->tx_path[prev].next_tx_fn)) != 0 && txmod_position[next] < curr_mod_position) prev = next; /* next == 0 indicate this is the first addition to the path * it HAS to be SCB_TRANSMIT as it's the one that puts the packet in * txq. If this changes, then assert will need to be removed. */ ASSERT(next != 0 || fid == SCB_TRANSMIT); ASSERT(txmod_position[next] != curr_mod_position); SCB_TXMOD_SET(scb, prev, fid); SCB_TXMOD_SET(scb, fid, next); /* invoke any activate notify functions now that it's in the path */ if (curr_mod_info.activate_notify_fn) curr_mod_info.activate_notify_fn(curr_mod_info.ctx, scb);}/* Remove a fid from the path. It should be already on the path * Does not take care of replacing it with any other feature. */static voidwlc_txmod_deactivate(wlc_info_t *wlc, struct scb *scb, scb_txmod_t fid){ scb_txmod_t prev, next; txmod_info_t curr_mod_info = wlc->txmod_fns[fid]; /* If not active, do nothing */ if (!SCB_TXMOD_ACTIVE(scb, fid)) return; /* if deactivate notify function is present, call it */ if (curr_mod_info.deactivate_notify_fn) curr_mod_info.deactivate_notify_fn(curr_mod_info.ctx, scb); prev = SCB_START; while ((next = wlc_txmod_fid(wlc, scb->tx_path[prev].next_tx_fn)) != fid) prev = next; SCB_TXMOD_SET(scb, prev, wlc_txmod_fid(wlc, scb->tx_path[fid].next_tx_fn)); scb->tx_path[fid].next_tx_fn = NULL;}/* Add the fid to handle packets for this SCB, if allowed */voidwlc_txmod_config(wlc_info_t *wlc, struct scb *scb, scb_txmod_t fid){ ASSERT(fid < SCB_LAST); /* Don't do anything if not yet registered or * already configured */ if ((wlc->txmod_fns[fid].tx_fn == NULL) || (SCB_TXMOD_CONFIGURED(scb, fid))) return; /* Indicate that the feature is configured */ scb->tx_path[fid].configured = TRUE; ASSERT(!SCB_TXMOD_ACTIVE(scb, fid)); /* Try to activate this feature by adding it to the path * If conflicting features exist in the path, then * - If this feature is of higher precedence, deactivate other features * - Else, mark this feature deactivated * Note: When evicting other features, they remain 'configured' */ switch (fid) { case SCB_APPS: /* Deactivate CRAM/AMSDU/BA/AMPDU */ wlc_txmod_deactivate(wlc, scb, SCB_CRAM); wlc_txmod_deactivate(wlc, scb, SCB_AMSDU); wlc_txmod_deactivate(wlc, scb, SCB_BA); wlc_txmod_deactivate(wlc, scb, SCB_AMPDU); break; case SCB_CRAM: /* Don't activate if AMSDU or APPS are active */ if (SCB_TXMOD_ACTIVE(scb, SCB_AMSDU) || SCB_TXMOD_ACTIVE(scb, SCB_APPS)) return; break; case SCB_AMSDU: /* Don't activate if APPS is active */ if (SCB_TXMOD_ACTIVE(scb, SCB_APPS)) return; /* Deactivate CRAM if on path */ wlc_txmod_deactivate(wlc, scb, SCB_CRAM); break; case SCB_BA: /* Don't activate if AMPDU is active */ if (SCB_TXMOD_ACTIVE(scb, SCB_AMPDU)) return; /* Don't activate if APPS is active */ if (SCB_TXMOD_ACTIVE(scb, SCB_APPS)) return; break; case SCB_AMPDU: /* Don't activate if APPS is active */ if (SCB_TXMOD_ACTIVE(scb, SCB_APPS)) return; /* Deactivate BA if on path */ wlc_txmod_deactivate(wlc, scb, SCB_BA); break; case SCB_TRANSMIT: break; case SCB_START: case SCB_LAST: ASSERT(0); }; wlc_txmod_activate(wlc, scb, fid);}/* Remove the feature to handle packets for this SCB. * If just configured but not in path, just marked unconfigured * If in path, feature is removed and, if applicable, replaced by any other feature */voidwlc_txmod_unconfig(wlc_info_t *wlc, struct scb *scb, scb_txmod_t fid){ ASSERT(fid < SCB_LAST && fid != SCB_TRANSMIT); if (!SCB_TXMOD_CONFIGURED(scb, fid)) return; scb->tx_path[fid].configured = FALSE; /* Nothing to do if not active */ if (!SCB_TXMOD_ACTIVE(scb, fid)) return; wlc_txmod_deactivate(wlc, scb, fid); /* Restore any other features to the path */ /* APPS unconfigured => CRAM/AMSDU/BA can be active * AMSDU unconfigured => CRAM can be active */ switch (fid) { case SCB_APPS: /* Activate AMSDU/BA/CRAM if configured * Order below helps reduce redundant operations * if both CRAM/AMSDU are configured */ if (SCB_TXMOD_CONFIGURED(scb, SCB_AMSDU)) wlc_txmod_activate(wlc, scb, SCB_AMSDU); else if (SCB_TXMOD_CONFIGURED(scb, SCB_CRAM)) wlc_txmod_activate(wlc, scb, SCB_CRAM); if (SCB_TXMOD_CONFIGURED(scb, SCB_BA)) wlc_txmod_activate(wlc, scb, SCB_BA); if (SCB_TXMOD_CONFIGURED(scb, SCB_AMPDU)) wlc_txmod_activate(wlc, scb, SCB_AMPDU); break; case SCB_AMSDU: /* Activate CRAM if configured and APPS is not active */ if (SCB_TXMOD_CONFIGURED(scb, SCB_CRAM) && !SCB_TXMOD_ACTIVE(scb, SCB_APPS)) wlc_txmod_activate(wlc, scb, SCB_CRAM); break; case SCB_CRAM: case SCB_BA: case SCB_AMPDU: case SCB_TRANSMIT: case SCB_START: case SCB_LAST: break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -