/** * batadv_hardif_release() - release hard interface from lists and queue for * free after rcu grace period * @ref: kref pointer of the hard interface
*/ void batadv_hardif_release(struct kref *ref)
{ struct batadv_hard_iface *hard_iface;
/** * batadv_hardif_get_by_netdev() - Get hard interface object of a net_device * @net_dev: net_device to search for * * Return: batadv_hard_iface of net_dev (with increased refcnt), NULL on errors
*/ struct batadv_hard_iface *
batadv_hardif_get_by_netdev(conststruct net_device *net_dev)
{ struct batadv_hard_iface *hard_iface;
/** * batadv_getlink_net() - return link net namespace (of use fallback) * @netdev: net_device to check * @fallback_net: return in case get_link_net is not available for @netdev * * Return: result of rtnl_link_ops->get_link_net or @fallback_net
*/ staticstruct net *batadv_getlink_net(conststruct net_device *netdev, struct net *fallback_net)
{ if (!netdev->rtnl_link_ops) return fallback_net;
if (!netdev->rtnl_link_ops->get_link_net) return fallback_net;
/** * batadv_mutual_parents() - check if two devices are each others parent * @dev1: 1st net dev * @net1: 1st devices netns * @dev2: 2nd net dev * @net2: 2nd devices netns * * veth devices come in pairs and each is the parent of the other! * * Return: true if the devices are each others parent, otherwise false
*/ staticbool batadv_mutual_parents(conststruct net_device *dev1, struct net *net1, conststruct net_device *dev2, struct net *net2)
{ int dev1_parent_iflink = dev_get_iflink(dev1); int dev2_parent_iflink = dev_get_iflink(dev2); conststruct net *dev1_parent_net; conststruct net *dev2_parent_net;
/** * batadv_is_on_batman_iface() - check if a device is a batman iface descendant * @net_dev: the device to check * * If the user creates any virtual device on top of a batman-adv interface, it * is important to prevent this new interface from being used to create a new * mesh network (this behaviour would lead to a batman-over-batman * configuration). This function recursively checks all the fathers of the * device passed as argument looking for a batman-adv mesh interface. * * Return: true if the device is descendant of a batman-adv mesh interface (or * if it is a batman-adv interface itself), false otherwise
*/ staticbool batadv_is_on_batman_iface(conststruct net_device *net_dev)
{ struct net *net = dev_net(net_dev); struct net_device *parent_dev; struct net *parent_net; int iflink; bool ret;
/* check if this is a batman-adv mesh interface */ if (batadv_meshif_is_valid(net_dev)) returntrue;
iflink = dev_get_iflink(net_dev); if (iflink == 0) returnfalse;
parent_net = batadv_getlink_net(net_dev, net);
/* iflink to itself, most likely physical device */ if (net == parent_net && iflink == net_dev->ifindex) returnfalse;
/* recurse over the parent device */
parent_dev = __dev_get_by_index((struct net *)parent_net, iflink); if (!parent_dev) {
pr_warn("Cannot find parent device. Skipping batadv-on-batadv check for %s\n",
net_dev->name); returnfalse;
}
if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net)) returnfalse;
ret = batadv_is_on_batman_iface(parent_dev);
return ret;
}
staticbool batadv_is_valid_iface(conststruct net_device *net_dev)
{ if (net_dev->flags & IFF_LOOPBACK) returnfalse;
if (net_dev->type != ARPHRD_ETHER) returnfalse;
if (net_dev->addr_len != ETH_ALEN) returnfalse;
/* no batman over batman */ if (batadv_is_on_batman_iface(net_dev)) returnfalse;
returntrue;
}
/** * batadv_get_real_netdevice() - check if the given netdev struct is a virtual * interface on top of another 'real' interface * @netdev: the device to check * * Callers must hold the rtnl semaphore. You may want batadv_get_real_netdev() * instead of this. * * Return: the 'real' net device or the original net device and NULL in case * of an error.
*/ staticstruct net_device *batadv_get_real_netdevice(struct net_device *netdev)
{ struct batadv_hard_iface *hard_iface = NULL; struct net_device *real_netdev = NULL; struct net *real_net; struct net *net; int iflink;
/** * batadv_get_real_netdev() - check if the given net_device struct is a virtual * interface on top of another 'real' interface * @net_device: the device to check * * Return: the 'real' net device or the original net device and NULL in case * of an error.
*/ struct net_device *batadv_get_real_netdev(struct net_device *net_device)
{ struct net_device *real_netdev;
/** * batadv_is_wext_netdev() - check if the given net_device struct is a * wext wifi interface * @net_device: the device to check * * Return: true if the net device is a wext wireless device, false * otherwise.
*/ staticbool batadv_is_wext_netdev(struct net_device *net_device)
{ if (!net_device) returnfalse;
#ifdef CONFIG_WIRELESS_EXT /* pre-cfg80211 drivers have to implement WEXT, so it is possible to * check for wireless_handlers != NULL
*/ if (net_device->wireless_handlers) returntrue; #endif
returnfalse;
}
/** * batadv_is_cfg80211_netdev() - check if the given net_device struct is a * cfg80211 wifi interface * @net_device: the device to check * * Return: true if the net device is a cfg80211 wireless device, false * otherwise.
*/ staticbool batadv_is_cfg80211_netdev(struct net_device *net_device)
{ if (!net_device) returnfalse;
#if IS_ENABLED(CONFIG_CFG80211) /* cfg80211 drivers have to set ieee80211_ptr */ if (net_device->ieee80211_ptr) returntrue; #endif
returnfalse;
}
/** * batadv_wifi_flags_evaluate() - calculate wifi flags for net_device * @net_device: the device to check * * Return: batadv_hard_iface_wifi_flags flags of the device
*/ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device)
{
u32 wifi_flags = 0; struct net_device *real_netdev;
if (batadv_is_wext_netdev(net_device))
wifi_flags |= BATADV_HARDIF_WIFI_WEXT_DIRECT;
if (batadv_is_cfg80211_netdev(net_device))
wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT;
real_netdev = batadv_get_real_netdevice(net_device); if (!real_netdev) return wifi_flags;
if (real_netdev == net_device) goto out;
if (batadv_is_wext_netdev(real_netdev))
wifi_flags |= BATADV_HARDIF_WIFI_WEXT_INDIRECT;
if (batadv_is_cfg80211_netdev(real_netdev))
wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT;
out:
dev_put(real_netdev); return wifi_flags;
}
/** * batadv_is_cfg80211_hardif() - check if the given hardif is a cfg80211 wifi * interface * @hard_iface: the device to check * * Return: true if the net device is a cfg80211 wireless device, false * otherwise.
*/ bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface)
{
u32 allowed_flags = 0;
/** * batadv_is_wifi_hardif() - check if the given hardif is a wifi interface * @hard_iface: the device to check * * Return: true if the net device is a 802.11 wireless device, false otherwise.
*/ bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface)
{ if (!hard_iface) returnfalse;
return hard_iface->wifi_flags != 0;
}
/** * batadv_hardif_no_broadcast() - check whether (re)broadcast is necessary * @if_outgoing: the outgoing interface checked and considered for (re)broadcast * @orig_addr: the originator of this packet * @orig_neigh: originator address of the forwarder we just got the packet from * (NULL if we originated) * * Checks whether a packet needs to be (re)broadcasted on the given interface. * * Return: * BATADV_HARDIF_BCAST_NORECIPIENT: No neighbor on interface * BATADV_HARDIF_BCAST_DUPFWD: Just one neighbor, but it is the forwarder * BATADV_HARDIF_BCAST_DUPORIG: Just one neighbor, but it is the originator * BATADV_HARDIF_BCAST_OK: Several neighbors, must broadcast
*/ int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing,
u8 *orig_addr, u8 *orig_neigh)
{ struct batadv_hardif_neigh_node *hardif_neigh; struct hlist_node *first; int ret = BATADV_HARDIF_BCAST_OK;
rcu_read_lock();
/* 0 neighbors -> no (re)broadcast */
first = rcu_dereference(hlist_first_rcu(&if_outgoing->neigh_list)); if (!first) {
ret = BATADV_HARDIF_BCAST_NORECIPIENT; goto out;
}
/* >1 neighbors -> (re)broadcast */ if (rcu_dereference(hlist_next_rcu(first))) goto out;
/* 1 neighbor, is the originator -> no rebroadcast */ if (orig_addr && batadv_compare_eth(hardif_neigh->orig, orig_addr)) {
ret = BATADV_HARDIF_BCAST_DUPORIG; /* 1 neighbor, is the one we received from -> no rebroadcast */
} elseif (orig_neigh &&
batadv_compare_eth(hardif_neigh->orig, orig_neigh)) {
ret = BATADV_HARDIF_BCAST_DUPFWD;
}
netdev_for_each_lower_private(mesh_iface, tmp_hard_iface, iter) { if (tmp_hard_iface == hard_iface) continue;
if (tmp_hard_iface->if_status == BATADV_IF_NOT_IN_USE) continue;
if (!batadv_compare_eth(tmp_hard_iface->net_dev->dev_addr,
hard_iface->net_dev->dev_addr)) continue;
pr_warn("The newly added mac address (%pM) already exists on: %s\n",
hard_iface->net_dev->dev_addr, tmp_hard_iface->net_dev->name);
pr_warn("It is strongly recommended to keep mac addresses unique to avoid problems!\n");
}
}
/** * batadv_hardif_min_mtu() - Calculate maximum MTU for mesh interface * @mesh_iface: netdev struct of the mesh interface * * Return: MTU for the mesh-interface (limited by the minimal MTU of all active * slave interfaces)
*/ int batadv_hardif_min_mtu(struct net_device *mesh_iface)
{ struct batadv_priv *bat_priv = netdev_priv(mesh_iface); conststruct batadv_hard_iface *hard_iface; struct list_head *iter; int min_mtu = INT_MAX;
if (atomic_read(&bat_priv->fragmentation) == 0) goto out;
/* with fragmentation enabled the maximum size of internally generated * packets such as translation table exchanges or tvlv containers, etc * has to be calculated
*/
min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE);
min_mtu -= sizeof(struct batadv_frag_packet);
min_mtu *= BATADV_FRAG_MAX_FRAGMENTS;
out: /* report to the other components the maximum amount of bytes that * batman-adv can send over the wire (without considering the payload * overhead). For example, this value is used by TT to compute the * maximum local table size
*/
atomic_set(&bat_priv->packet_size_max, min_mtu);
/* the real mesh-interface MTU is computed by removing the payload * overhead from the maximum amount of bytes that was just computed.
*/ return min_t(int, min_mtu - batadv_max_header_len(), BATADV_MAX_MTU);
}
/** * batadv_update_min_mtu() - Adjusts the MTU if a new interface with a smaller * MTU appeared * @mesh_iface: netdev struct of the mesh interface
*/ void batadv_update_min_mtu(struct net_device *mesh_iface)
{ struct batadv_priv *bat_priv = netdev_priv(mesh_iface); int limit_mtu; int mtu;
mtu = batadv_hardif_min_mtu(mesh_iface);
if (bat_priv->mtu_set_by_user)
limit_mtu = bat_priv->mtu_set_by_user; else
limit_mtu = ETH_DATA_LEN;
mtu = min(mtu, limit_mtu);
dev_set_mtu(mesh_iface, mtu);
/* Check if the local translate table should be cleaned up to match a * new (and smaller) MTU.
*/
batadv_tt_local_resize_to_mtu(mesh_iface);
}
/* the first active interface becomes our primary interface or * the next active interface after the old primary interface was removed
*/
primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if)
batadv_primary_if_select(bat_priv, hard_iface);
/** * batadv_hardif_enable_interface() - Enslave hard interface to mesh interface * @hard_iface: hard interface to add to mesh interface * @mesh_iface: netdev struct of the mesh interface * * Return: 0 on success or negative error number in case of failure
*/ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, struct net_device *mesh_iface)
{ struct batadv_priv *bat_priv;
__be16 ethertype = htons(ETH_P_BATMAN); int max_header_len = batadv_max_header_len(); unsignedint required_mtu; unsignedint hardif_mtu; int ret;
if (atomic_read(&bat_priv->fragmentation) &&
hardif_mtu < required_mtu)
batadv_info(hard_iface->mesh_iface, "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %i would solve the problem.\n",
hard_iface->net_dev->name, hardif_mtu,
required_mtu);
if (!atomic_read(&bat_priv->fragmentation) &&
hardif_mtu < required_mtu)
batadv_info(hard_iface->mesh_iface, "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %i.\n",
hard_iface->net_dev->name, hardif_mtu,
required_mtu);
batadv_check_known_mac_addr(hard_iface);
if (batadv_hardif_is_iface_up(hard_iface))
batadv_hardif_activate_interface(hard_iface); else
batadv_err(hard_iface->mesh_iface, "Not using interface %s (retrying later): interface not active\n",
hard_iface->net_dev->name);
batadv_hardif_recalc_extra_skbroom(mesh_iface);
if (bat_priv->algo_ops->iface.enabled)
bat_priv->algo_ops->iface.enabled(hard_iface);
/** * batadv_hardif_cnt() - get number of interfaces enslaved to mesh interface * @mesh_iface: mesh interface to check * * This function is only using RCU for locking - the result can therefore be * off when another function is modifying the list at the same time. The * caller can use the rtnl_lock to make sure that the count is accurate. * * Return: number of connected/enslaved hard interfaces
*/ static size_t batadv_hardif_cnt(struct net_device *mesh_iface)
{ struct batadv_hard_iface *hard_iface; struct list_head *iter;
size_t count = 0;
/* delete all references to this hard_iface */
batadv_purge_orig_ref(bat_priv);
batadv_purge_outstanding_packets(bat_priv, hard_iface);
netdev_put(hard_iface->mesh_iface, &hard_iface->meshif_dev_tracker);
switch (event) { case NETDEV_UP:
batadv_hardif_activate_interface(hard_iface); break; case NETDEV_GOING_DOWN: case NETDEV_DOWN:
batadv_hardif_deactivate_interface(hard_iface); break; case NETDEV_UNREGISTER: case NETDEV_PRE_TYPE_CHANGE:
list_del_rcu(&hard_iface->list);
batadv_hardif_generation++;
batadv_hardif_remove_interface(hard_iface); break; case NETDEV_CHANGEMTU: if (hard_iface->mesh_iface)
batadv_update_min_mtu(hard_iface->mesh_iface); break; case NETDEV_CHANGEADDR: if (hard_iface->if_status == BATADV_IF_NOT_IN_USE) goto hardif_put;
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.