/** * batadv_mcast_forw_skb_push() - skb_push and memorize amount of pushed bytes * @skb: the skb to push onto * @size: the amount of bytes to push * @len: stores the total amount of bytes pushed * * Performs an skb_push() onto the given skb and adds the amount of pushed bytes * to the given len pointer. * * Return: the return value of the skb_push() call.
*/ staticvoid *batadv_mcast_forw_skb_push(struct sk_buff *skb, size_t size, unsignedshort *len)
{
*len += size; return skb_push(skb, size);
}
/** * batadv_mcast_forw_push_padding() - push 2 padding bytes to skb's front * @skb: the skb to push onto * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Pushes two padding bytes to the front of the given skb. * * Return: On success a pointer to the first byte of the two pushed padding * bytes within the skb. NULL otherwise.
*/ staticchar *
batadv_mcast_forw_push_padding(struct sk_buff *skb, unsignedshort *tvlv_len)
{ constint pad_len = 2; char *padding;
/** * batadv_mcast_forw_push_est_padding() - push padding bytes if necessary * @skb: the skb to potentially push the padding onto * @count: the (estimated) number of originators the multicast packet needs to * be sent to * @tvlv_len: stores the amount of currently pushed TVLV bytes * * If the number of destination entries is even then this adds two * padding bytes to the end of the tracker TVLV. * * Return: true on success or if no padding is needed, false otherwise.
*/ staticbool
batadv_mcast_forw_push_est_padding(struct sk_buff *skb, int count, unsignedshort *tvlv_len)
{ if (!(count % 2) && !batadv_mcast_forw_push_padding(skb, tvlv_len)) returnfalse;
returntrue;
}
/** * batadv_mcast_forw_orig_entry() - get orig_node from an hlist node * @node: the hlist node to get the orig_node from * @entry_offset: the offset of the hlist node within the orig_node struct * * Return: The orig_node containing the hlist node on success, NULL on error.
*/ staticstruct batadv_orig_node *
batadv_mcast_forw_orig_entry(struct hlist_node *node,
size_t entry_offset)
{ /* sanity check */ switch (entry_offset) { case offsetof(struct batadv_orig_node, mcast_want_all_ipv4_node): case offsetof(struct batadv_orig_node, mcast_want_all_ipv6_node): case offsetof(struct batadv_orig_node, mcast_want_all_rtr4_node): case offsetof(struct batadv_orig_node, mcast_want_all_rtr6_node): break; default:
WARN_ON(1); return NULL;
}
/** * batadv_mcast_forw_push_dest() - push an originator MAC address onto an skb * @bat_priv: the bat priv with all the mesh interface information * @skb: the skb to push the destination address onto * @vid: the vlan identifier * @orig_node: the originator node to get the MAC address from * @num_dests: a pointer to store the number of pushed addresses in * @tvlv_len: stores the amount of currently pushed TVLV bytes * * If the orig_node is a BLA backbone gateway, if there is not enough skb * headroom available or if num_dests is already at its maximum (65535) then * neither the skb nor num_dests is changed. Otherwise the originator's MAC * address is pushed onto the given skb and num_dests incremented by one. * * Return: true if the orig_node is a backbone gateway or if an orig address * was pushed successfully, false otherwise.
*/ staticbool batadv_mcast_forw_push_dest(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, struct batadv_orig_node *orig_node, unsignedshort *num_dests, unsignedshort *tvlv_len)
{
BUILD_BUG_ON(sizeof_field(struct batadv_tvlv_mcast_tracker, num_dests)
!= sizeof(__be16));
/* Avoid sending to other BLA gateways - they already got the frame from * the LAN side we share with them. * TODO: Refactor to take BLA into account earlier in mode check.
*/ if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) returntrue;
if (skb_headroom(skb) < ETH_ALEN || *num_dests == U16_MAX) returnfalse;
/** * batadv_mcast_forw_push_dests_list() - push originators from list onto an skb * @bat_priv: the bat priv with all the mesh interface information * @skb: the skb to push the destination addresses onto * @vid: the vlan identifier * @head: the list to gather originators from * @entry_offset: offset of an hlist node in an orig_node structure * @num_dests: a pointer to store the number of pushed addresses in * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Push the MAC addresses of all originators in the given list onto the given * skb. * * Return: true on success, false otherwise.
*/ staticint batadv_mcast_forw_push_dests_list(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, struct hlist_head *head,
size_t entry_offset, unsignedshort *num_dests, unsignedshort *tvlv_len)
{ struct hlist_node *node; struct batadv_orig_node *orig_node;
/** * batadv_mcast_forw_push_tt() - push originators with interest through TT * @bat_priv: the bat priv with all the mesh interface information * @skb: the skb to push the destination addresses onto * @vid: the vlan identifier * @num_dests: a pointer to store the number of pushed addresses in * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Push the MAC addresses of all originators which have indicated interest in * this multicast packet through the translation table onto the given skb. * * Return: true on success, false otherwise.
*/ staticbool
batadv_mcast_forw_push_tt(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, unsignedshort *num_dests, unsignedshort *tvlv_len)
{ struct batadv_tt_orig_list_entry *orig_entry;
tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global) goto out;
rcu_read_lock();
hlist_for_each_entry_rcu(orig_entry, &tt_global->orig_list, list) { if (!batadv_mcast_forw_push_dest(bat_priv, skb, vid,
orig_entry->orig_node,
num_dests, tvlv_len)) {
ret = false; break;
}
}
rcu_read_unlock();
batadv_tt_global_entry_put(tt_global);
out: return ret;
}
/** * batadv_mcast_forw_push_want_all() - push originators with want-all flag * @bat_priv: the bat priv with all the mesh interface information * @skb: the skb to push the destination addresses onto * @vid: the vlan identifier * @num_dests: a pointer to store the number of pushed addresses in * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Push the MAC addresses of all originators which have indicated interest in * this multicast packet through the want-all flag onto the given skb. * * Return: true on success, false otherwise.
*/ staticbool batadv_mcast_forw_push_want_all(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, unsignedshort *num_dests, unsignedshort *tvlv_len)
{ struct hlist_head *head = NULL;
size_t offset; int ret;
switch (eth_hdr(skb)->h_proto) { case htons(ETH_P_IP):
head = &bat_priv->mcast.want_all_ipv4_list;
offset = offsetof(struct batadv_orig_node,
mcast_want_all_ipv4_node); break; case htons(ETH_P_IPV6):
head = &bat_priv->mcast.want_all_ipv6_list;
offset = offsetof(struct batadv_orig_node,
mcast_want_all_ipv6_node); break; default: returnfalse;
}
ret = batadv_mcast_forw_push_dests_list(bat_priv, skb, vid, head,
offset, num_dests, tvlv_len); if (!ret) returnfalse;
returntrue;
}
/** * batadv_mcast_forw_push_want_rtr() - push originators with want-router flag * @bat_priv: the bat priv with all the mesh interface information * @skb: the skb to push the destination addresses onto * @vid: the vlan identifier * @num_dests: a pointer to store the number of pushed addresses in * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Push the MAC addresses of all originators which have indicated interest in * this multicast packet through the want-all-rtr flag onto the given skb. * * Return: true on success, false otherwise.
*/ staticbool batadv_mcast_forw_push_want_rtr(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, unsignedshort *num_dests, unsignedshort *tvlv_len)
{ struct hlist_head *head = NULL;
size_t offset; int ret;
switch (eth_hdr(skb)->h_proto) { case htons(ETH_P_IP):
head = &bat_priv->mcast.want_all_rtr4_list;
offset = offsetof(struct batadv_orig_node,
mcast_want_all_rtr4_node); break; case htons(ETH_P_IPV6):
head = &bat_priv->mcast.want_all_rtr6_list;
offset = offsetof(struct batadv_orig_node,
mcast_want_all_rtr6_node); break; default: returnfalse;
}
ret = batadv_mcast_forw_push_dests_list(bat_priv, skb, vid, head,
offset, num_dests, tvlv_len); if (!ret) returnfalse;
returntrue;
}
/** * batadv_mcast_forw_scrape() - remove bytes within skb data * @skb: the skb to remove bytes from * @offset: the offset from the skb data from which to scrape * @len: the amount of bytes to scrape starting from the offset * * Scrapes/removes len bytes from the given skb at the given offset from the * skb data. * * Caller needs to ensure that the region from the skb data's start up * to/including the to be removed bytes are linearized.
*/ staticvoid batadv_mcast_forw_scrape(struct sk_buff *skb, unsignedshort offset, unsignedshort len)
{ char *to, *from;
SKB_LINEAR_ASSERT(skb);
to = skb_pull(skb, len);
from = to - len;
memmove(to, from, offset);
}
/** * batadv_mcast_forw_push_scrape_padding() - remove TVLV padding * @skb: the skb to potentially adjust the TVLV's padding on * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Remove two padding bytes from the end of the multicast tracker TVLV, * from before the payload data. * * Caller needs to ensure that the TVLV bytes are linearized.
*/ staticvoid batadv_mcast_forw_push_scrape_padding(struct sk_buff *skb, unsignedshort *tvlv_len)
{ constint pad_len = 2;
/** * batadv_mcast_forw_push_insert_padding() - insert TVLV padding * @skb: the skb to potentially adjust the TVLV's padding on * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Inserts two padding bytes at the end of the multicast tracker TVLV, * before the payload data in the given skb. * * Return: true on success, false otherwise.
*/ staticbool batadv_mcast_forw_push_insert_padding(struct sk_buff *skb, unsignedshort *tvlv_len)
{ unsignedshort offset = *tvlv_len; char *to, *from = skb->data;
to = batadv_mcast_forw_push_padding(skb, tvlv_len); if (!to) returnfalse;
/** * batadv_mcast_forw_push_adjust_padding() - adjust padding if necessary * @skb: the skb to potentially adjust the TVLV's padding on * @count: the estimated number of originators the multicast packet needs to * be sent to * @num_dests_pushed: the number of originators that were actually added to the * multicast packet's tracker TVLV * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Adjusts the padding in the multicast packet's tracker TVLV depending on the * initially estimated amount of destinations versus the amount of destinations * that were actually added to the tracker TVLV. * * If the initial estimate was correct or at least the oddness was the same then * no padding adjustment is performed. * If the initially estimated number was even, so padding was initially added, * but it turned out to be odd then padding is removed. * If the initially estimated number was odd, so no padding was initially added, * but it turned out to be even then padding is added. * * Return: true if no padding adjustment is needed or the adjustment was * successful, false otherwise.
*/ staticbool
batadv_mcast_forw_push_adjust_padding(struct sk_buff *skb, int *count, unsignedshort num_dests_pushed, unsignedshort *tvlv_len)
{ int ret = true;
if (likely((num_dests_pushed % 2) == (*count % 2))) goto out;
/** * estimated even number of destinations, but turned out to be odd * -> remove padding
*/ if (!(*count % 2) && (num_dests_pushed % 2))
batadv_mcast_forw_push_scrape_padding(skb, tvlv_len); /** * estimated odd number of destinations, but turned out to be even * -> add padding
*/ elseif ((*count % 2) && (!(num_dests_pushed % 2)))
ret = batadv_mcast_forw_push_insert_padding(skb, tvlv_len);
out:
*count = num_dests_pushed; return ret;
}
/** * batadv_mcast_forw_push_dests() - push originator addresses onto an skb * @bat_priv: the bat priv with all the mesh interface information * @skb: the skb to push the destination addresses onto * @vid: the vlan identifier * @is_routable: indicates whether the destination is routable * @count: the number of originators the multicast packet needs to be sent to * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Push the MAC addresses of all originators which have indicated interest in * this multicast packet onto the given skb. * * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on * success 0.
*/ staticint
batadv_mcast_forw_push_dests(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, int is_routable, int *count, unsignedshort *tvlv_len)
{ unsignedshort num_dests = 0;
if (!batadv_mcast_forw_push_est_padding(skb, *count, tvlv_len)) goto err;
if (!batadv_mcast_forw_push_tt(bat_priv, skb, vid, &num_dests,
tvlv_len)) goto err;
if (!batadv_mcast_forw_push_want_all(bat_priv, skb, vid, &num_dests,
tvlv_len)) goto err;
if (is_routable &&
!batadv_mcast_forw_push_want_rtr(bat_priv, skb, vid, &num_dests,
tvlv_len)) goto err;
if (!batadv_mcast_forw_push_adjust_padding(skb, count, num_dests,
tvlv_len)) goto err;
return 0;
err: return -ENOMEM;
}
/** * batadv_mcast_forw_push_tracker() - push a multicast tracker TVLV header * @skb: the skb to push the tracker TVLV onto * @num_dests: the number of destination addresses to set in the header * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Pushes a multicast tracker TVLV header onto the given skb, including the * generic TVLV header but excluding the destination MAC addresses. * * The provided num_dests value is taken into consideration to set the * num_dests field in the tracker header and to set the appropriate TVLV length * value fields. * * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on * success 0.
*/ staticint batadv_mcast_forw_push_tracker(struct sk_buff *skb, int num_dests, unsignedshort *tvlv_len)
{ struct batadv_tvlv_mcast_tracker *mcast_tracker; struct batadv_tvlv_hdr *tvlv_hdr; unsignedint tvlv_value_len;
if (skb_headroom(skb) < sizeof(*mcast_tracker) + sizeof(*tvlv_hdr)) return -ENOMEM;
/** * batadv_mcast_forw_push_tvlvs() - push a multicast tracker TVLV onto an skb * @bat_priv: the bat priv with all the mesh interface information * @skb: the skb to push the tracker TVLV onto * @vid: the vlan identifier * @is_routable: indicates whether the destination is routable * @count: the number of originators the multicast packet needs to be sent to * @tvlv_len: stores the amount of currently pushed TVLV bytes * * Pushes a multicast tracker TVLV onto the given skb, including the collected * destination MAC addresses and the generic TVLV header. * * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on * success 0.
*/ staticint
batadv_mcast_forw_push_tvlvs(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, int is_routable, int count, unsignedshort *tvlv_len)
{ int ret;
ret = batadv_mcast_forw_push_dests(bat_priv, skb, vid, is_routable,
&count, tvlv_len); if (ret < 0) return ret;
ret = batadv_mcast_forw_push_tracker(skb, count, tvlv_len); if (ret < 0) return ret;
return 0;
}
/** * batadv_mcast_forw_push_hdr() - push a multicast packet header onto an skb * @skb: the skb to push the header onto * @tvlv_len: the total TVLV length value to set in the header * * Pushes a batman-adv multicast packet header onto the given skb and sets * the provided total TVLV length value in it. * * Caller needs to ensure enough skb headroom is available. * * Return: -ENOMEM if there is not enough skb headroom available. Otherwise, on * success 0.
*/ staticint
batadv_mcast_forw_push_hdr(struct sk_buff *skb, unsignedshort tvlv_len)
{ struct batadv_mcast_packet *mcast_packet;
if (skb_headroom(skb) < sizeof(*mcast_packet)) return -ENOMEM;
/** * batadv_mcast_forw_scrub_dests() - scrub destinations in a tracker TVLV * @bat_priv: the bat priv with all the mesh interface information * @comp_neigh: next hop neighbor to scrub+collect destinations for * @dest: start MAC entry in original skb's tracker TVLV * @next_dest: start MAC entry in to be sent skb's tracker TVLV * @num_dests: number of remaining destination MAC entries to iterate over * * This sorts destination entries into either the original batman-adv * multicast packet or the skb (copy) that is going to be sent to comp_neigh * next. * * In preparation for the next, to be (unicast) transmitted batman-adv multicast * packet skb to be sent to the given neighbor node, tries to collect all * originator MAC addresses that have the given neighbor node as their next hop * in the to be transmitted skb (copy), which next_dest points into. That is we * zero all destination entries in next_dest which do not have comp_neigh as * their next hop. And zero all destination entries in the original skb that * would have comp_neigh as their next hop (to avoid redundant transmissions and * duplicated payload later).
*/ staticvoid
batadv_mcast_forw_scrub_dests(struct batadv_priv *bat_priv, struct batadv_neigh_node *comp_neigh, u8 *dest,
u8 *next_dest, u16 num_dests)
{ struct batadv_neigh_node *next_neigh;
/* skip first entry, this is what we are comparing with */
eth_zero_addr(dest);
dest += ETH_ALEN;
next_dest += ETH_ALEN;
num_dests--;
batadv_mcast_forw_tracker_for_each_dest2(dest, next_dest, num_dests) { if (is_zero_ether_addr(next_dest)) continue;
/* sanity check, we expect unicast destinations */ if (is_multicast_ether_addr(next_dest)) {
eth_zero_addr(dest);
eth_zero_addr(next_dest); continue;
}
if (!batadv_compare_eth(next_neigh->addr, comp_neigh->addr)) {
eth_zero_addr(next_dest);
batadv_neigh_node_put(next_neigh); continue;
}
/* found an entry for our next packet to transmit, so remove it * from the original packet
*/
eth_zero_addr(dest);
batadv_neigh_node_put(next_neigh);
}
}
/** * batadv_mcast_forw_shrink_fill() - swap slot with next non-zero destination * @slot: the to be filled zero-MAC destination entry in a tracker TVLV * @num_dests_slot: remaining entries in tracker TVLV from/including slot * * Searches for the next non-zero-MAC destination entry in a tracker TVLV after * the given slot pointer. And if found, swaps it with the zero-MAC destination * entry which the slot points to. * * Return: true if slot was swapped/filled successfully, false otherwise.
*/ staticbool batadv_mcast_forw_shrink_fill(u8 *slot, u16 num_dests_slot)
{
u16 num_dests_filler;
u8 *filler;
/* sanity check, should not happen */ if (!num_dests_slot) returnfalse;
/* find a candidate to fill the empty slot */
batadv_mcast_forw_tracker_for_each_dest(filler, num_dests_filler) { if (is_zero_ether_addr(filler)) continue;
/** * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV * @skb: the batman-adv multicast packet to compact destinations in * * Compacts the originator destination MAC addresses in the multicast tracker * TVLV of the given multicast packet. This is done by moving all non-zero * MAC addresses in direction of the skb head and all zero MAC addresses in skb * tail direction, within the multicast tracker TVLV. * * Return: The number of consecutive zero MAC address destinations which are * now at the end of the multicast tracker TVLV.
*/ staticint batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
{ struct batadv_tvlv_mcast_tracker *mcast_tracker; unsignedchar *skb_net_hdr;
u16 num_dests_slot;
u8 *slot;
batadv_mcast_forw_tracker_for_each_dest(slot, num_dests_slot) { /* find an empty slot */ if (!is_zero_ether_addr(slot)) continue;
if (!batadv_mcast_forw_shrink_fill(slot, num_dests_slot)) /* could not find a filler, so we successfully packed * and can stop - and must not reduce num_dests_slot!
*/ break;
}
/* num_dests_slot is now the amount of reduced, zeroed * destinations at the end of the tracker TVLV
*/ return num_dests_slot;
}
/** * batadv_mcast_forw_shrink_align_offset() - get new alignment offset * @num_dests_old: the old, to be updated amount of destination nodes * @num_dests_reduce: the number of destinations that were removed * * Calculates the amount of potential extra alignment offset that is needed to * adjust the TVLV padding after the change in destination nodes. * * Return: * 0: If no change to padding is needed. * 2: If padding needs to be removed. * -2: If padding needs to be added.
*/ staticshort
batadv_mcast_forw_shrink_align_offset(unsignedint num_dests_old, unsignedint num_dests_reduce)
{ /* even amount of removed destinations -> no alignment change */ if (!(num_dests_reduce % 2)) return 0;
/* even to odd amount of destinations -> remove padding */ if (!(num_dests_old % 2)) return 2;
/* odd to even amount of destinations -> add padding */ return -2;
}
/** * batadv_mcast_forw_shrink_update_headers() - update shrunk mc packet headers * @skb: the batman-adv multicast packet to update headers of * @num_dests_reduce: the number of destinations that were removed * * This updates any fields of a batman-adv multicast packet that are affected * by the reduced number of destinations in the multicast tracket TVLV. In * particular this updates: * * The num_dest field of the multicast tracker TVLV. * The TVLV length field of the according generic TVLV header. * The batman-adv multicast packet's total TVLV length field. * * Return: The offset in skb's tail direction at which the new batman-adv * multicast packet header needs to start.
*/ staticunsignedint
batadv_mcast_forw_shrink_update_headers(struct sk_buff *skb, unsignedint num_dests_reduce)
{ struct batadv_tvlv_mcast_tracker *mcast_tracker; struct batadv_mcast_packet *mcast_packet; struct batadv_tvlv_hdr *tvlv_hdr; unsignedchar *skb_net_hdr; unsignedint offset; short align_offset;
u16 num_dests;
/** * batadv_mcast_forw_shrink_move_headers() - move multicast headers by offset * @skb: the batman-adv multicast packet to move headers for * @offset: a non-negative offset to move headers by, towards the skb tail * * Moves the batman-adv multicast packet header, its multicast tracker TVLV and * any TVLVs in between by the given offset in direction towards the tail.
*/ staticvoid
batadv_mcast_forw_shrink_move_headers(struct sk_buff *skb, unsignedint offset)
{ struct batadv_tvlv_mcast_tracker *mcast_tracker; unsignedchar *skb_net_hdr; unsignedint len;
u16 num_dests;
/** * batadv_mcast_forw_shrink_tracker() - remove zero addresses in a tracker tvlv * @skb: the batman-adv multicast packet to (potentially) shrink * * Removes all destinations with a zero MAC addresses (00:00:00:00:00:00) from * the given batman-adv multicast packet's tracker TVLV and updates headers * accordingly to maintain a valid batman-adv multicast packet.
*/ staticvoid batadv_mcast_forw_shrink_tracker(struct sk_buff *skb)
{ unsignedint offset;
u16 dests_reduced;
dests_reduced = batadv_mcast_forw_shrink_pack_dests(skb); if (!dests_reduced) return;
/** * batadv_mcast_forw_packet() - forward a batman-adv multicast packet * @bat_priv: the bat priv with all the mesh interface information * @skb: the received or locally generated batman-adv multicast packet * @local_xmit: indicates that the packet was locally generated and not received * * Parses the tracker TVLV of a batman-adv multicast packet and forwards the * packet as indicated in this TVLV. * * Caller needs to set the skb network header to the start of the multicast * tracker TVLV (excluding the generic TVLV header) and the skb transport header * to the next byte after this multicast tracker TVLV. * * Caller needs to free the skb. * * Return: NET_RX_SUCCESS or NET_RX_DROP on success or a negative error * code on failure. NET_RX_SUCCESS if the received packet is supposed to be * decapsulated and forwarded to the own mesh interface, NET_RX_DROP otherwise.
*/ staticint batadv_mcast_forw_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, bool local_xmit)
{ struct batadv_tvlv_mcast_tracker *mcast_tracker; struct batadv_neigh_node *neigh_node; unsignedlong offset, num_dests_off; struct sk_buff *nexthop_skb; unsignedchar *skb_net_hdr; bool local_recv = false; unsignedint tvlv_len; bool xmitted = false;
u8 *dest, *next_dest;
u16 num_dests; int ret;
/* (at least) TVLV part needs to be linearized */
SKB_LINEAR_ASSERT(skb);
/* check if num_dests is within skb length */
num_dests_off = offsetof(struct batadv_tvlv_mcast_tracker, num_dests); if (num_dests_off > skb_network_header_len(skb)) return -EINVAL;
dest = (u8 *)mcast_tracker + sizeof(*mcast_tracker);
/* check if full tracker tvlv is within skb length */
tvlv_len = sizeof(*mcast_tracker) + ETH_ALEN * num_dests; if (tvlv_len > skb_network_header_len(skb)) return -EINVAL;
if (local_recv) return NET_RX_SUCCESS; else return NET_RX_DROP;
}
/** * batadv_mcast_forw_tracker_tvlv_handler() - handle an mcast tracker tvlv * @bat_priv: the bat priv with all the mesh interface information * @skb: the received batman-adv multicast packet * * Parses the tracker TVLV of an incoming batman-adv multicast packet and * forwards the packet as indicated in this TVLV. * * Caller needs to set the skb network header to the start of the multicast * tracker TVLV (excluding the generic TVLV header) and the skb transport header * to the next byte after this multicast tracker TVLV. * * Caller needs to free the skb. * * Return: NET_RX_SUCCESS or NET_RX_DROP on success or a negative error * code on failure. NET_RX_SUCCESS if the received packet is supposed to be * decapsulated and forwarded to the own mesh interface, NET_RX_DROP otherwise.
*/ int batadv_mcast_forw_tracker_tvlv_handler(struct batadv_priv *bat_priv, struct sk_buff *skb)
{ return batadv_mcast_forw_packet(bat_priv, skb, false);
}
/** * batadv_mcast_forw_packet_hdrlen() - multicast packet header length * @num_dests: number of destination nodes * * Calculates the total batman-adv multicast packet header length for a given * number of destination nodes (excluding the outer ethernet frame). * * Return: The calculated total batman-adv multicast packet header length.
*/ unsignedint batadv_mcast_forw_packet_hdrlen(unsignedint num_dests)
{ /** * If the number of destination entries is even then we need to add * two byte padding to the tracker TVLV.
*/ int padding = (!(num_dests % 2)) ? 2 : 0;
/** * batadv_mcast_forw_expand_head() - expand headroom for an mcast packet * @bat_priv: the bat priv with all the mesh interface information * @skb: the multicast packet to send * * Tries to expand an skb's headroom so that its head to tail is 1298 * bytes (minimum IPv6 MTU + vlan ethernet header size) large. * * Return: -EINVAL if the given skb's length is too large or -ENOMEM on memory * allocation failure. Otherwise, on success, zero is returned.
*/ staticint batadv_mcast_forw_expand_head(struct batadv_priv *bat_priv, struct sk_buff *skb)
{ int hdr_size = VLAN_ETH_HLEN + IPV6_MIN_MTU - skb->len;
/* TODO: Could be tightened to actual number of destination nodes? * But it's tricky, number of destinations might have increased since * we last checked.
*/ if (hdr_size < 0) { /* batadv_mcast_forw_mode_check_count() should ensure we do not * end up here
*/
WARN_ON(1); return -EINVAL;
}
/** * batadv_mcast_forw_push() - encapsulate skb in a batman-adv multicast packet * @bat_priv: the bat priv with all the mesh interface information * @skb: the multicast packet to encapsulate and send * @vid: the vlan identifier * @is_routable: indicates whether the destination is routable * @count: the number of originators the multicast packet needs to be sent to * * Encapsulates the given multicast packet in a batman-adv multicast packet. * A multicast tracker TVLV with destination originator addresses for any node * that signaled interest in it, that is either via the translation table or the * according want-all flags, is attached accordingly. * * Return: true on success, false otherwise.
*/ bool batadv_mcast_forw_push(struct batadv_priv *bat_priv, struct sk_buff *skb, unsignedshort vid, int is_routable, int count)
{ unsignedshort tvlv_len = 0; int ret;
if (batadv_mcast_forw_expand_head(bat_priv, skb) < 0) goto err;
skb_reset_transport_header(skb);
ret = batadv_mcast_forw_push_tvlvs(bat_priv, skb, vid, is_routable,
count, &tvlv_len); if (ret < 0) goto err;
ret = batadv_mcast_forw_push_hdr(skb, tvlv_len); if (ret < 0) goto err;
returntrue;
err: if (tvlv_len)
skb_pull(skb, tvlv_len);
returnfalse;
}
/** * batadv_mcast_forw_mcsend() - send a self prepared batman-adv multicast packet * @bat_priv: the bat priv with all the mesh interface information * @skb: the multicast packet to encapsulate and send * * Transmits a batman-adv multicast packet that was locally prepared and * consumes/frees it. * * Return: NET_XMIT_DROP on memory allocation failure. NET_XMIT_SUCCESS * otherwise.
*/ int batadv_mcast_forw_mcsend(struct batadv_priv *bat_priv, struct sk_buff *skb)
{ int ret = batadv_mcast_forw_packet(bat_priv, skb, true);
if (ret < 0) {
kfree_skb(skb); return NET_XMIT_DROP;
}
consume_skb(skb); return NET_XMIT_SUCCESS;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet)
¤
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.