/* now we pretend that the client would have sent this ... */ switch (claimtype) { case BATADV_CLAIM_TYPE_CLAIM: /* normal claim frame *setEthernetSRCtotheclientsmac
*/
ether_addr_copy(ethhdr->h_source, mac);
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): CLAIM %pM on vid %d\n", __func__, mac,
batadv_print_vid(vid)); break; case BATADV_CLAIM_TYPE_UNCLAIM: /* unclaim frame *setHWSRCtotheclientsmac
*/
ether_addr_copy(hw_src, mac);
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): UNCLAIM %pM on vid %d\n", __func__, mac,
batadv_print_vid(vid)); break; case BATADV_CLAIM_TYPE_ANNOUNCE: /* announcement frame *setHWSRCtothespecialmaccontainingthecrc
*/
ether_addr_copy(hw_src, mac);
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): ANNOUNCE of %pM on vid %d\n", __func__,
ethhdr->h_source, batadv_print_vid(vid)); break; case BATADV_CLAIM_TYPE_REQUEST: /* request frame *setHWSRCandheaderdestinationtothereceivingbackbone *gwsmac
*/
ether_addr_copy(hw_src, mac);
ether_addr_copy(ethhdr->h_dest, mac);
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): REQUEST of %pM to %pM on vid %d\n", __func__,
ethhdr->h_source, ethhdr->h_dest,
batadv_print_vid(vid)); break; case BATADV_CLAIM_TYPE_LOOPDETECT:
ether_addr_copy(ethhdr->h_source, mac);
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): LOOPDETECT of %pM to %pM on vid %d\n",
__func__, ethhdr->h_source, ethhdr->h_dest,
batadv_print_vid(vid));
break;
}
if (vid & BATADV_VLAN_HAS_TAG) {
skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),
vid & VLAN_VID_MASK); if (!skb) goto out;
}
batadv_info(bat_priv->mesh_iface, "Possible loop on VLAN %d detected which can't be handled by BLA - please check your network setup!\n",
batadv_print_vid(backbone_gw->vid));
snprintf(vid_str, sizeof(vid_str), "%d",
batadv_print_vid(backbone_gw->vid));
vid_str[sizeof(vid_str) - 1] = 0;
if (unlikely(hash_added != 0)) { /* hash failed, free the structure */
kfree(entry); return NULL;
}
/* this is a gateway now, remove any TT entry on this VLAN */
orig_node = batadv_orig_hash_find(bat_priv, orig); if (orig_node) {
batadv_tt_global_del_orig(bat_priv, orig_node, vid, "became a backbone gateway");
batadv_orig_node_put(orig_node);
}
if (own_backbone) {
batadv_bla_send_announce(bat_priv, entry);
/* this will be decreased in the worker thread */
atomic_inc(&entry->request_sent);
atomic_set(&entry->wait_periods, BATADV_BLA_WAIT_PERIODS);
atomic_inc(&bat_priv->bla.num_requests);
}
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): received a claim request, send all of our own claims again\n",
__func__);
backbone_gw = batadv_backbone_hash_find(bat_priv,
primary_if->net_dev->dev_addr,
vid); if (!backbone_gw) return;
hash = bat_priv->bla.claim_hash; for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(claim, head, hash_entry) { /* only own claims are interesting */ if (claim->backbone_gw != backbone_gw) continue;
/* no local broadcasts should be sent or received, for now. */ if (!atomic_read(&backbone_gw->request_sent)) {
atomic_inc(&backbone_gw->bat_priv->bla.num_requests);
atomic_set(&backbone_gw->request_sent, 1);
}
}
if (unlikely(hash_added != 0)) { /* only local changes happened. */
kfree(claim); return;
}
} else {
claim->lasttime = jiffies; if (claim->backbone_gw == backbone_gw) /* no need to register a new backbone */ goto claim_free_ref;
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): changing ownership for %pM, vid %d to gw %pM\n",
__func__, mac, batadv_print_vid(vid),
backbone_gw->orig);
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): %pM, vid %d\n", __func__,
mac, batadv_print_vid(vid));
claim_removed_node = batadv_hash_remove(bat_priv->bla.claim_hash,
batadv_compare_claim,
batadv_choose_claim, claim); if (!claim_removed_node) goto free_claim;
/* reference from the hash is gone */
claim_removed_entry = hlist_entry(claim_removed_node, struct batadv_bla_claim, hash_entry);
batadv_claim_put(claim_removed_entry);
free_claim: /* don't need the reference from hash_find() anymore */
batadv_claim_put(claim);
}
if (backbone_crc != crc) {
batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv, "%s(): CRC FAILED for %pM/%d (my = %#.4x, sent = %#.4x)\n",
__func__, backbone_gw->orig,
batadv_print_vid(backbone_gw->vid),
backbone_crc, crc);
batadv_bla_send_request(backbone_gw);
} else { /* if we have sent a request and the crc was OK, *wecanallowtrafficagain.
*/ if (atomic_read(&backbone_gw->request_sent)) {
atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
atomic_set(&backbone_gw->request_sent, 0);
}
}
/* sanity check, this should not happen on a normal switch, *weignoreitinthiscase.
*/ if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr)) returntrue;
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): REQUEST vid %d (sent by %pM)...\n",
__func__, batadv_print_vid(vid), ethhdr->h_source);
/* unclaim in any case if it is our own */ if (primary_if && batadv_compare_eth(backbone_addr,
primary_if->net_dev->dev_addr))
batadv_bla_send_claim(bat_priv, claim_addr, vid,
BATADV_CLAIM_TYPE_UNCLAIM);
/* this must be an UNCLAIM frame */
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,
claim_addr, batadv_print_vid(vid), backbone_gw->orig);
/* this must be a CLAIM frame */
batadv_bla_add_claim(bat_priv, claim_addr, vid, backbone_gw); if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
batadv_bla_send_claim(bat_priv, claim_addr, vid,
BATADV_CLAIM_TYPE_CLAIM);
/* TODO: we could call something like tt_local_del() here. */
/* if announcement packet, use the source, *otherwiseassumeitisinthehw_src
*/ switch (bla_dst->type) { case BATADV_CLAIM_TYPE_CLAIM:
backbone_addr = hw_src; break; case BATADV_CLAIM_TYPE_REQUEST: case BATADV_CLAIM_TYPE_ANNOUNCE: case BATADV_CLAIM_TYPE_UNCLAIM:
backbone_addr = ethhdr->h_source; break; default: return0;
}
/* don't accept claim frames from ourselves */ if (batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr)) return0;
/* if its already the same group, it is fine. */ if (bla_dst->group == bla_dst_own->group) return2;
/* lets see if this originator is in our mesh */
orig_node = batadv_orig_hash_find(bat_priv, backbone_addr);
/* don't accept claims from gateways which are not in *thesamemeshorgroup.
*/ if (!orig_node) return1;
/* if our mesh friends mac is bigger, use it for ourselves. */ if (ntohs(bla_dst->group) > ntohs(bla_dst_own->group)) {
batadv_dbg(BATADV_DBG_BLA, bat_priv, "taking other backbones claim group: %#.4x\n",
ntohs(bla_dst->group));
bla_dst_own->group = bla_dst->group;
}
/* check if it is a claim frame in general */ if (memcmp(bla_dst->magic, bla_dst_own->magic, sizeof(bla_dst->magic)) != 0) returnfalse;
/* check if there is a claim frame encapsulated deeper in (QinQ) and *dropthat,asthisisnotsupportedbyBLAbutshouldalsonotbe *sentviathemesh.
*/ if (vlan_depth > 1) returntrue;
/* Let the loopdetect frames on the mesh in any case. */ if (bla_dst->type == BATADV_CLAIM_TYPE_LOOPDETECT) returnfalse;
/* check if it is a claim frame. */
ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,
ethhdr); if (ret == 1)
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
__func__, ethhdr->h_source, batadv_print_vid(vid),
hw_src, hw_dst);
if (ret < 2) return !!ret;
/* become a backbone gw ourselves on this vlan if not happened yet */
batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
/* check for the different types of claim frames ... */ switch (bla_dst->type) { case BATADV_CLAIM_TYPE_CLAIM: if (batadv_handle_claim(bat_priv, primary_if, hw_src,
ethhdr->h_source, vid)) returntrue; break; case BATADV_CLAIM_TYPE_UNCLAIM: if (batadv_handle_unclaim(bat_priv, primary_if,
ethhdr->h_source, hw_src, vid)) returntrue; break;
case BATADV_CLAIM_TYPE_ANNOUNCE: if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source,
vid)) returntrue; break; case BATADV_CLAIM_TYPE_REQUEST: if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr,
vid)) returntrue; break;
}
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
__func__, ethhdr->h_source, batadv_print_vid(vid), hw_src,
hw_dst); returntrue;
}
/* reset bridge loop avoidance group id */
group = htons(crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN));
bat_priv->bla.claim_dest.group = group;
/* purge everything when bridge loop avoidance is turned off */ if (!atomic_read(&bat_priv->bridge_loop_avoidance))
oldif = NULL;
if (!oldif) {
batadv_bla_purge_claims(bat_priv, NULL, 1);
batadv_bla_purge_backbone_gw(bat_priv, 1); return;
}
hash = bat_priv->bla.backbone_hash; if (!hash) return;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { /* own orig still holds the old value. */ if (!batadv_compare_eth(backbone_gw->orig,
oldif->net_dev->dev_addr)) continue;
ether_addr_copy(backbone_gw->orig,
primary_if->net_dev->dev_addr); /* send an announce frame so others will ask for our *claimsandupdatetheirtables.
*/
batadv_bla_send_announce(bat_priv, backbone_gw);
}
rcu_read_unlock();
}
}
primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) return;
/* this function already purges everything when bla is disabled, *sojustcallthatone.
*/
batadv_bla_update_orig_address(bat_priv, primary_if, primary_if);
batadv_hardif_put(primary_if);
}
if (!atomic_read(&bat_priv->bridge_loop_avoidance)) goto out;
if (atomic_dec_and_test(&bat_priv->bla.loopdetect_next)) { /* set a new random mac address for the next bridge loop *detectionframes.Setthelocallyadministeredbittoavoid *collisionswithusersmacaddresses.
*/
eth_random_addr(bat_priv->bla.loopdetect_addr);
bat_priv->bla.loopdetect_addr[0] = 0xba;
bat_priv->bla.loopdetect_addr[1] = 0xbe;
bat_priv->bla.loopdetect_lasttime = jiffies;
atomic_set(&bat_priv->bla.loopdetect_next,
BATADV_BLA_LOOPDETECT_PERIODS);
/* mark for sending loop detect on all VLANs */
send_loopdetect = true;
}
hash = bat_priv->bla.backbone_hash; if (!hash) goto out;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { if (!batadv_compare_eth(backbone_gw->orig,
primary_if->net_dev->dev_addr)) continue;
backbone_gw->lasttime = jiffies;
batadv_bla_send_announce(bat_priv, backbone_gw); if (send_loopdetect)
batadv_bla_send_loopdetect(bat_priv,
backbone_gw);
/* request_sent is only set after creation to avoid *problemswhenwearenotyetknownasbackbonegw *inthebackbone. * *Wecanresetthisnowafterwewaitedsomeperiods *togivebridgeforwarddelaysandblagroupforming *somegracetime.
*/
if (atomic_read(&backbone_gw->request_sent) == 0) continue;
if (!atomic_dec_and_test(&backbone_gw->wait_periods)) continue;
/* The hash for claim and backbone hash receive the same key because they *aregettinginitializedbyhash_newwiththesamekey.Reinitializing *themwithtodifferentkeystoallownestedlockingwithoutgenerating *lockdepwarnings
*/ staticstruct lock_class_key batadv_claim_hash_lock_class_key; staticstruct lock_class_key batadv_backbone_hash_lock_class_key;
/* setting claim destination address */
memcpy(&bat_priv->bla.claim_dest.magic, claim_dest, 3);
bat_priv->bla.claim_dest.type = 0;
primary_if = batadv_primary_if_get_selected(bat_priv); if (primary_if) {
crc = crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN);
bat_priv->bla.claim_dest.group = htons(crc);
batadv_hardif_put(primary_if);
} else {
bat_priv->bla.claim_dest.group = 0; /* will be set later */
}
/* initialize the duplicate list */
entrytime = jiffies - msecs_to_jiffies(BATADV_DUPLIST_TIMEOUT); for (i = 0; i < BATADV_DUPLIST_SIZE; i++)
bat_priv->bla.bcast_duplist[i].entrytime = entrytime;
bat_priv->bla.bcast_duplist_curr = 0;
/* calculate the crc ... */
crc = batadv_skb_crc32(skb, payload_ptr);
spin_lock_bh(&bat_priv->bla.bcast_duplist_lock);
for (i = 0; i < BATADV_DUPLIST_SIZE; i++) {
curr = (bat_priv->bla.bcast_duplist_curr + i);
curr %= BATADV_DUPLIST_SIZE;
entry = &bat_priv->bla.bcast_duplist[curr];
/* we can stop searching if the entry is too old ; *laterentrieswillbeevenolder
*/ if (batadv_has_timed_out(entry->entrytime,
BATADV_DUPLIST_TIMEOUT)) break;
if (entry->crc != crc) continue;
/* are the originators both known and not anonymous? */ if (orig && !is_zero_ether_addr(orig) &&
!is_zero_ether_addr(entry->orig)) { /* If known, check if the new frame came from *thesameoriginator: *Wearesafetotakeidenticalframesfromthe *sameorig,ifknown,asmultiplicationsin *themesharedetectedviathe(orig,seqno)pair. *Sowecanbeabitmoreliberalhereandallow *identicalframesfromthesameorigwhichthesource *hostmighthavesentmultipletimesonpurpose.
*/ if (batadv_compare_eth(entry->orig, orig)) continue;
}
/* this entry seems to match: same crc, not too old, *andfromanothergw.thereforereturntruetoforbidit.
*/
ret = true; goto out;
} /* not found, add a new entry (overwrite the oldest entry) *andallowit,itsthefirstoccurrence.
*/
curr = (bat_priv->bla.bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1);
curr %= BATADV_DUPLIST_SIZE;
entry = &bat_priv->bla.bcast_duplist[curr];
entry->crc = crc;
entry->entrytime = jiffies;
/* known originator */ if (orig)
ether_addr_copy(entry->orig, orig); /* anonymous originator */ else
eth_zero_addr(entry->orig);
if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) returnfalse;
/* first, find out the vid. */ if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) returnfalse;
vid = batadv_get_vid(skb, hdr_size);
/* see if this originator is a backbone gw for this VLAN */
backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,
orig_node->orig, vid); if (!backbone_gw) returnfalse;
/* Only check for the MAC address and skip more checks here for *performancereasons-thisfunctionisonthehotpath,afterall.
*/ if (!batadv_compare_eth(ethhdr->h_source,
bat_priv->bla.loopdetect_addr)) returnfalse;
/* If the packet came too late, don't forward it on the mesh *butdon'tconsiderthatasloop.Itmightbeacoincidence.
*/ if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime,
BATADV_BLA_LOOPDETECT_TIMEOUT)) returntrue;
backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
primary_if->net_dev->dev_addr,
vid, true); if (unlikely(!backbone_gw)) returntrue;
ret = queue_work(batadv_event_workqueue, &backbone_gw->report_work);
/* backbone_gw is unreferenced in the report work function *ifqueue_work()callwassuccessful
*/ if (!ret)
batadv_backbone_gw_put(backbone_gw);
/* if it is our own claim ... */
backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
own_claim = batadv_compare_eth(backbone_gw->orig,
primary_if->net_dev->dev_addr);
batadv_backbone_gw_put(backbone_gw);
if (own_claim) { /* ... allow it in any case */
claim->lasttime = jiffies; goto allow;
}
/* if it is a multicast ... */ if (is_multicast_ether_addr(ethhdr->h_dest) &&
(packet_type == BATADV_BCAST || packet_type == BATADV_UNICAST)) { /* ... drop it. the responsible gateway is in charge. * *Weneedtocheckpackettypebecausewiththegateway *feature,broadcasts(likeDHCPrequests)maybesent *usingaunicast4addresspackettype.Seecommentabove.
*/ goto handled;
} else { /* seems the client considers us as its best gateway. *sendaclaimandupdatetheclaimtable *immediately.
*/
batadv_handle_claim(bat_priv, primary_if,
primary_if->net_dev->dev_addr,
ethhdr->h_source, vid); goto allow;
}
allow:
batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
ret = false; goto out;
primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) goto out;
if (!atomic_read(&bat_priv->bridge_loop_avoidance)) goto allow;
if (batadv_bla_process_claim(bat_priv, primary_if, skb)) goto handled;
ethhdr = eth_hdr(skb);
if (unlikely(atomic_read(&bat_priv->bla.num_requests))) /* don't allow broadcasts while requests are in flight */ if (is_multicast_ether_addr(ethhdr->h_dest)) goto handled;
/* if no claim exists, allow it. */ if (!claim) goto allow;
/* check if we are responsible. */
backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
client_roamed = batadv_compare_eth(backbone_gw->orig,
primary_if->net_dev->dev_addr);
batadv_backbone_gw_put(backbone_gw);
if (client_roamed) { /* if yes, the client has roamed and we have *tounclaimit.
*/ if (batadv_has_timed_out(claim->lasttime, 100)) { /* only unclaim if the last claim entry is *olderthan100mstomakesurewereally *havearoamingclienthere.
*/
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Roaming client %pM detected. Unclaim it.\n",
__func__, ethhdr->h_source);
batadv_handle_unclaim(bat_priv, primary_if,
primary_if->net_dev->dev_addr,
ethhdr->h_source, vid); goto allow;
} else {
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Race for claim %pM detected. Drop packet.\n",
__func__, ethhdr->h_source); goto handled;
}
}
/* check if it is a multicast/broadcast frame */ if (is_multicast_ether_addr(ethhdr->h_dest)) { /* drop it. the responsible gateway has forwarded it into *thebackbonenetwork.
*/ goto handled;
} else { /* we must allow it. at least if we are *responsiblefortheDESTINATION.
*/ goto allow;
}
allow:
batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
ret = false; goto out;
handled:
ret = true;
out:
batadv_hardif_put(primary_if);
batadv_claim_put(claim); return ret;
}
/* If there is a claim and we are not owner of the claim, *returnfalse.
*/ if (claim) { if (!batadv_compare_eth(claim->backbone_gw->orig,
primary_if->net_dev->dev_addr))
ret = false;
batadv_claim_put(claim);
}
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.