static u32 mesh_table_hash(constvoid *addr, u32 len, u32 seed)
{ /* Use last four bytes of hw addr as hash index */ return jhash_1word(get_unaligned((u32 *)((u8 *)addr + 2)), seed);
}
/** * mesh_path_assign_nexthop - update mesh path next hop * * @mpath: mesh path to update * @sta: next hop to assign * * Locking: mpath->state_lock must be held when calling this function
*/ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
{ struct sk_buff *skb; struct ieee80211_hdr *hdr; unsignedlong flags;
/** * mesh_path_move_to_queue - Move or copy frames from one mpath queue to another * * @gate_mpath: An active mpath the frames will be sent to (i.e. the gate) * @from_mpath: The failed mpath * @copy: When true, copy all the frames to the new mpath queue. When false, * move them. * * This function is used to transfer or copy frames from an unresolved mpath to * a gate mpath. The function also adds the Address Extension field and * updates the next hop. * * If a frame already has an Address Extension field, only the next hop and * destination addresses are updated. * * The gate mpath must be an active mpath with a valid mpath->next_hop.
*/ staticvoid mesh_path_move_to_queue(struct mesh_path *gate_mpath, struct mesh_path *from_mpath, bool copy)
{ struct sk_buff *skb, *fskb, *tmp; struct sk_buff_head failq; unsignedlong flags;
if (WARN_ON(gate_mpath == from_mpath)) return; if (WARN_ON(!gate_mpath->next_hop)) return;
/** * mesh_path_lookup - look up a path in the mesh path table * @sdata: local subif * @dst: hardware address (ETH_ALEN length) of destination * * Returns: pointer to the mesh path structure, or NULL if not found * * Locking: must be called within a read rcu section.
*/ struct mesh_path *
mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
{ return mpath_lookup(&sdata->u.mesh.mesh_paths, dst, sdata);
}
/** * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index * @sdata: local subif, or NULL for all entries * @idx: index * * Returns: pointer to the mesh path structure, or NULL if not found. * * Locking: must be called within a read rcu section.
*/ struct mesh_path *
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
{ return __mesh_path_lookup_by_idx(&sdata->u.mesh.mesh_paths, idx);
}
/** * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index * @sdata: local subif, or NULL for all entries * @idx: index * * Returns: pointer to the proxy path structure, or NULL if not found. * * Locking: must be called within a read rcu section.
*/ struct mesh_path *
mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
{ return __mesh_path_lookup_by_idx(&sdata->u.mesh.mpp_paths, idx);
}
/** * mesh_path_add_gate - add the given mpath to a mesh gate to our path table * @mpath: gate path to add to table * * Returns: 0 on success, -EEXIST
*/ int mesh_path_add_gate(struct mesh_path *mpath)
{ struct mesh_table *tbl; int err;
mpath_dbg(mpath->sdata, "Mesh path: Recorded new gate: %pM. %d known gates\n",
mpath->dst, mpath->sdata->u.mesh.num_gates);
err = 0;
err_rcu:
rcu_read_unlock(); return err;
}
/** * mesh_gate_del - remove a mesh gate from the list of known gates * @tbl: table which holds our list of known gates * @mpath: gate mpath
*/ staticvoid mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
{
lockdep_assert_held(&mpath->state_lock); if (!mpath->is_gate) return;
/** * mesh_gate_num - number of gates known to this interface * @sdata: subif data * * Returns: The number of gates
*/ int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
{ return sdata->u.mesh.num_gates;
}
cache = &sdata->u.mesh.tx_cache; if (atomic_read(&cache->rht.nelems) >= MESH_FAST_TX_CACHE_MAX_SIZE) return;
sta = rcu_dereference(mpath->next_hop); if (!sta) return;
build.key.type = MESH_FAST_TX_TYPE_LOCAL; if ((meshhdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) { /* This is required to keep the mppath alive */
mppath = mpp_path_lookup(sdata, meshhdr->eaddr1); if (!mppath) return;
build.mppath = mppath; if (!ether_addr_equal(meshhdr->eaddr2, sdata->vif.addr))
build.key.type = MESH_FAST_TX_TYPE_PROXIED;
} elseif (ieee80211_has_a4(hdr->frame_control)) {
mppath = mpath;
} else { return;
}
if (!ether_addr_equal(hdr->addr4, sdata->vif.addr))
build.key.type = MESH_FAST_TX_TYPE_FORWARDED;
/* rate limit, in case fast xmit can't be enabled */ if (mppath->fast_tx_check == jiffies) return;
mppath->fast_tx_check = jiffies;
/* * Same use of the sta lock as in ieee80211_check_fast_xmit, in order * to protect against concurrent sta key updates.
*/
spin_lock_bh(&sta->lock);
key = rcu_access_pointer(sta->ptk[sta->ptk_idx]); if (!key)
key = rcu_access_pointer(sdata->default_unicast_key);
build.fast_tx.key = key;
/* * replace any previous entry in the hash table, in case we're * replacing it with a different type (e.g. mpath -> mpp)
*/ if (unlikely(prev)) {
rhashtable_replace_fast(&cache->rht, &prev->rhash,
&entry->rhash, fast_tx_rht_params);
hlist_del_rcu(&prev->walk_list);
kfree_rcu(prev, fast_tx.rcu_head);
}
ether_addr_copy(key.addr, addr);
spin_lock_bh(&cache->walk_lock); for (i = 0; i < NUM_MESH_FAST_TX_TYPE; i++) {
key.type = i;
entry = rhashtable_lookup_fast(&cache->rht, &key, fast_tx_rht_params); if (entry)
mesh_fast_tx_entry_free(cache, entry);
}
spin_unlock_bh(&cache->walk_lock);
}
/** * mesh_path_add - allocate and add a new path to the mesh path table * @sdata: local subif * @dst: destination address of the path (ETH_ALEN length) * * Returns: 0 on success * * State: the initial state of the new path is set to 0
*/ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
{ struct mesh_table *tbl; struct mesh_path *mpath, *new_mpath;
if (ether_addr_equal(dst, sdata->vif.addr)) /* never add ourselves as neighbours */ return ERR_PTR(-EOPNOTSUPP);
if (is_multicast_ether_addr(dst)) return ERR_PTR(-EOPNOTSUPP);
if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0) return ERR_PTR(-ENOSPC);
new_mpath = mesh_path_new(sdata, dst, GFP_ATOMIC); if (!new_mpath) return ERR_PTR(-ENOMEM);
/** * mesh_plink_broken - deactivates paths and sends perr when a link breaks * * @sta: broken peer link * * This function must be called from the rate control algorithm if enough * delivery errors suggest that a peer link is no longer usable.
*/ void mesh_plink_broken(struct sta_info *sta)
{ struct ieee80211_sub_if_data *sdata = sta->sdata; struct mesh_table *tbl = &sdata->u.mesh.mesh_paths; staticconst u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; struct mesh_path *mpath;
/** * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches * * @sta: mesh peer to match * * RCU notes: this function is called when a mesh plink transitions from * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that * allows path creation. This will happen before the sta can be freed (because * sta_info_destroy() calls this) so any reader in a rcu read block will be * protected against the plink disappearing.
*/ void mesh_path_flush_by_nexthop(struct sta_info *sta)
{ struct ieee80211_sub_if_data *sdata = sta->sdata; struct mesh_table *tbl = &sdata->u.mesh.mesh_paths; struct mesh_path *mpath; struct hlist_node *n;
spin_lock_bh(&tbl->walk_lock);
hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) { if (rcu_access_pointer(mpath->next_hop) == sta)
__mesh_path_del(tbl, mpath);
}
spin_unlock_bh(&tbl->walk_lock);
}
/** * mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface * * @sdata: interface data to match * * This function deletes both mesh paths as well as mesh portal paths.
*/ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
{
table_flush_by_iface(&sdata->u.mesh.mesh_paths);
table_flush_by_iface(&sdata->u.mesh.mpp_paths);
}
/** * table_path_del - delete a path from the mesh or mpp table * * @tbl: mesh or mpp path table * @sdata: local subif * @addr: dst address (ETH_ALEN length) * * Returns: 0 if successful
*/ staticint table_path_del(struct mesh_table *tbl, struct ieee80211_sub_if_data *sdata, const u8 *addr)
{ struct mesh_path *mpath;
/** * mesh_path_tx_pending - sends pending frames in a mesh path queue * * @mpath: mesh path to activate * * Locking: the state_lock of the mpath structure must NOT be held when calling * this function.
*/ void mesh_path_tx_pending(struct mesh_path *mpath)
{ if (mpath->flags & MESH_PATH_ACTIVE)
ieee80211_add_pending_skbs(mpath->sdata->local,
&mpath->frame_queue);
}
/** * mesh_path_send_to_gates - sends pending frames to all known mesh gates * * @mpath: mesh path whose queue will be emptied * * If there is only one gate, the frames are transferred from the failed mpath * queue to that gate's queue. If there are more than one gates, the frames * are copied from each gate to the next. After frames are copied, the * mpath queues are emptied onto the transmission queue. * * Returns: 0 on success, -EHOSTUNREACH
*/ int mesh_path_send_to_gates(struct mesh_path *mpath)
{ struct ieee80211_sub_if_data *sdata = mpath->sdata; struct mesh_table *tbl; struct mesh_path *from_mpath = mpath; struct mesh_path *gate; bool copy = false;
/** * mesh_path_discard_frame - discard a frame whose path could not be resolved * * @sdata: network subif the frame was to be sent through * @skb: frame to discard * * Locking: the function must me called within a rcu_read_lock region
*/ void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
ieee80211_free_txskb(&sdata->local->hw, skb);
sdata->u.mesh.mshstats.dropped_frames_no_route++;
}
/** * mesh_path_flush_pending - free the pending queue of a mesh path * * @mpath: mesh path whose queue has to be freed * * Locking: the function must me called within a rcu_read_lock region
*/ void mesh_path_flush_pending(struct mesh_path *mpath)
{ struct ieee80211_sub_if_data *sdata = mpath->sdata; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_preq_queue *preq, *tmp; struct sk_buff *skb;
while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
mesh_path_discard_frame(mpath->sdata, skb);
/** * mesh_path_fix_nexthop - force a specific next hop for a mesh path * * @mpath: the mesh path to modify * @next_hop: the next hop to force * * Locking: this function must be called holding mpath->state_lock
*/ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
{
spin_lock_bh(&mpath->state_lock);
mesh_path_assign_nexthop(mpath, next_hop);
mpath->sn = 0xffff;
mpath->metric = 0;
mpath->hop_count = 0;
mpath->exp_time = 0;
mpath->flags = MESH_PATH_FIXED | MESH_PATH_SN_VALID;
mesh_path_activate(mpath);
mesh_fast_tx_flush_mpath(mpath);
spin_unlock_bh(&mpath->state_lock);
ewma_mesh_fail_avg_init(&next_hop->mesh->fail_avg); /* init it at a low value - 0 start is tricky */
ewma_mesh_fail_avg_add(&next_hop->mesh->fail_avg, 1);
mesh_path_tx_pending(mpath);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.