static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, const u8 *perr_elem) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; u8 ttl; const u8 *ta, *target_addr; u32 target_sn; u16 target_rcode; ta = mgmt->sa; ttl = PERR_IE_TTL(perr_elem); if (ttl <= 1) { ifmsh->mshstats.dropped_frames_ttl++; return; } ttl--; target_addr = PERR_IE_TARGET_ADDR(perr_elem); target_sn = PERR_IE_TARGET_SN(perr_elem); target_rcode = PERR_IE_TARGET_RCODE(perr_elem); rcu_read_lock(); mpath = mesh_path_lookup(sdata, target_addr); if (mpath) { struct sta_info *sta; spin_lock_bh(&mpath->state_lock); sta = next_hop_deref_protected(mpath); if (mpath->flags & MESH_PATH_ACTIVE && ether_addr_equal(ta, sta->sta.addr) && !(mpath->flags & MESH_PATH_FIXED) && (!(mpath->flags & MESH_PATH_SN_VALID) || SN_GT(target_sn, mpath->sn) || target_sn == 0)) { mpath->flags &= ~MESH_PATH_ACTIVE; if (target_sn != 0) mpath->sn = target_sn; else mpath->sn += 1; spin_unlock_bh(&mpath->state_lock); if (!ifmsh->mshcfg.dot11MeshForwarding) goto endperr; mesh_path_error_tx(sdata, ttl, target_addr, target_sn, target_rcode, broadcast_addr); } else spin_unlock_bh(&mpath->state_lock); } endperr: rcu_read_unlock(); }
static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, u8 *perr_elem) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; u8 ttl; u8 *ta, *target_addr; u32 target_sn; u16 target_rcode; ta = mgmt->sa; ttl = PERR_IE_TTL(perr_elem); if (ttl <= 1) { ifmsh->mshstats.dropped_frames_ttl++; return; } ttl--; target_addr = PERR_IE_TARGET_ADDR(perr_elem); target_sn = PERR_IE_TARGET_SN(perr_elem); target_rcode = PERR_IE_TARGET_RCODE(perr_elem); rcu_read_lock(); mpath = mesh_path_lookup(target_addr, sdata); if (mpath) { spin_lock_bh(&mpath->state_lock); if (mpath->flags & MESH_PATH_ACTIVE && memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN) == 0 && (!(mpath->flags & MESH_PATH_SN_VALID) || SN_GT(target_sn, mpath->sn))) { mpath->flags &= ~MESH_PATH_ACTIVE; mpath->sn = target_sn; spin_unlock_bh(&mpath->state_lock); mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), cpu_to_le16(target_rcode), broadcast_addr, sdata); } else spin_unlock_bh(&mpath->state_lock); } rcu_read_unlock(); }
static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, u8 *prep_elem, u32 metric) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; u8 *target_addr, *orig_addr; u8 ttl, hopcount, flags; u8 next_hop[ETH_ALEN]; u32 target_sn, orig_sn, lifetime; mhwmp_dbg(sdata, "received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem)); orig_addr = PREP_IE_ORIG_ADDR(prep_elem); if (ether_addr_equal(orig_addr, sdata->vif.addr)) /* destination, no forwarding required */ return; if (!ifmsh->mshcfg.dot11MeshForwarding) return; ttl = PREP_IE_TTL(prep_elem); if (ttl <= 1) { sdata->u.mesh.mshstats.dropped_frames_ttl++; return; } rcu_read_lock(); mpath = mesh_path_lookup(orig_addr, sdata); if (mpath) spin_lock_bh(&mpath->state_lock); else goto fail; if (!(mpath->flags & MESH_PATH_ACTIVE)) { spin_unlock_bh(&mpath->state_lock); goto fail; } memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN); spin_unlock_bh(&mpath->state_lock); --ttl; flags = PREP_IE_FLAGS(prep_elem); lifetime = PREP_IE_LIFETIME(prep_elem); hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; target_addr = PREP_IE_TARGET_ADDR(prep_elem); target_sn = PREP_IE_TARGET_SN(prep_elem); orig_sn = PREP_IE_ORIG_SN(prep_elem); mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, cpu_to_le32(orig_sn), 0, target_addr, cpu_to_le32(target_sn), next_hop, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); sdata->u.mesh.mshstats.fwded_unicast++; sdata->u.mesh.mshstats.fwded_frames++; return; fail: rcu_read_unlock(); sdata->u.mesh.mshstats.dropped_frames_no_route++; }
static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, u8 *prep_elem, u32 metric) { struct mesh_path *mpath; u8 *target_addr, *orig_addr; u8 ttl, hopcount, flags; u8 next_hop[ETH_ALEN]; u32 target_sn, orig_sn, lifetime; mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem)); /* Note that we divert from the draft nomenclature and denominate * destination to what the draft refers to as origininator. So in this * function destnation refers to the final destination of the PREP, * which corresponds with the originator of the PREQ which this PREP * replies */ target_addr = PREP_IE_TARGET_ADDR(prep_elem); if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) /* destination, no forwarding required */ return; ttl = PREP_IE_TTL(prep_elem); if (ttl <= 1) { sdata->u.mesh.mshstats.dropped_frames_ttl++; return; } rcu_read_lock(); mpath = mesh_path_lookup(target_addr, sdata); if (mpath) spin_lock_bh(&mpath->state_lock); else goto fail; if (!(mpath->flags & MESH_PATH_ACTIVE)) { spin_unlock_bh(&mpath->state_lock); goto fail; } memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN); spin_unlock_bh(&mpath->state_lock); --ttl; flags = PREP_IE_FLAGS(prep_elem); lifetime = PREP_IE_LIFETIME(prep_elem); hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; orig_addr = PREP_IE_ORIG_ADDR(prep_elem); target_sn = PREP_IE_TARGET_SN(prep_elem); orig_sn = PREP_IE_ORIG_SN(prep_elem); mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, cpu_to_le32(orig_sn), 0, target_addr, cpu_to_le32(target_sn), next_hop, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); sdata->u.mesh.mshstats.fwded_unicast++; sdata->u.mesh.mshstats.fwded_frames++; return; fail: rcu_read_unlock(); sdata->u.mesh.mshstats.dropped_frames_no_route++; }