/* Handle a STA interface link status update */ int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, uint8 status) { if_flow_lkup_t *if_flow_lkup; unsigned long flags; ASSERT(ifindex < DHD_MAX_IFS); if (ifindex >= DHD_MAX_IFS) return BCME_BADARG; DHD_INFO(("%s: ifindex %d status %d\n", __FUNCTION__, ifindex, status)); DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { if (status) if_flow_lkup[ifindex].status = TRUE; else if_flow_lkup[ifindex].status = FALSE; } DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); return BCME_OK; }
/* For a given interface, search the hash table for a matching flow */ uint16 dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) { int hash; bool ismcast = FALSE; flow_hash_info_t *cur; if_flow_lkup_t *if_flow_lkup; unsigned long flags; DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { #ifdef WLTDLS if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) && is_tdls_destination(dhdp, da)) { hash = DHD_FLOWRING_HASHINDEX(da, prio); cur = if_flow_lkup[ifindex].fl_hash[hash]; while (cur != NULL) { if (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN)) { DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); return cur->flowid; } cur = cur->next; } DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); return FLOWID_INVALID; } #endif /* WLTDLS */ cur = if_flow_lkup[ifindex].fl_hash[prio]; if (cur) { DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); return cur->flowid; } } else { if (ETHER_ISMULTI(da)) { ismcast = TRUE; hash = 0; } else { hash = DHD_FLOWRING_HASHINDEX(da, prio); } cur = if_flow_lkup[ifindex].fl_hash[hash]; while (cur) { if ((ismcast && ETHER_ISMULTI(cur->flow_info.da)) || (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN) && (cur->flow_info.tid == prio))) { DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); return cur->flowid; } cur = cur->next; } } DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); return FLOWID_INVALID; }
/* Handle Interface ADD, DEL operations */ void dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, uint8 op, uint8 role) { if_flow_lkup_t *if_flow_lkup; unsigned long flags; ASSERT(ifindex < DHD_MAX_IFS); if (ifindex >= DHD_MAX_IFS) return; DHD_INFO(("%s: ifindex %u op %u role is %u \n", __FUNCTION__, ifindex, op, role)); if (!dhdp->flowid_allocator) { DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); return; } DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) { if_flow_lkup[ifindex].role = role; if (!(DHD_IF_ROLE_STA(role))) { if_flow_lkup[ifindex].status = TRUE; DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n", __FUNCTION__, ifindex, role)); /* Create Mcast Flow */ } } else if (op == WLC_E_IF_DEL) { if_flow_lkup[ifindex].status = FALSE; DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n", __FUNCTION__, ifindex, role)); } DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); }
/* Allocate Flow ID */ static INLINE uint16 dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) { flow_hash_info_t *fl_hash_node, *cur; if_flow_lkup_t *if_flow_lkup; int hash; uint16 flowid; unsigned long flags; fl_hash_node = (flow_hash_info_t *) MALLOC(dhdp->osh, sizeof(flow_hash_info_t)); memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da)); DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ASSERT(dhdp->flowid_allocator != NULL); flowid = id16_map_alloc(dhdp->flowid_allocator); DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); if (flowid == FLOWID_INVALID) { MFREE(dhdp->osh, fl_hash_node, sizeof(flow_hash_info_t)); DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__)); return FLOWID_INVALID; } fl_hash_node->flowid = flowid; fl_hash_node->flow_info.tid = prio; fl_hash_node->flow_info.ifindex = ifindex; fl_hash_node->next = NULL; DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) { /* For STA non TDLS dest we allocate entry based on prio only */ #ifdef WLTDLS if (dhdp->peer_tbl.tdls_peer_count && (is_tdls_destination(dhdp, da))) { hash = DHD_FLOWRING_HASHINDEX(da, prio); cur = if_flow_lkup[ifindex].fl_hash[hash]; if (cur) { while (cur->next) { cur = cur->next; } cur->next = fl_hash_node; } else { if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; } } else #endif /* WLTDLS */ if_flow_lkup[ifindex].fl_hash[prio] = fl_hash_node; } else { /* For bcast/mcast assign first slot in in interface */ hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio); cur = if_flow_lkup[ifindex].fl_hash[hash]; if (cur) { while (cur->next) { cur = cur->next; } cur->next = fl_hash_node; } else if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; } DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid)); return fl_hash_node->flowid; }