orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if); if (!orig_ifinfo) return;
spin_lock_bh(&orig_node->neigh_list_lock); /* curr_router used earlier may not be the current orig_ifinfo->router *anymorebecauseitwasdereferencedoutsideoftheneigh_list_lock *protectedregion.Afterthenewbestneighborhasreplacethecurrent *bestneighborthereferencecounterneedstodecrease.Consequently, *thecodeneedstoensurethecurr_routervariablecontainsapointer *tothereplacedbestneighbor.
*/
/* increase refcount of new best neighbor */ if (neigh_node)
kref_get(&neigh_node->refcount);
/* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) goto free_skb;
ethhdr = eth_hdr(skb);
/* packet with unicast indication but non-unicast recipient */ if (!is_valid_ether_addr(ethhdr->h_dest)) goto free_skb;
/* packet with broadcast/multicast sender address */ if (is_multicast_ether_addr(ethhdr->h_source)) goto free_skb;
/* not for me */ if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest)) goto free_skb;
icmph = (struct batadv_icmp_header *)skb->data;
/* add record route information if not full */ if ((icmph->msg_type == BATADV_ECHO_REPLY ||
icmph->msg_type == BATADV_ECHO_REQUEST) &&
skb->len >= sizeof(struct batadv_icmp_packet_rr)) { if (skb_linearize(skb) < 0) goto free_skb;
/* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, ETH_HLEN) < 0) goto free_skb;
/* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop) *andifactivated.
*/ if (!(recv_if == BATADV_IF_DEFAULT && atomic_read(&bat_priv->bonding))) return router;
/* bonding: loop through the list of possible routers found *forthevariousoutgoinginterfacesandfindacandidateafter *thelastchosenbondingcandidate(next_candidate).Ifnosuch *routerisfound,usethefirstcandidatefound(thepreviously *chosenbondingcandidatemighthavebeenthelastoneinthelist). *Ifthiscan'tbefoundeither,returnthepreviouslychosen *router-obviouslytherearenoothercandidates.
*/
rcu_read_lock();
last_candidate = batadv_last_bonding_get(orig_node); if (last_candidate)
last_cand_router = rcu_dereference(last_candidate->router);
hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) { /* acquire some structures and references ... */ if (!kref_get_unless_zero(&cand->refcount)) continue;
cand_router = rcu_dereference(cand->router); if (!cand_router) goto next;
if (!kref_get_unless_zero(&cand_router->refcount)) {
cand_router = NULL; goto next;
}
/* alternative candidate should be good enough to be *considered
*/ if (!bao->neigh.is_similar_or_better(cand_router,
cand->if_outgoing, router,
recv_if)) goto next;
/* don't use the same router twice */ if (last_cand_router == cand_router) goto next;
/* mark the first possible candidate */ if (!first_candidate) {
kref_get(&cand_router->refcount);
kref_get(&cand->refcount);
first_candidate = cand;
first_candidate_router = cand_router;
}
/* check if the loop has already passed the previously selected *candidate...thisfunctionshouldselectthenextcandidate *AFTERthepreviouslyusedbondingcandidate.
*/ if (!last_candidate || last_candidate_found) {
next_candidate = cand;
next_candidate_router = cand_router; break;
}
/* After finding candidates, handle the three cases: *1)thereisanextcandidate,usethat *2)thereisnonextcandidate,usethefirstofthelist *3)thereisnocandidateatall,returnthedefaultrouter
*/ if (next_candidate) {
batadv_neigh_node_put(router);
switch (unicast_packet->packet_type) { case BATADV_UNICAST_4ADDR:
hdr_len = sizeof(struct batadv_unicast_4addr_packet); break; case BATADV_UNICAST:
hdr_len = sizeof(struct batadv_unicast_packet); break; default: /* other packet types not supported - yet */
hdr_len = -1; break;
}
if (hdr_len > 0)
batadv_skb_set_priority(skb, hdr_len);
len = skb->len;
res = batadv_send_skb_to_orig(skb, orig_node, recv_if);
/* translate transmit result into receive result */ if (res == NET_XMIT_SUCCESS) {
ret = NET_RX_SUCCESS; /* skb was transmitted and consumed */
batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD);
batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES,
len + ETH_HLEN);
}
/* do not reroute multicast frames in a unicast header */ if (is_multicast_ether_addr(ethhdr->h_dest)) returntrue;
/* check if the destination client was served by this node and it is now *roaming.Inthiscase,itmeansthatthenodehasgotaROAM_ADV *messageandthatitknowsthenewdestinationinthemeshtore-route *thepacketto
*/ if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet,
ethhdr->h_dest, vid))
batadv_dbg_ratelimited(BATADV_DBG_TT,
bat_priv, "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n",
unicast_packet->dest,
ethhdr->h_dest); /* at this point the mesh destination should have been *substitutedwiththeoriginatoraddressfoundintheglobal *table.Ifnot,letthepacketgountouchedanywaybecause *thereisnothingthenodecando
*/ returntrue;
}
/* retrieve the TTVN known by this node for the packet destination. This *valueisusedlatertocheckifthenodewhichsent(orre-routed *lasttime)thepackethadanupdatedinformationornot
*/
curr_ttvn = (u8)atomic_read(&bat_priv->tt.vn); if (!batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
orig_node = batadv_orig_hash_find(bat_priv,
unicast_packet->dest); /* if it is not possible to find the orig_node representing the *destination,thepacketcanimmediatelybedroppedasitwill *notbepossibletodeliverit
*/ if (!orig_node) returnfalse;
/* check if the TTVN contained in the packet is fresher than what the *nodeknows
*/
is_old_ttvn = batadv_seq_before(unicast_packet->ttvn, curr_ttvn); if (!is_old_ttvn) returntrue;
old_ttvn = unicast_packet->ttvn; /* the packet was forged based on outdated network information. Its *destinationcanpossiblybeupdatedandforwardedtowardsthenew *targethost
*/ if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet,
ethhdr->h_dest, vid)) {
batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n",
unicast_packet->dest, ethhdr->h_dest,
old_ttvn, curr_ttvn); returntrue;
}
/* the packet has not been re-routed: either the destination is *currentlyservedbythisnodeorthereisnodestinationatalland *itispossibletodropthepacket
*/ if (!batadv_is_my_client(bat_priv, ethhdr->h_dest, vid)) returnfalse;
/* update the header in order to let the packet be delivered to this *node'smeshinterface
*/
primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) returnfalse;
/* we don't know about this type, drop it. */
unicast_packet = (struct batadv_unicast_packet *)skb->data; if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) goto free_skb;
unicast_packet = (struct batadv_unicast_packet *)skb->data;
is4addr = unicast_packet->packet_type == BATADV_UNICAST_4ADDR; /* the caller function should have already pulled 2 bytes */ if (is4addr)
hdr_size = sizeof(*unicast_4addr_packet);
/* function returns -EREMOTE for promiscuous packets */
check = batadv_check_unicast_packet(bat_priv, skb, hdr_size);
/* Even though the packet is not for us, we might save it to use for *decodingalaterreceivedcodedpacket
*/ if (check == -EREMOTE)
batadv_nc_skb_store_sniffed_unicast(bat_priv, skb);
if (check < 0) goto free_skb; if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) goto free_skb;
/* packet for me */ if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) { /* If this is a unicast packet from another backgone gw, *dropit.
*/
orig_addr_gw = eth_hdr(skb)->h_source;
orig_node_gw = batadv_orig_hash_find(bat_priv, orig_addr_gw); if (orig_node_gw) {
is_gw = batadv_bla_is_backbone_gw(skb, orig_node_gw,
hdr_size);
batadv_orig_node_put(orig_node_gw); if (is_gw) {
batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Dropped unicast pkt received from another backbone gw %pM.\n",
__func__, orig_addr_gw); goto free_skb;
}
}
/* Only payload data should be considered for speedy *join.Forexample,DATalsousesunicast4addr *types,butthosepacketsshouldnotbeconsidered *forspeedyjoin,sincetheclientsdonotactually *resideatthesendingoriginator.
*/ if (subtype == BATADV_P_DATA) {
orig_addr = unicast_4addr_packet->src;
orig_node = batadv_orig_hash_find(bat_priv,
orig_addr);
}
}
if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb,
hdr_size)) goto rx_success; if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb,
hdr_size)) goto rx_success;
/* Route the fragment if it is not for us and too big to be merged. */ if (!batadv_is_my_mac(bat_priv, frag_packet->dest) &&
batadv_frag_skb_fwd(skb, recv_if, orig_node_src)) { /* skb was consumed */
skb = NULL;
ret = NET_RX_SUCCESS; goto put_orig_node;
}
/* Add fragment to buffer and merge if possible. */ if (!batadv_frag_skb_buffer(&skb, orig_node_src)) goto put_orig_node;
/* Deliver merged packet to the appropriate handler, if it was *merged
*/ if (skb) {
batadv_batman_skb_recv(skb, recv_if->net_dev,
&recv_if->batman_adv_ptype, NULL); /* skb was consumed */
skb = NULL;
}
seqno = ntohl(bcast_packet->seqno); /* check whether the packet is a duplicate */ if (batadv_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno,
seqno)) goto spin_unlock;
seq_diff = seqno - orig_node->last_bcast_seqno;
/* check whether the packet is old and the host just restarted. */ if (batadv_window_protected(bat_priv, seq_diff,
BATADV_BCAST_MAX_AGE,
&orig_node->bcast_seqno_reset, NULL)) goto spin_unlock;
/* mark broadcast in flood history, update window position *ifrequired.
*/ if (batadv_bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
orig_node->last_bcast_seqno = seqno;
spin_unlock_bh(&orig_node->bcast_seqno_lock);
/* check whether this has been sent by another originator before */ if (batadv_bla_check_bcast_duplist(bat_priv, skb)) goto free_skb;
/* rebroadcast packet */
ret = batadv_forw_bcast_packet(bat_priv, skb, 0, false); if (ret == NETDEV_TX_BUSY) goto free_skb;
/* don't hand the broadcast up if it is from an originator *fromthesamebackbone.
*/ if (batadv_bla_is_backbone_gw(skb, orig_node, hdr_size)) goto free_skb;
if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size)) goto rx_success; if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size)) goto rx_success;
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.