/** *batadv_skb_head_push()-Increaseheadersizeandmove(push)headpointer *@skb:packetbufferwhichshouldbemodified *@len:numberofbytestoadd * *Return:0onsuccessornegativeerrornumberincaseoffailure
*/ int batadv_skb_head_push(struct sk_buff *skb, unsignedint len)
{ int result;
/* TODO: We must check if we can release all references to non-payload *datausing__skb_header_releaseinourskbstoallowskb_cow_header *toworkoptimally.Thismeansthatthoseskbsarenotallowedtoread *orwriteanydatawhichisbeforethecurrentpositionofskb->data *afterthatcallandthusallowotherskbswiththesamedatabuffer *towritefreelyinthatarea.
*/
result = skb_cow_head(skb, len); if (result < 0) return result;
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto dropped;
/* reset control block to avoid left overs from previous users */
memset(skb->cb, 0, sizeof(struct batadv_skb_cb));
netif_trans_update(mesh_iface);
vid = batadv_get_vid(skb, 0);
skb_reset_mac_header(skb);
ethhdr = eth_hdr(skb);
proto = ethhdr->h_proto;
switch (ntohs(proto)) { case ETH_P_8021Q: if (!pskb_may_pull(skb, sizeof(*vhdr))) goto dropped;
vhdr = vlan_eth_hdr(skb);
proto = vhdr->h_vlan_encapsulated_proto;
/* drop batman-in-batman packets to prevent loops */ if (proto != htons(ETH_P_BATMAN)) {
network_offset += VLAN_HLEN; break;
}
fallthrough; case ETH_P_BATMAN: goto dropped;
}
skb_set_network_header(skb, network_offset);
if (batadv_bla_tx(bat_priv, skb, vid)) goto dropped;
/* skb->data might have been reallocated by batadv_bla_tx() */
ethhdr = eth_hdr(skb);
/* Register the client MAC in the transtable */ if (!is_multicast_ether_addr(ethhdr->h_source) &&
!batadv_bla_is_loopdetect_mac(ethhdr->h_source)) {
client_added = batadv_tt_local_add(mesh_iface, ethhdr->h_source,
vid, skb->skb_iif,
skb->mark); if (!client_added) goto dropped;
}
/* Snoop address candidates from DHCPACKs for early DAT filling */
batadv_dat_snoop_outgoing_dhcp_ack(bat_priv, skb, proto, vid);
/* don't accept stp packets. STP does not help in meshes. *betterusethebridgeloopavoidance... * *ThesamegoesforECTPsentatleastbysomeCiscoSwitches, *itmightconfusethemeshwhenusedwithbridgeloopavoidance.
*/ if (batadv_compare_eth(ethhdr->h_dest, stp_addr)) goto dropped;
if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) goto dropped;
gw_mode = atomic_read(&bat_priv->gw.mode); if (is_multicast_ether_addr(ethhdr->h_dest)) { /* if gw mode is off, broadcast every packet */ if (gw_mode == BATADV_GW_MODE_OFF) {
do_bcast = true; goto send;
}
dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len,
chaddr); /* skb->data may have been modified by *batadv_gw_dhcp_recipient_get()
*/
ethhdr = eth_hdr(skb); /* if gw_mode is on, broadcast any non-DHCP message. *AlltheDHCPpacketsaregoingtobesentasunicast
*/ if (dhcp_rcp == BATADV_DHCP_NO) {
do_bcast = true; goto send;
}
if (dhcp_rcp == BATADV_DHCP_TO_CLIENT)
dst_hint = chaddr; elseif ((gw_mode == BATADV_GW_MODE_SERVER) &&
(dhcp_rcp == BATADV_DHCP_TO_SERVER)) /* gateways should not forward any DHCP message if *directedtoaDHCPserver
*/ goto dropped;
send: if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
forw_mode = batadv_mcast_forw_mode(bat_priv, skb, vid,
&mcast_is_routable); switch (forw_mode) { case BATADV_FORW_BCAST: break; case BATADV_FORW_UCASTS: case BATADV_FORW_MCAST:
do_bcast = false; break; case BATADV_FORW_NONE:
fallthrough; default: goto dropped;
}
}
}
batadv_skb_set_priority(skb, 0);
/* ethernet packet should be broadcasted */ if (do_bcast) {
primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) goto dropped;
/* in case of ARP request, we do not immediately broadcasti the *packet,insteadwefirstwaitforDATtotrytoretrievethe *correctARPentry
*/ if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
brd_delay = msecs_to_jiffies(ARP_REQ_DELAY);
if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0) goto dropped;
/* hw address of first interface is the orig mac because only *thismacisknownthroughoutthemesh
*/
ether_addr_copy(bcast_packet->orig,
primary_if->net_dev->dev_addr);
/* set broadcast sequence number */
seqno = atomic_inc_return(&bat_priv->bcast_seqno);
bcast_packet->seqno = htonl(seqno);
batadv_send_bcast_packet(bat_priv, skb, brd_delay, true); /* unicast packet */
} else { /* DHCP packets going to a server will use the GW feature */ if (dhcp_rcp == BATADV_DHCP_TO_SERVER) {
ret = batadv_gw_out_of_range(bat_priv, skb); if (ret) goto dropped;
ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
} elseif (forw_mode == BATADV_FORW_UCASTS) {
ret = batadv_mcast_forw_send(bat_priv, skb, vid,
mcast_is_routable);
} elseif (forw_mode == BATADV_FORW_MCAST) {
ret = batadv_mcast_forw_mcsend(bat_priv, skb);
} else { if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
skb)) goto dropped;
/* Let the bridge loop avoidance check the packet. If will *nothandleit,wecansafelypushitup.
*/ if (batadv_bla_rx(bat_priv, skb, vid, packet_type)) goto out;
if (orig_node)
batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
ethhdr->h_source, vid);
if (is_multicast_ether_addr(ethhdr->h_dest)) { /* set the mark on broadcast packets if AP isolation is ON and *thepacketiscomingfroman"isolated"client
*/ if (batadv_vlan_ap_isola_get(bat_priv, vid) &&
batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source,
vid)) { /* save bits in skb->mark not covered by the mask and *applythemarkontherest
*/
skb->mark &= ~bat_priv->isolation_mark_mask;
skb->mark |= bat_priv->isolation_mark;
}
} elseif (batadv_is_ap_isolated(bat_priv, ethhdr->h_source,
ethhdr->h_dest, vid)) { goto dropped;
}
/* add a new TT local entry. This one will be marked with the NOPURGE *flag
*/
batadv_tt_local_add(bat_priv->mesh_iface,
bat_priv->mesh_iface->dev_addr, vid,
BATADV_NULL_IFINDEX, BATADV_NO_MARK);
/* don't return reference to new meshif_vlan */
batadv_meshif_vlan_put(vlan);
return0;
}
/** *batadv_meshif_destroy_vlan()-removeanddestroyameshif_vlanobject *@bat_priv:thebatprivwithallthemeshinterfaceinformation *@vlan:theobjecttoremove
*/ staticvoid batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv, struct batadv_meshif_vlan *vlan)
{ /* explicitly remove the associated TT local entry because it is marked *withtheNOPURGEflag
*/
batadv_tt_local_remove(bat_priv, bat_priv->mesh_iface->dev_addr,
vlan->vid, "vlan interface destroyed", false);
/* only 802.1Q vlans are supported. *batman-advdoesnotknowhowtohandleothertypes
*/ if (proto != htons(ETH_P_8021Q)) return -EINVAL;
/* VID 0 is only used to indicate "priority tag" frames which only *containpriorityinformationandnoVID.Nomanagementstructures *shouldbecreatedforthisVIDanditshouldbehandledlikean *untaggedframe.
*/ if (vid == 0) return0;
vid |= BATADV_VLAN_HAS_TAG;
/* if a new vlan is getting created and it already exists, it means that *itwasnotdeletedyet.batadv_meshif_vlan_get()increasesthe *refcountinordertorevivetheobject. * *ifitdoesnotexistthencreateit.
*/
vlan = batadv_meshif_vlan_get(bat_priv, vid); if (!vlan) return batadv_meshif_create_vlan(bat_priv, vid);
/* add a new TT local entry. This one will be marked with the NOPURGE *flag.Thismustbeaddedagain,evenifthevlanobjectalready *exists,becausetheentrywasdeletedbykill_vid()
*/
batadv_tt_local_add(bat_priv->mesh_iface,
bat_priv->mesh_iface->dev_addr, vid,
BATADV_NULL_IFINDEX, BATADV_NO_MARK);
/* only 802.1Q vlans are supported. batman-adv does not know how to *handleothertypes
*/ if (proto != htons(ETH_P_8021Q)) return -EINVAL;
/* "priority tag" frames are handled like "untagged" frames *andnomeshif_vlanneedstobedestroyed
*/ if (vid == 0) return0;
vlan = batadv_meshif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG); if (!vlan) return -ENOENT;
batadv_meshif_destroy_vlan(bat_priv, vlan);
/* finally free the vlan object */
batadv_meshif_vlan_put(vlan);
return0;
}
/* batman-adv network devices have devices nesting below it and are a special *"superclass"ofnormalnetworkdevices;splittheirlocksoffintoa *separateclasssincetheyalwaysnest.
*/ staticstruct lock_class_key batadv_netdev_xmit_lock_key; staticstruct lock_class_key batadv_netdev_addr_lock_key;
/* batadv_interface_stats() needs to be available as soon as *register_netdevice()hasbeencalled
*/
bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(u64)); if (!bat_priv->bat_counters) return -ENOMEM;
/* some scheduled RCU callbacks need the bat_priv struct to accomplish *theirtasks.Waitforthemalltobefinishedbeforefreeingthe *netdevanditsprivatedata(bat_priv)
*/
rcu_barrier();
}
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.