diff --git a/MAINTAINERS b/MAINTAINERS index 142a91386338..cf7e92d9e6db 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4449,7 +4449,7 @@ W: https://www.open-mesh.org/ Q: https://patchwork.open-mesh.org/project/batman/list/ B: https://www.open-mesh.org/projects/batman-adv/issues C: ircs://irc.hackint.org/batadv -T: git https://git.open-mesh.org/linux-merge.git +T: git https://git.open-mesh.org/batadv.git F: Documentation/networking/batman-adv.rst F: include/uapi/linux/batadv_packet.h F: include/uapi/linux/batman_adv.h @@ -18642,6 +18642,7 @@ F: net/ F: samples/pktgen/ F: tools/net/ F: tools/testing/selftests/net/ +X: Documentation/networking/batman-adv.rst X: Documentation/networking/mac80211-injection.rst X: Documentation/networking/mac80211_hwsim/ X: Documentation/networking/regulatory.rst @@ -18652,6 +18653,7 @@ X: include/net/iw_handler.h X: include/net/mac80211.h X: include/net/wext.h X: net/9p/ +X: net/batman-adv/ X: net/bluetooth/ X: net/can/ X: net/ceph/ diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index d3c4d4143c14..5d7456f1240d 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile @@ -30,5 +30,6 @@ batman-adv-$(CONFIG_BATMAN_ADV_TRACING) += trace.o batman-adv-y += tp_meter.o batman-adv-y += translation-table.o batman-adv-y += tvlv.o +batman-adv-y += version.o CFLAGS_trace.o := -I$(src) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index b8b1b997960a..6f5a468c4084 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -194,14 +195,17 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) get_random_bytes(&random_seqno, sizeof(random_seqno)); atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno); - hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN; - ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC); + hard_iface->bat_iv.ogm_buff.len = BATADV_OGM_HLEN; + hard_iface->bat_iv.ogm_buff.capacity = BATADV_OGM_HLEN; + hard_iface->bat_iv.ogm_buff.header_length = BATADV_OGM_HLEN; + + ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff.capacity, GFP_ATOMIC); if (!ogm_buff) { mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); return -ENOMEM; } - hard_iface->bat_iv.ogm_buff = ogm_buff; + hard_iface->bat_iv.ogm_buff.buf = ogm_buff; batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff; batadv_ogm_packet->packet_type = BATADV_IV_OGM; @@ -220,8 +224,9 @@ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface) { mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); - kfree(hard_iface->bat_iv.ogm_buff); - hard_iface->bat_iv.ogm_buff = NULL; + kfree(hard_iface->bat_iv.ogm_buff.buf); + memset(&hard_iface->bat_iv.ogm_buff, 0, + sizeof(hard_iface->bat_iv.ogm_buff)); mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); @@ -235,7 +240,7 @@ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface) mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); - ogm_buff = hard_iface->bat_iv.ogm_buff; + ogm_buff = hard_iface->bat_iv.ogm_buff.buf; if (!ogm_buff) goto unlock; @@ -257,7 +262,7 @@ batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface) mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); - ogm_buff = hard_iface->bat_iv.ogm_buff; + ogm_buff = hard_iface->bat_iv.ogm_buff.buf; if (!ogm_buff) goto unlock; @@ -274,7 +279,7 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv) { unsigned int msecs; - msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER; + msecs = READ_ONCE(bat_priv->orig_interval) - BATADV_JITTER; msecs += get_random_u32_below(2 * BATADV_JITTER); return jiffies + msecs_to_jiffies(msecs); @@ -289,7 +294,7 @@ static unsigned long batadv_iv_ogm_fwd_send_time(void) /* apply hop penalty for a normal link */ static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv) { - int hop_penalty = atomic_read(&bat_priv->hop_penalty); + int hop_penalty = READ_ONCE(bat_priv->hop_penalty); int new_tq; new_tq = tq * (BATADV_TQ_MAX_VALUE - hop_penalty); @@ -555,7 +560,7 @@ static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, unsigned int skb_size; atomic_t *queue_left = own_packet ? NULL : &bat_priv->batman_queue_left; - if (atomic_read(&bat_priv->aggregated_ogms)) + if (READ_ONCE(bat_priv->aggregated_ogms)) skb_size = max_t(unsigned int, BATADV_MAX_AGGREGATION_BYTES, packet_len); else @@ -641,6 +646,7 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, struct batadv_ogm_packet *batadv_ogm_packet; bool direct_link; unsigned long max_aggregation_jiffies; + bool aggregated_ogms; batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff; direct_link = !!(batadv_ogm_packet->flags & BATADV_DIRECTLINK); @@ -648,8 +654,10 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, /* find position for the packet in the forward queue */ spin_lock_bh(&bat_priv->forw_bat_list_lock); + aggregated_ogms = READ_ONCE(bat_priv->aggregated_ogms); + /* own packets are not to be aggregated */ - if (atomic_read(&bat_priv->aggregated_ogms) && !own_packet) { + if (aggregated_ogms && !own_packet) { hlist_for_each_entry(forw_packet_pos, &bat_priv->forw_bat_list, list) { if (batadv_iv_ogm_can_aggregate(batadv_ogm_packet, @@ -675,7 +683,7 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, * we hold it back for a while, so that it might be aggregated * later on */ - if (!own_packet && atomic_read(&bat_priv->aggregated_ogms)) + if (!own_packet && aggregated_ogms) send_time += max_aggregation_jiffies; return batadv_iv_ogm_aggregate_new(packet_buff, packet_len, @@ -792,10 +800,9 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); - unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff; + struct batadv_ogm_buf *ogm_buff = &hard_iface->bat_iv.ogm_buff; struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_hard_iface *primary_if, *tmp_hard_iface; - int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; struct list_head *iter; u32 seqno; u16 tvlv_len = 0; @@ -807,7 +814,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex); /* interface already disabled by batadv_iv_ogm_iface_disable */ - if (!*ogm_buff) + if (!ogm_buff->buf) return; /* the interface gets activated here to avoid race conditions between @@ -826,9 +833,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) * appended as it may alter the tt tvlv container */ batadv_tt_local_commit_changes(bat_priv); - ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, - ogm_buff_len, - BATADV_OGM_HLEN); + ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff); if (ret < 0) { reschedule = true; goto out; @@ -837,7 +842,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) tvlv_len = ret; } - batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); + batadv_ogm_packet = ogm_buff->buf; batadv_ogm_packet->tvlv_len = htons(tvlv_len); /* change sequence number to network order */ @@ -853,7 +858,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) /* OGMs from secondary interfaces are only scheduled on their * respective interfaces. */ - scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, + scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf, ogm_buff->len, hard_iface, hard_iface, 1, send_time); if (!scheduled) reschedule = true; @@ -869,8 +874,8 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) if (!kref_get_unless_zero(&tmp_hard_iface->refcount)) continue; - scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, - *ogm_buff_len, hard_iface, + scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf, + ogm_buff->len, hard_iface, tmp_hard_iface, 1, send_time); batadv_hardif_put(tmp_hard_iface); @@ -888,7 +893,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) */ queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_iv.reschedule_work, - msecs_to_jiffies(atomic_read(&bat_priv->orig_interval))); + msecs_to_jiffies(READ_ONCE(bat_priv->orig_interval))); } batadv_hardif_put(primary_if); @@ -1214,7 +1219,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, inv_asym_penalty = BATADV_TQ_MAX_VALUE * neigh_rq_inv_cube; inv_asym_penalty /= neigh_rq_max_cube; tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty; - tq_iface_hop_penalty -= atomic_read(&if_incoming->hop_penalty); + tq_iface_hop_penalty -= READ_ONCE(if_incoming->hop_penalty); /* penalize if the OGM is forwarded on the same interface. WiFi * interfaces and other half duplex devices suffer from throughput @@ -1773,7 +1778,7 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) delayed_work); bat_priv = netdev_priv(forw_packet->if_incoming->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { dropped = true; goto out; } @@ -2321,7 +2326,7 @@ static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface) static void batadv_iv_init_sel_class(struct batadv_priv *bat_priv) { /* set default TQ difference threshold to 20 */ - atomic_set(&bat_priv->gw.sel_class, 20); + WRITE_ONCE(bat_priv->gw.sel_class, 20); } static struct batadv_gw_node * @@ -2353,7 +2358,7 @@ batadv_iv_gw_get_best_gw_node(struct batadv_priv *bat_priv) tq_avg = router_ifinfo->bat_iv.tq_avg; - switch (atomic_read(&bat_priv->gw.sel_class)) { + switch (READ_ONCE(bat_priv->gw.sel_class)) { case 1: /* fast connection */ tmp_gw_factor = tq_avg * tq_avg; tmp_gw_factor *= gw_node->bandwidth_down; @@ -2407,13 +2412,14 @@ static bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv, { struct batadv_neigh_ifinfo *router_orig_ifinfo = NULL; struct batadv_neigh_ifinfo *router_gw_ifinfo = NULL; + u32 sel_class = READ_ONCE(bat_priv->gw.sel_class); struct batadv_neigh_node *router_gw = NULL; struct batadv_neigh_node *router_orig = NULL; u8 gw_tq_avg, orig_tq_avg; bool ret = false; /* dynamic re-election is performed only on fast or late switch */ - if (atomic_read(&bat_priv->gw.sel_class) <= 2) + if (sel_class <= 2) return false; router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); @@ -2448,8 +2454,7 @@ static bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv, /* if the routing class is greater than 3 the value tells us how much * greater the TQ value of the new gateway must be */ - if ((atomic_read(&bat_priv->gw.sel_class) > 3) && - (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw.sel_class))) + if (sel_class > 3 && orig_tq_avg - gw_tq_avg < sel_class) goto out; batadv_dbg(BATADV_DBG_BATMAN, bat_priv, diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index de9444714264..ac2932da5472 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -7,8 +7,8 @@ #include "bat_v.h" #include "main.h" -#include #include +#include #include #include #include @@ -505,7 +505,7 @@ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, static void batadv_v_init_sel_class(struct batadv_priv *bat_priv) { /* set default throughput difference threshold to 5Mbps */ - atomic_set(&bat_priv->gw.sel_class, 50); + WRITE_ONCE(bat_priv->gw.sel_class, 50); } /** @@ -602,7 +602,7 @@ static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv, u32 gw_throughput, orig_throughput, threshold; bool ret = false; - threshold = atomic_read(&bat_priv->gw.sel_class); + threshold = READ_ONCE(bat_priv->gw.sel_class); curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig); if (!curr_gw) { @@ -812,8 +812,8 @@ void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface) /* enable link throughput auto-detection by setting the throughput * override to zero */ - atomic_set(&hard_iface->bat_v.throughput_override, 0); - atomic_set(&hard_iface->bat_v.elp_interval, 500); + WRITE_ONCE(hard_iface->bat_v.throughput_override, 0); + WRITE_ONCE(hard_iface->bat_v.elp_interval, 500); hard_iface->bat_v.aggr_len = 0; skb_queue_head_init(&hard_iface->bat_v.aggr_list); diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index fdc2abe96d77..d53485d17220 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +63,7 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface) { unsigned int msecs; - msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER; + msecs = READ_ONCE(hard_iface->bat_v.elp_interval) - BATADV_JITTER; msecs += get_random_u32_below(2 * BATADV_JITTER); queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq, @@ -85,6 +86,7 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh, struct ethtool_link_ksettings link_settings; struct net_device *real_netdev; struct station_info sinfo; + u32 wifi_flags; u32 throughput; int ret; @@ -97,7 +99,7 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh, /* if the user specified a customised value for this interface, then * return it directly */ - throughput = atomic_read(&hard_iface->bat_v.throughput_override); + throughput = READ_ONCE(hard_iface->bat_v.throughput_override); if (throughput != 0) { *pthroughput = throughput; return true; @@ -106,8 +108,9 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh, /* if this is a wireless device, then ask its throughput through * cfg80211 API */ - if (batadv_is_wifi_hardif(hard_iface)) { - if (!batadv_is_cfg80211_hardif(hard_iface)) + wifi_flags = batadv_hardif_get_wifi_flags(hard_iface); + if (batadv_is_wifi(wifi_flags)) { + if (!batadv_is_cfg80211(wifi_flags)) /* unsupported WiFi driver version */ goto default_throughput; @@ -304,7 +307,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work) hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v); bat_priv = netdev_priv(hard_iface->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) goto out; /* we are in the process of shutting this interface down */ @@ -322,7 +325,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work) elp_packet = (struct batadv_elp_packet *)skb->data; elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno)); - elp_interval = atomic_read(&hard_iface->bat_v.elp_interval); + elp_interval = READ_ONCE(hard_iface->bat_v.elp_interval); elp_packet->elp_interval = htonl(elp_interval); batadv_dbg(BATADV_DBG_BATMAN, bat_priv, diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index d66ca77b1aaa..5936d0048be0 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -8,7 +8,9 @@ #include "main.h" #include +#include #include +#include #include #include #include @@ -105,7 +107,7 @@ static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv) if (delayed_work_pending(&bat_priv->bat_v.ogm_wq)) return; - msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER; + msecs = READ_ONCE(bat_priv->orig_interval) - BATADV_JITTER; msecs += get_random_u32_below(2 * BATADV_JITTER); queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq, msecs_to_jiffies(msecs)); @@ -246,7 +248,7 @@ static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv, return; } - if (!atomic_read(&bat_priv->aggregated_ogms)) { + if (!READ_ONCE(bat_priv->aggregated_ogms)) { batadv_v_ogm_send_to_if(bat_priv, skb, hard_iface); return; } @@ -268,39 +270,35 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv) { struct batadv_hard_iface *hard_iface; struct batadv_ogm2_packet *ogm_packet; + struct batadv_ogm_buf *ogm_buff; struct sk_buff *skb, *skb_tmp; - unsigned char **ogm_buff; struct list_head *iter; - int *ogm_buff_len; u16 tvlv_len; int ret; lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) goto out; ogm_buff = &bat_priv->bat_v.ogm_buff; - ogm_buff_len = &bat_priv->bat_v.ogm_buff_len; /* tt changes have to be committed before the tvlv data is * appended as it may alter the tt tvlv container */ batadv_tt_local_commit_changes(bat_priv); - ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, - ogm_buff_len, - BATADV_OGM2_HLEN); + ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff); if (ret < 0) goto reschedule; tvlv_len = ret; - skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + *ogm_buff_len); + skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff->len); if (!skb) goto reschedule; skb_reserve(skb, ETH_HLEN); - skb_put_data(skb, *ogm_buff, *ogm_buff_len); + skb_put_data(skb, ogm_buff->buf, ogm_buff->len); ogm_packet = (struct batadv_ogm2_packet *)skb->data; ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno)); @@ -446,10 +444,10 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface) struct batadv_ogm2_packet *ogm_packet; mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); - if (!bat_priv->bat_v.ogm_buff) + if (!bat_priv->bat_v.ogm_buff.buf) goto unlock; - ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff; + ogm_packet = bat_priv->bat_v.ogm_buff.buf; ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr); unlock: @@ -484,9 +482,9 @@ static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, struct batadv_hard_iface *if_outgoing, u32 throughput) { - int if_hop_penalty = atomic_read(&if_incoming->hop_penalty); - int hop_penalty = atomic_read(&bat_priv->hop_penalty); - int hop_penalty_max = BATADV_TQ_MAX_VALUE; + u32 if_hop_penalty = READ_ONCE(if_incoming->hop_penalty); + u32 hop_penalty = READ_ONCE(bat_priv->hop_penalty); + u32 hop_penalty_max = BATADV_TQ_MAX_VALUE; /* Apply per hardif hop penalty */ throughput = throughput * (hop_penalty_max - if_hop_penalty) / @@ -721,7 +719,7 @@ static bool batadv_v_ogm_route_update(struct batadv_priv *bat_priv, * don't route towards it */ router = batadv_orig_router_get(orig_node, if_outgoing); - if (router && router->orig_node != orig_node && !orig_neigh_router) { + if (router && ACCESS_PRIVATE(router, orig_node_id) != orig_node && !orig_neigh_router) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: OGM via unknown neighbor!\n"); goto out; @@ -1050,12 +1048,15 @@ int batadv_v_ogm_init(struct batadv_priv *bat_priv) unsigned char *ogm_buff; u32 random_seqno; - bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN; - ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC); + bat_priv->bat_v.ogm_buff.len = BATADV_OGM2_HLEN; + bat_priv->bat_v.ogm_buff.capacity = BATADV_OGM2_HLEN; + bat_priv->bat_v.ogm_buff.header_length = BATADV_OGM2_HLEN; + + ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff.capacity, GFP_ATOMIC); if (!ogm_buff) return -ENOMEM; - bat_priv->bat_v.ogm_buff = ogm_buff; + bat_priv->bat_v.ogm_buff.buf = ogm_buff; ogm_packet = (struct batadv_ogm2_packet *)ogm_buff; ogm_packet->packet_type = BATADV_OGM2; ogm_packet->version = BATADV_COMPAT_VERSION; @@ -1083,9 +1084,8 @@ void batadv_v_ogm_free(struct batadv_priv *bat_priv) mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); - kfree(bat_priv->bat_v.ogm_buff); - bat_priv->bat_v.ogm_buff = NULL; - bat_priv->bat_v.ogm_buff_len = 0; + kfree(bat_priv->bat_v.ogm_buff.buf); + memset(&bat_priv->bat_v.ogm_buff, 0, sizeof(bat_priv->bat_v.ogm_buff)); mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex); } diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index ffe854018bd3..87d6b11161e4 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include @@ -1379,7 +1380,7 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, bat_priv->bla.claim_dest.group = group; /* purge everything when bridge loop avoidance is turned off */ - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) oldif = NULL; if (!oldif) { @@ -1483,7 +1484,7 @@ static void batadv_bla_periodic_work(struct work_struct *work) batadv_bla_purge_claims(bat_priv, primary_if, 0); batadv_bla_purge_backbone_gw(bat_priv, 0); - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) goto out; if (atomic_dec_and_test(&bat_priv->bla.loopdetect_next)) { @@ -1782,7 +1783,7 @@ bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, struct batadv_bla_backbone_gw *backbone_gw; int i; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) return false; if (!hash) @@ -1820,7 +1821,7 @@ bool batadv_bla_is_backbone_gw(struct sk_buff *skb, struct batadv_bla_backbone_gw *backbone_gw; unsigned short vid; - if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(orig_node->bat_priv->bridge_loop_avoidance)) return false; /* first, find out the vid. */ @@ -1952,7 +1953,7 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, if (!primary_if) goto handled; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) goto allow; if (batadv_bla_loopdetect_check(bat_priv, skb, primary_if, vid)) @@ -2084,7 +2085,7 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, if (!primary_if) goto out; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) goto allow; if (batadv_bla_process_claim(bat_priv, primary_if, skb)) @@ -2504,7 +2505,7 @@ bool batadv_bla_check_claim(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if = NULL; bool ret = true; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) return ret; primary_if = batadv_primary_if_get_selected(bat_priv); diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 0a8bd95e2f99..0b02018c5b85 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -742,7 +743,7 @@ static void batadv_dat_tvlv_container_update(struct batadv_priv *bat_priv) { char dat_mode; - dat_mode = atomic_read(&bat_priv->distributed_arp_table); + dat_mode = READ_ONCE(bat_priv->distributed_arp_table); switch (dat_mode) { case 0: @@ -1138,7 +1139,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, int hdr_size = 0; unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1233,7 +1234,7 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, unsigned short vid; int err; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1295,7 +1296,7 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, int hdr_size = 0; unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) return; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1343,7 +1344,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, bool dropped = false; unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1713,7 +1714,7 @@ void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv, u8 chaddr[BATADV_DHCP_CHADDR_LEN]; __be32 ip_src, yiaddr; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) return; if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr)) @@ -1743,7 +1744,7 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv, __be16 proto; u8 *hw_src; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) return; if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN))) @@ -1788,7 +1789,7 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, int hdr_size = sizeof(struct batadv_bcast_packet); unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; /* If this packet is an ARP_REQUEST and the node already has the diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index e9553db42349..14ccf7811bf6 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index a9d0346e8332..305488a74a25 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include @@ -170,7 +171,7 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv) { struct batadv_gw_node *curr_gw; - if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) + if (READ_ONCE(bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) return; curr_gw = batadv_gw_get_selected_gw_node(bat_priv); @@ -202,7 +203,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) struct batadv_neigh_ifinfo *router_ifinfo = NULL; char gw_addr[18] = { '\0' }; - if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) + if (READ_ONCE(bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) goto out; if (!bat_priv->algo_ops->gw.get_best_gw_node) @@ -210,7 +211,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) curr_gw = batadv_gw_get_selected_gw_node(bat_priv); - if (!batadv_atomic_dec_not_zero(&bat_priv->gw.reselect) && curr_gw) + if (atomic_xchg(&bat_priv->gw.reselect, 0) == 0 && curr_gw) goto out; /* if gw.reselect is set to 1 it means that a previous call to @@ -702,7 +703,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!gw_node) goto out; - switch (atomic_read(&bat_priv->gw.mode)) { + switch (READ_ONCE(bat_priv->gw.mode)) { case BATADV_GW_MODE_SERVER: /* If we are a GW then we are our best GW. We can artificially * set the tq towards ourself as the maximum value diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 315fa90f0c94..675ebf098d4e 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -7,8 +7,8 @@ #include "gateway_common.h" #include "main.h" -#include #include +#include #include #include #include @@ -25,10 +25,10 @@ void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) { struct batadv_tvlv_gateway_data gw; + enum batadv_gw_modes gw_mode; u32 down, up; - char gw_mode; - gw_mode = atomic_read(&bat_priv->gw.mode); + gw_mode = READ_ONCE(bat_priv->gw.mode); switch (gw_mode) { case BATADV_GW_MODE_OFF: @@ -36,8 +36,8 @@ void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); break; case BATADV_GW_MODE_SERVER: - down = atomic_read(&bat_priv->gw.bandwidth_down); - up = atomic_read(&bat_priv->gw.bandwidth_up); + down = READ_ONCE(bat_priv->gw.bandwidth_down); + up = READ_ONCE(bat_priv->gw.bandwidth_up); gw.bandwidth_down = htonl(down); gw.bandwidth_up = htonl(up); batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1, @@ -83,7 +83,7 @@ static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, /* restart gateway selection */ if (gateway.bandwidth_down != 0 && - atomic_read(&bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT) + READ_ONCE(bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT) batadv_gw_check_election(bat_priv, orig); } @@ -96,7 +96,7 @@ void batadv_gw_init(struct batadv_priv *bat_priv) if (bat_priv->algo_ops->gw.init_sel_class) bat_priv->algo_ops->gw.init_sel_class(bat_priv); else - atomic_set(&bat_priv->gw.sel_class, 1); + WRITE_ONCE(bat_priv->gw.sel_class, 1); batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, NULL, NULL, BATADV_TVLV_GW, 1, diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index d6732c34aeaf..bb3c31b5f259 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -7,7 +7,7 @@ #include "hard-interface.h" #include "main.h" -#include +#include #include #include #include @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -42,6 +44,15 @@ #include "send.h" #include "translation-table.h" +static const struct rhashtable_params batadv_wifi_net_devices_params = { + .key_len = sizeof(struct net_device *), + .key_offset = offsetof(struct batadv_wifi_net_device_state, netdev), + .head_offset = offsetof(struct batadv_wifi_net_device_state, l), + .automatic_shrinking = true, +}; + +static struct rhashtable batadv_wifi_net_devices; + /** * batadv_hardif_release() - release hard interface from lists and queue for * free after rcu grace period @@ -355,21 +366,28 @@ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device) } /** - * batadv_is_cfg80211_hardif() - check if the given hardif is a cfg80211 wifi - * interface + * batadv_hardif_get_wifi_flags() - retrieve wifi flags for hard_iface * @hard_iface: the device to check * - * Return: true if the net device is a cfg80211 wireless device, false - * otherwise. + * Return: batadv_hard_iface_wifi_flags flags of the device */ -bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface) +u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface) { - u32 allowed_flags = 0; + struct batadv_wifi_net_device_state *device_state; + u32 wifi_flags = 0; - allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT; - allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT; + if (!hard_iface) + return 0; - return !!(hard_iface->wifi_flags & allowed_flags); + rcu_read_lock(); + device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, + &hard_iface->net_dev, + batadv_wifi_net_devices_params); + if (device_state) + wifi_flags = READ_ONCE(device_state->wifi_flags); + rcu_read_unlock(); + + return wifi_flags; } /** @@ -380,10 +398,9 @@ bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface) */ bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface) { - if (!hard_iface) - return false; + u32 wifi_flags = batadv_hardif_get_wifi_flags(hard_iface); - return hard_iface->wifi_flags != 0; + return batadv_is_wifi(wifi_flags); } /** @@ -594,7 +611,7 @@ int batadv_hardif_min_mtu(struct net_device *mesh_iface) } rcu_read_unlock(); - if (atomic_read(&bat_priv->fragmentation) == 0) + if (READ_ONCE(bat_priv->fragmentation) == 0) goto out; /* with fragmentation enabled the maximum size of internally generated @@ -611,7 +628,7 @@ int batadv_hardif_min_mtu(struct net_device *mesh_iface) * 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); + WRITE_ONCE(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. @@ -709,6 +726,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, int max_header_len = batadv_max_header_len(); unsigned int required_mtu; unsigned int hardif_mtu; + bool fragmentation; int ret; hardif_mtu = READ_ONCE(hard_iface->net_dev->mtu); @@ -746,15 +764,14 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, batadv_info(hard_iface->mesh_iface, "Adding interface: %s\n", hard_iface->net_dev->name); - if (atomic_read(&bat_priv->fragmentation) && - hardif_mtu < required_mtu) + fragmentation = READ_ONCE(bat_priv->fragmentation); + if (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) + if (!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, @@ -889,11 +906,10 @@ batadv_hardif_add_interface(struct net_device *net_dev) kref_init(&hard_iface->refcount); hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT; - hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev); if (batadv_is_wifi_hardif(hard_iface)) hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; - atomic_set(&hard_iface->hop_penalty, 0); + WRITE_ONCE(hard_iface->hop_penalty, 0); batadv_v_hardif_init(hard_iface); @@ -941,6 +957,131 @@ static int batadv_hard_if_event_meshif(unsigned long event, return NOTIFY_DONE; } +/** + * batadv_wifi_net_device_insert() - save information about wifi net_device + * @net_dev: net_device to add to batadv_wifi_net_devices + * @wifi_flags: net_device which generated an event + * + * Return: 0 on result, negative value on error + */ +static int +batadv_wifi_net_device_insert(struct net_device *net_dev, u32 wifi_flags) +{ + struct batadv_wifi_net_device_state *device_state; + int ret; + + ASSERT_RTNL(); + + device_state = kzalloc_obj(*device_state, GFP_ATOMIC); + if (!device_state) + return -ENOMEM; + + device_state->wifi_flags = wifi_flags; + netdev_hold(net_dev, &device_state->dev_tracker, GFP_ATOMIC); + device_state->netdev = net_dev; + WRITE_ONCE(device_state->wifi_flags, wifi_flags); + + ret = rhashtable_insert_fast(&batadv_wifi_net_devices, &device_state->l, + batadv_wifi_net_devices_params); + if (ret < 0) + goto err_free; + + return 0; + +err_free: + netdev_put(device_state->netdev, &device_state->dev_tracker); + kfree(device_state); + return ret; +} + +/** + * batadv_wifi_net_device_remove() - remove information about wifi net_device + * @device_state: wifi net_device state to remove from batadv_wifi_net_device_state + */ +static void +batadv_wifi_net_device_remove(struct batadv_wifi_net_device_state *device_state) +{ + ASSERT_RTNL(); + + rhashtable_remove_fast(&batadv_wifi_net_devices, &device_state->l, + batadv_wifi_net_devices_params); + netdev_put(device_state->netdev, &device_state->dev_tracker); + kfree_rcu(device_state, rcu); +} + +/** + * batadv_wifi_net_device_update() - update wifi state of net_device + * @net_dev: net_device to update in batadv_wifi_net_devices + * + * The device will only be stored in batadv_wifi_net_devices when + * it could be identified as wifi device. If the net_device is no + * longer a wifi device, it is automatically removed from + * batadv_wifi_net_devices. + */ +static void +batadv_wifi_net_device_update(struct net_device *net_dev) +{ + struct batadv_wifi_net_device_state *device_state; + u32 wifi_flags; + + ASSERT_RTNL(); + + wifi_flags = batadv_wifi_flags_evaluate(net_dev); + device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, + &net_dev, + batadv_wifi_net_devices_params); + + if (device_state) { + if (batadv_is_wifi(wifi_flags)) + WRITE_ONCE(device_state->wifi_flags, wifi_flags); + else + batadv_wifi_net_device_remove(device_state); + } else if (batadv_is_wifi(wifi_flags)) { + batadv_wifi_net_device_insert(net_dev, wifi_flags); + } +} + +/** + * batadv_wifi_net_device_unregister() - remove wifi state of net_device + * @net_dev: net_device to remove from batadv_wifi_net_devices + */ +static void +batadv_wifi_net_device_unregister(struct net_device *net_dev) +{ + struct batadv_wifi_net_device_state *device_state; + + ASSERT_RTNL(); + + device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, + &net_dev, + batadv_wifi_net_devices_params); + if (!device_state) + return; + + batadv_wifi_net_device_remove(device_state); +} + +/** + * batadv_wifi_net_device_event() - handle network events for batadv_wifi_net_devices + * @event: enum netdev_cmd event to handle + * @net_dev: net_device to update in batadv_wifi_net_devices + */ +static void batadv_wifi_net_device_event(unsigned long event, + struct net_device *net_dev) +{ + switch (event) { + case NETDEV_REGISTER: + case NETDEV_POST_TYPE_CHANGE: + case NETDEV_CHANGEUPPER: + batadv_wifi_net_device_update(net_dev); + break; + case NETDEV_UNREGISTER: + case NETDEV_PRE_TYPE_CHANGE: + batadv_wifi_net_device_unregister(net_dev); + break; + } +} + static int batadv_hard_if_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -952,6 +1093,8 @@ static int batadv_hard_if_event(struct notifier_block *this, if (batadv_meshif_is_valid(net_dev)) return batadv_hard_if_event_meshif(event, net_dev); + batadv_wifi_net_device_event(event, net_dev); + hard_iface = batadv_hardif_get_by_netdev(net_dev); if (!hard_iface && (event == NETDEV_REGISTER || event == NETDEV_POST_TYPE_CHANGE)) @@ -995,8 +1138,9 @@ static int batadv_hard_if_event(struct notifier_block *this, if (hard_iface == primary_if) batadv_primary_if_update_addr(bat_priv, NULL); break; + case NETDEV_REGISTER: + case NETDEV_POST_TYPE_CHANGE: case NETDEV_CHANGEUPPER: - hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev); if (batadv_is_wifi_hardif(hard_iface)) hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; break; @@ -1014,3 +1158,22 @@ static int batadv_hard_if_event(struct notifier_block *this, struct notifier_block batadv_hard_if_notifier = { .notifier_call = batadv_hard_if_event, }; + +/** + * batadv_wifi_net_devices_init() - Initialize wifi devices cache + * + * Return: 0 on success, negative error code on failure + */ +int __init batadv_wifi_net_devices_init(void) +{ + return rhashtable_init(&batadv_wifi_net_devices, + &batadv_wifi_net_devices_params); +} + +/** + * batadv_wifi_net_devices_deinit() - Deinitialize wifi devices cache + */ +void batadv_wifi_net_devices_deinit(void) +{ + rhashtable_destroy(&batadv_wifi_net_devices); +} diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index 9ba8fb2bdceb..089e65c8a481 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -10,6 +10,7 @@ #include "main.h" #include +#include #include #include #include @@ -69,7 +70,7 @@ extern struct notifier_block batadv_hard_if_notifier; struct net_device *__batadv_get_real_netdev(struct net_device *net_device); struct net_device *batadv_get_real_netdev(struct net_device *net_device); -bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface); +u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface); bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface); struct batadv_hard_iface* batadv_hardif_get_by_netdev(const struct net_device *net_dev); @@ -81,6 +82,8 @@ void batadv_update_min_mtu(struct net_device *mesh_iface); void batadv_hardif_release(struct kref *ref); int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, u8 *orig_addr, u8 *orig_neigh); +int __init batadv_wifi_net_devices_init(void); +void batadv_wifi_net_devices_deinit(void); /** * batadv_hardif_put() - decrement the hard interface refcounter and possibly @@ -119,4 +122,33 @@ batadv_primary_if_get_selected(struct batadv_priv *bat_priv) return hard_iface; } +/** + * batadv_is_cfg80211() - check if the given hardif is a cfg80211 + * wifi interface + * @wifi_flags: extracted batadv_hard_iface_wifi_flagss of an net_device + * + * Return: true if the net device is a cfg80211 wireless device, false + * otherwise. + */ +static inline bool batadv_is_cfg80211(u32 wifi_flags) +{ + u32 allowed_flags = 0; + + allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT; + allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT; + + return !!(wifi_flags & allowed_flags); +} + +/** + * batadv_is_wifi() - check if flags belong to wifi interface + * @wifi_flags: extracted batadv_hard_iface_wifi_flagss of an net_device + * + * Return: true if the net device is a 802.11 wireless device, false otherwise. + */ +static inline bool batadv_is_wifi(u32 wifi_flags) +{ + return wifi_flags != 0; +} + #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ diff --git a/net/batman-adv/log.h b/net/batman-adv/log.h index 225b747a2048..a0d2b0d64b2b 100644 --- a/net/batman-adv/log.h +++ b/net/batman-adv/log.h @@ -76,7 +76,7 @@ __printf(2, 3); #define _batadv_dbg(type, bat_priv, ratelimited, fmt, arg...) \ do { \ struct batadv_priv *__batpriv = (bat_priv); \ - if (atomic_read(&__batpriv->log_level) & (type) && \ + if (READ_ONCE(__batpriv->log_level) & (type) && \ (!(ratelimited) || net_ratelimit())) \ batadv_debug_log(__batpriv, fmt, ## arg); \ } \ diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index a4d33ee0fda5..60d4f60066c8 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -104,22 +105,33 @@ static int __init batadv_init(void) batadv_tp_meter_init(); batadv_event_workqueue = create_singlethread_workqueue("bat_events"); - if (!batadv_event_workqueue) + if (!batadv_event_workqueue) { + ret = -ENOMEM; goto err_create_wq; + } + + ret = batadv_wifi_net_devices_init(); + if (ret < 0) + goto err_init_wifi; register_netdevice_notifier(&batadv_hard_if_notifier); rtnl_link_register(&batadv_link_ops); batadv_netlink_register(); pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n", - BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION); + init_utsname()->release, BATADV_COMPAT_VERSION); return 0; +err_init_wifi: + destroy_workqueue(batadv_event_workqueue); + batadv_event_workqueue = NULL; + rcu_barrier(); + err_create_wq: batadv_tt_cache_destroy(); - return -ENOMEM; + return ret; } static void __exit batadv_exit(void) @@ -133,6 +145,7 @@ static void __exit batadv_exit(void) rcu_barrier(); + batadv_wifi_net_devices_deinit(); batadv_tt_cache_destroy(); } @@ -187,31 +200,31 @@ int batadv_mesh_init(struct net_device *mesh_iface) ret = batadv_originator_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_orig; } ret = batadv_tt_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_tt; } ret = batadv_v_mesh_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_v; } ret = batadv_bla_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_bla; } ret = batadv_dat_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_dat; } @@ -219,7 +232,7 @@ int batadv_mesh_init(struct net_device *mesh_iface) batadv_mcast_init(bat_priv); atomic_set(&bat_priv->gw.reselect, 0); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_ACTIVE); return 0; @@ -233,7 +246,7 @@ int batadv_mesh_init(struct net_device *mesh_iface) batadv_originator_free(bat_priv); err_orig: batadv_purge_outstanding_packets(bat_priv, NULL); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_INACTIVE); return ret; } @@ -246,7 +259,7 @@ void batadv_mesh_free(struct net_device *mesh_iface) { struct batadv_priv *bat_priv = netdev_priv(mesh_iface); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); batadv_purge_outstanding_packets(bat_priv, NULL); batadv_tp_stop_all(bat_priv); @@ -277,7 +290,7 @@ void batadv_mesh_free(struct net_device *mesh_iface) free_percpu(bat_priv->bat_counters); bat_priv->bat_counters = NULL; - atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_INACTIVE); } /** @@ -441,7 +454,7 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, bat_priv = netdev_priv(hard_iface->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto err_free; /* discard frames on not active interfaces */ @@ -614,7 +627,7 @@ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid) */ vlan = batadv_meshif_vlan_get(bat_priv, vid); if (vlan) { - ap_isolation_enabled = atomic_read(&vlan->ap_isolation); + ap_isolation_enabled = READ_ONCE(vlan->ap_isolation); batadv_meshif_vlan_put(vlan); } @@ -684,6 +697,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR(BATADV_DRIVER_AUTHOR); MODULE_DESCRIPTION(BATADV_DRIVER_DESC); -MODULE_VERSION(BATADV_SOURCE_VERSION); MODULE_ALIAS_RTNL_LINK("batadv"); MODULE_ALIAS_GENL_FAMILY(BATADV_NL_NAME); diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index af230b017bc1..f68fc8b7239c 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -12,10 +12,6 @@ #define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced" #define BATADV_DRIVER_DEVICE "batman-adv" -#ifndef BATADV_SOURCE_VERSION -#define BATADV_SOURCE_VERSION "2025.5" -#endif - /* B.A.T.M.A.N. parameters */ #define BATADV_TQ_MAX_VALUE 255 diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index e7aa45bc6b7a..b6797654b18a 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -123,7 +125,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) eth_hw_addr_set(dev, addr->sa_data); /* only modify transtable if it has been initialized before */ - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) return 0; rcu_read_lock(); @@ -190,7 +192,7 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, int network_offset = ETH_HLEN; __be16 proto; - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto dropped; /* reset control block to avoid left overs from previous users */ @@ -255,7 +257,7 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) goto dropped; - gw_mode = atomic_read(&bat_priv->gw.mode); + gw_mode = READ_ONCE(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) { @@ -565,7 +567,7 @@ int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) vlan->vid = vid; kref_init(&vlan->refcount); - atomic_set(&vlan->ap_isolation, 0); + WRITE_ONCE(vlan->ap_isolation, 0); kref_get(&vlan->refcount); hlist_add_head_rcu(&vlan->list, &bat_priv->meshif_vlan_list); @@ -752,36 +754,36 @@ static int batadv_meshif_init_late(struct net_device *dev) if (!bat_priv->bat_counters) return -ENOMEM; - atomic_set(&bat_priv->aggregated_ogms, 1); - atomic_set(&bat_priv->bonding, 0); + WRITE_ONCE(bat_priv->aggregated_ogms, 1); + WRITE_ONCE(bat_priv->bonding, 0); #ifdef CONFIG_BATMAN_ADV_BLA - atomic_set(&bat_priv->bridge_loop_avoidance, 1); + WRITE_ONCE(bat_priv->bridge_loop_avoidance, 1); #endif #ifdef CONFIG_BATMAN_ADV_DAT - atomic_set(&bat_priv->distributed_arp_table, 1); + WRITE_ONCE(bat_priv->distributed_arp_table, 1); #endif #ifdef CONFIG_BATMAN_ADV_MCAST - atomic_set(&bat_priv->multicast_mode, 1); - atomic_set(&bat_priv->multicast_fanout, 16); + WRITE_ONCE(bat_priv->multicast_mode, 1); + WRITE_ONCE(bat_priv->multicast_fanout, 16); atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0); atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0); atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0); atomic_set(&bat_priv->mcast.num_no_mc_ptype_capa, 0); #endif - atomic_set(&bat_priv->gw.mode, BATADV_GW_MODE_OFF); - atomic_set(&bat_priv->gw.bandwidth_down, 100); - atomic_set(&bat_priv->gw.bandwidth_up, 20); - atomic_set(&bat_priv->orig_interval, 1000); - atomic_set(&bat_priv->hop_penalty, 30); + WRITE_ONCE(bat_priv->gw.mode, BATADV_GW_MODE_OFF); + WRITE_ONCE(bat_priv->gw.bandwidth_down, 100); + WRITE_ONCE(bat_priv->gw.bandwidth_up, 20); + WRITE_ONCE(bat_priv->orig_interval, 1000); + WRITE_ONCE(bat_priv->hop_penalty, 30); #ifdef CONFIG_BATMAN_ADV_DEBUG - atomic_set(&bat_priv->log_level, 0); + WRITE_ONCE(bat_priv->log_level, 0); #endif - atomic_set(&bat_priv->fragmentation, 1); - atomic_set(&bat_priv->packet_size_max, BATADV_MAX_MTU); + WRITE_ONCE(bat_priv->fragmentation, 1); + WRITE_ONCE(bat_priv->packet_size_max, BATADV_MAX_MTU); atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN); atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_INACTIVE); atomic_set(&bat_priv->bcast_seqno, 1); atomic_set(&bat_priv->tt.vn, 0); atomic_set(&bat_priv->tt.ogm_append_cnt, 0); @@ -892,7 +894,7 @@ static void batadv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strscpy(info->driver, "B.A.T.M.A.N. advanced", sizeof(info->driver)); - strscpy(info->version, BATADV_SOURCE_VERSION, sizeof(info->version)); + strscpy(info->version, init_utsname()->release, sizeof(info->version)); strscpy(info->fw_version, "N/A", sizeof(info->fw_version)); strscpy(info->bus_info, "batman", sizeof(info->bus_info)); } diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index a3d3efe22d30..3274e2ac4f4a 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -1099,7 +1099,7 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, { struct ethhdr *ethhdr = eth_hdr(skb); - if (!atomic_read(&bat_priv->multicast_mode)) + if (!READ_ONCE(bat_priv->multicast_mode)) return -EINVAL; switch (ntohs(ethhdr->h_proto)) { @@ -1204,7 +1204,7 @@ batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv, batadv_mcast_forw_push(bat_priv, skb, vid, is_routable, count)) return BATADV_FORW_MCAST; - if (count <= atomic_read(&bat_priv->multicast_fanout)) + if (count <= READ_ONCE(bat_priv->multicast_fanout)) return BATADV_FORW_UCASTS; return BATADV_FORW_BCAST; diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 78c651f634cd..e5463003a3bd 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -179,7 +181,7 @@ static int batadv_netlink_mesh_fill_ap_isolation(struct sk_buff *msg, if (!vlan) return 0; - ap_isolation = atomic_read(&vlan->ap_isolation); + ap_isolation = READ_ONCE(vlan->ap_isolation); batadv_meshif_vlan_put(vlan); return nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED, @@ -202,7 +204,7 @@ static int batadv_netlink_set_mesh_ap_isolation(struct nlattr *attr, if (!vlan) return -ENOENT; - atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); + WRITE_ONCE(vlan->ap_isolation, !!nla_get_u8(attr)); batadv_meshif_vlan_put(vlan); return 0; @@ -233,7 +235,7 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, if (!hdr) return -ENOBUFS; - if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) || + if (nla_put_string(msg, BATADV_ATTR_VERSION, init_utsname()->release) || nla_put_string(msg, BATADV_ATTR_ALGO_NAME, bat_priv->algo_ops->name) || nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, mesh_iface->ifindex) || @@ -267,7 +269,7 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, } if (nla_put_u8(msg, BATADV_ATTR_AGGREGATED_OGMS_ENABLED, - !!atomic_read(&bat_priv->aggregated_ogms))) + !!READ_ONCE(bat_priv->aggregated_ogms))) goto nla_put_failure; if (batadv_netlink_mesh_fill_ap_isolation(msg, bat_priv)) @@ -282,35 +284,35 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, goto nla_put_failure; if (nla_put_u8(msg, BATADV_ATTR_BONDING_ENABLED, - !!atomic_read(&bat_priv->bonding))) + !!READ_ONCE(bat_priv->bonding))) goto nla_put_failure; #ifdef CONFIG_BATMAN_ADV_BLA if (nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED, - !!atomic_read(&bat_priv->bridge_loop_avoidance))) + !!READ_ONCE(bat_priv->bridge_loop_avoidance))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_BLA */ #ifdef CONFIG_BATMAN_ADV_DAT if (nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED, - !!atomic_read(&bat_priv->distributed_arp_table))) + !!READ_ONCE(bat_priv->distributed_arp_table))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_DAT */ if (nla_put_u8(msg, BATADV_ATTR_FRAGMENTATION_ENABLED, - !!atomic_read(&bat_priv->fragmentation))) + !!READ_ONCE(bat_priv->fragmentation))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_DOWN, - atomic_read(&bat_priv->gw.bandwidth_down))) + READ_ONCE(bat_priv->gw.bandwidth_down))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_UP, - atomic_read(&bat_priv->gw.bandwidth_up))) + READ_ONCE(bat_priv->gw.bandwidth_up))) goto nla_put_failure; if (nla_put_u8(msg, BATADV_ATTR_GW_MODE, - atomic_read(&bat_priv->gw.mode))) + READ_ONCE(bat_priv->gw.mode))) goto nla_put_failure; if (bat_priv->algo_ops->gw.get_best_gw_node && @@ -319,32 +321,32 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, * in use does not implement the GW API */ if (nla_put_u32(msg, BATADV_ATTR_GW_SEL_CLASS, - atomic_read(&bat_priv->gw.sel_class))) + READ_ONCE(bat_priv->gw.sel_class))) goto nla_put_failure; } if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY, - atomic_read(&bat_priv->hop_penalty))) + READ_ONCE(bat_priv->hop_penalty))) goto nla_put_failure; #ifdef CONFIG_BATMAN_ADV_DEBUG if (nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL, - atomic_read(&bat_priv->log_level))) + READ_ONCE(bat_priv->log_level))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_DEBUG */ #ifdef CONFIG_BATMAN_ADV_MCAST if (nla_put_u8(msg, BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED, - !atomic_read(&bat_priv->multicast_mode))) + !READ_ONCE(bat_priv->multicast_mode))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_MULTICAST_FANOUT, - atomic_read(&bat_priv->multicast_fanout))) + READ_ONCE(bat_priv->multicast_fanout))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_MCAST */ if (nla_put_u32(msg, BATADV_ATTR_ORIG_INTERVAL, - atomic_read(&bat_priv->orig_interval))) + READ_ONCE(bat_priv->orig_interval))) goto nla_put_failure; batadv_hardif_put(primary_if); @@ -432,7 +434,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]) { attr = info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]; - atomic_set(&bat_priv->aggregated_ogms, !!nla_get_u8(attr)); + WRITE_ONCE(bat_priv->aggregated_ogms, !!nla_get_u8(attr)); } if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) { @@ -456,14 +458,14 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_BONDING_ENABLED]) { attr = info->attrs[BATADV_ATTR_BONDING_ENABLED]; - atomic_set(&bat_priv->bonding, !!nla_get_u8(attr)); + WRITE_ONCE(bat_priv->bonding, !!nla_get_u8(attr)); } #ifdef CONFIG_BATMAN_ADV_BLA if (info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]) { attr = info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]; - atomic_set(&bat_priv->bridge_loop_avoidance, + WRITE_ONCE(bat_priv->bridge_loop_avoidance, !!nla_get_u8(attr)); batadv_bla_status_update(bat_priv->mesh_iface); } @@ -473,7 +475,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]) { attr = info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]; - atomic_set(&bat_priv->distributed_arp_table, + WRITE_ONCE(bat_priv->distributed_arp_table, !!nla_get_u8(attr)); batadv_dat_status_update(bat_priv->mesh_iface); } @@ -482,7 +484,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED]) { attr = info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED]; - atomic_set(&bat_priv->fragmentation, !!nla_get_u8(attr)); + WRITE_ONCE(bat_priv->fragmentation, !!nla_get_u8(attr)); rtnl_lock(); batadv_update_min_mtu(bat_priv->mesh_iface); @@ -492,14 +494,14 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]) { attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]; - atomic_set(&bat_priv->gw.bandwidth_down, nla_get_u32(attr)); + WRITE_ONCE(bat_priv->gw.bandwidth_down, nla_get_u32(attr)); batadv_gw_tvlv_container_update(bat_priv); } if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]) { attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]; - atomic_set(&bat_priv->gw.bandwidth_up, nla_get_u32(attr)); + WRITE_ONCE(bat_priv->gw.bandwidth_up, nla_get_u32(attr)); batadv_gw_tvlv_container_update(bat_priv); } @@ -527,7 +529,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) * changing the gateway state */ batadv_gw_check_client_stop(bat_priv); - atomic_set(&bat_priv->gw.mode, gw_mode); + WRITE_ONCE(bat_priv->gw.mode, gw_mode); batadv_gw_tvlv_container_update(bat_priv); } } @@ -546,7 +548,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) sel_class = nla_get_u32(attr); if (sel_class >= 1 && sel_class <= sel_class_max) { - atomic_set(&bat_priv->gw.sel_class, sel_class); + WRITE_ONCE(bat_priv->gw.sel_class, sel_class); batadv_gw_reselect(bat_priv); } } @@ -554,14 +556,14 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_HOP_PENALTY]) { attr = info->attrs[BATADV_ATTR_HOP_PENALTY]; - atomic_set(&bat_priv->hop_penalty, nla_get_u8(attr)); + WRITE_ONCE(bat_priv->hop_penalty, nla_get_u8(attr)); } #ifdef CONFIG_BATMAN_ADV_DEBUG if (info->attrs[BATADV_ATTR_LOG_LEVEL]) { attr = info->attrs[BATADV_ATTR_LOG_LEVEL]; - atomic_set(&bat_priv->log_level, + WRITE_ONCE(bat_priv->log_level, nla_get_u32(attr) & BATADV_DBG_ALL); } #endif /* CONFIG_BATMAN_ADV_DEBUG */ @@ -570,13 +572,13 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]) { attr = info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]; - atomic_set(&bat_priv->multicast_mode, !nla_get_u8(attr)); + WRITE_ONCE(bat_priv->multicast_mode, !nla_get_u8(attr)); } if (info->attrs[BATADV_ATTR_MULTICAST_FANOUT]) { attr = info->attrs[BATADV_ATTR_MULTICAST_FANOUT]; - atomic_set(&bat_priv->multicast_fanout, nla_get_u32(attr)); + WRITE_ONCE(bat_priv->multicast_fanout, nla_get_u32(attr)); } #endif /* CONFIG_BATMAN_ADV_MCAST */ @@ -589,7 +591,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) orig_interval = min_t(u32, orig_interval, INT_MAX); orig_interval = max_t(u32, orig_interval, 2 * BATADV_JITTER); - atomic_set(&bat_priv->orig_interval, orig_interval); + WRITE_ONCE(bat_priv->orig_interval, orig_interval); } batadv_netlink_notify_mesh(bat_priv); @@ -809,16 +811,16 @@ static int batadv_netlink_hardif_fill(struct sk_buff *msg, } if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY, - atomic_read(&hard_iface->hop_penalty))) + READ_ONCE(hard_iface->hop_penalty))) goto nla_put_failure; #ifdef CONFIG_BATMAN_ADV_BATMAN_V if (nla_put_u32(msg, BATADV_ATTR_ELP_INTERVAL, - atomic_read(&hard_iface->bat_v.elp_interval))) + READ_ONCE(hard_iface->bat_v.elp_interval))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT_OVERRIDE, - atomic_read(&hard_iface->bat_v.throughput_override))) + READ_ONCE(hard_iface->bat_v.throughput_override))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_BATMAN_V */ @@ -911,7 +913,7 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, if (info->attrs[BATADV_ATTR_HOP_PENALTY]) { attr = info->attrs[BATADV_ATTR_HOP_PENALTY]; - atomic_set(&hard_iface->hop_penalty, nla_get_u8(attr)); + WRITE_ONCE(hard_iface->hop_penalty, nla_get_u8(attr)); } #ifdef CONFIG_BATMAN_ADV_BATMAN_V @@ -919,13 +921,13 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) { attr = info->attrs[BATADV_ATTR_ELP_INTERVAL]; - atomic_set(&hard_iface->bat_v.elp_interval, nla_get_u32(attr)); + WRITE_ONCE(hard_iface->bat_v.elp_interval, nla_get_u32(attr)); } if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) { attr = info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]; - atomic_set(&hard_iface->bat_v.throughput_override, + WRITE_ONCE(hard_iface->bat_v.throughput_override, nla_get_u32(attr)); } #endif /* CONFIG_BATMAN_ADV_BATMAN_V */ @@ -1020,7 +1022,7 @@ static int batadv_netlink_vlan_fill(struct sk_buff *msg, goto nla_put_failure; if (nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED, - !!atomic_read(&vlan->ap_isolation))) + !!READ_ONCE(vlan->ap_isolation))) goto nla_put_failure; genlmsg_end(msg, hdr); @@ -1108,7 +1110,7 @@ static int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) { attr = info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]; - atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); + WRITE_ONCE(vlan->ap_isolation, !!nla_get_u8(attr)); } batadv_netlink_notify_vlan(bat_priv, vlan); diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index ad4921b659d9..15d660ca7937 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -7,7 +7,6 @@ #include "originator.h" #include "main.h" -#include #include #include #include @@ -694,9 +693,12 @@ batadv_neigh_node_create(struct batadv_orig_node *orig_node, kref_get(&hard_iface->refcount); ether_addr_copy(neigh_node->addr, neigh_addr); neigh_node->if_incoming = hard_iface; - neigh_node->orig_node = orig_node; neigh_node->last_seen = jiffies; +#ifdef CONFIG_BATMAN_ADV_BATMAN_V + ACCESS_PRIVATE(neigh_node, orig_node_id) = orig_node; +#endif + /* increment unique neighbor refcount */ kref_get(&hardif_neigh->refcount); neigh_node->hardif_neigh = hardif_neigh; @@ -966,7 +968,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, orig_node->bat_priv = bat_priv; ether_addr_copy(orig_node->orig, addr); batadv_dat_init_orig_node_addr(orig_node); - atomic_set(&orig_node->last_ttvn, 0); + WRITE_ONCE(orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; orig_node->last_seen = jiffies; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 12c16f81cc51..cd4368b846ad 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -543,7 +543,7 @@ batadv_find_router(struct batadv_priv *bat_priv, /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop) * and if activated. */ - if (!(recv_if == BATADV_IF_DEFAULT && atomic_read(&bat_priv->bonding))) + if (!(recv_if == BATADV_IF_DEFAULT && READ_ONCE(bat_priv->bonding))) return router; /* bonding: loop through the list of possible routers found @@ -765,7 +765,7 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, goto out; orig_addr = orig_node->orig; - orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); + orig_ttvn = READ_ONCE(orig_node->last_ttvn); } /* update the packet header */ @@ -845,7 +845,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, if (!orig_node) return false; - curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn); + curr_ttvn = READ_ONCE(orig_node->last_ttvn); batadv_orig_node_put(orig_node); } diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 60cd67ec9cea..5f9da3606a8f 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -185,7 +185,7 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, /* Check if the skb is too large to send in one piece and fragment * it if needed. */ - if (atomic_read(&bat_priv->fragmentation) && + if (READ_ONCE(bat_priv->fragmentation) && skb->len > neigh_node->if_incoming->net_dev->mtu) { /* Fragment and send packet. */ ret = batadv_frag_send_packet(skb, orig_node, neigh_node); @@ -222,7 +222,7 @@ batadv_send_skb_push_fill_unicast(struct sk_buff *skb, int hdr_size, struct batadv_orig_node *orig_node) { struct batadv_unicast_packet *unicast_packet; - u8 ttvn = (u8)atomic_read(&orig_node->last_ttvn); + u8 ttvn = READ_ONCE(orig_node->last_ttvn); if (batadv_skb_head_push(skb, hdr_size) < 0) return false; @@ -1047,7 +1047,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) delayed_work); bat_priv = netdev_priv(forw_packet->if_incoming->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { dropped = true; goto out; } diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c index 0fc4ca78e84e..aefe757277b2 100644 --- a/net/batman-adv/tp_meter.c +++ b/net/batman-adv/tp_meter.c @@ -999,7 +999,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, /* look for an already existing test towards this node */ spin_lock_bh(&bat_priv->tp_list_lock); - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) { + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) { spin_unlock_bh(&bat_priv->tp_list_lock); batadv_tp_batctl_error_notify(BATADV_TP_REASON_DST_UNREACHABLE, dst, bat_priv, session_cookie); @@ -1387,7 +1387,7 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, struct batadv_tp_vars *tp_vars = NULL; spin_lock_bh(&bat_priv->tp_list_lock); - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto out_unlock; tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, @@ -1518,7 +1518,7 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb) { struct batadv_icmp_tp_packet *icmp; - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto out; icmp = (struct batadv_icmp_tp_packet *)skb->data; diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 9f6e67771ffa..5e134d08a80f 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -648,7 +649,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr, /* Ignore the client if we cannot send it in a full table response. */ table_size = batadv_tt_local_table_transmit_size(bat_priv); table_size += batadv_tt_len(1); - packet_size_max = atomic_read(&bat_priv->packet_size_max); + packet_size_max = READ_ONCE(bat_priv->packet_size_max); if (table_size > packet_size_max) { net_ratelimited_function(batadv_info, mesh_iface, "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n", @@ -798,10 +799,10 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, { u16 num_vlan = 0; u16 tvlv_len = 0; - unsigned int change_offset; struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_orig_node_vlan *vlan; u16 total_entries = 0; + size_t change_offset; u8 *tt_change_ptr; int vlan_entries; u16 sum_entries; @@ -825,14 +826,11 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, if (*tt_len < 0) *tt_len = batadv_tt_len(total_entries); - if (change_offset > U16_MAX || *tt_len > U16_MAX - change_offset) { + if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) { *tt_len = 0; goto out; } - tvlv_len = *tt_len; - tvlv_len += change_offset; - *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); if (!*tt_data) { *tt_len = 0; @@ -840,7 +838,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, } (*tt_data)->flags = BATADV_NO_FLAGS; - (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); + (*tt_data)->ttvn = READ_ONCE(orig_node->last_ttvn); (*tt_data)->num_vlan = htons(num_vlan); tt_vlan = (*tt_data)->vlan_data; @@ -1821,7 +1819,7 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, if (!hdr) return -ENOBUFS; - last_ttvn = atomic_read(&orig->orig_node->last_ttvn); + last_ttvn = READ_ONCE(orig->orig_node->last_ttvn); if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) || nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, @@ -3012,7 +3010,7 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, if (!res_dst_orig_node) goto out; - orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn); + orig_ttvn = READ_ONCE(req_dst_orig_node->last_ttvn); req_ttvn = tt_data->ttvn; /* this node doesn't have the requested data */ @@ -3068,7 +3066,7 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, /* Don't send the response, if larger than fragmented packet. */ tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; - if (tt_len > atomic_read(&bat_priv->packet_size_max)) { + if (tt_len > READ_ONCE(bat_priv->packet_size_max)) { net_ratelimited_function(batadv_info, bat_priv->mesh_iface, "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n", res_dst_orig_node->orig); @@ -3299,7 +3297,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, orig_node->tt_buff = NULL; spin_unlock_bh(&orig_node->tt_buff_lock); - atomic_set(&orig_node->last_ttvn, ttvn); + WRITE_ONCE(orig_node->last_ttvn, ttvn); out: batadv_orig_node_put(orig_node); @@ -3315,7 +3313,7 @@ static void batadv_tt_update_changes(struct batadv_priv *bat_priv, batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, batadv_tt_len(tt_num_changes)); - atomic_set(&orig_node->last_ttvn, ttvn); + WRITE_ONCE(orig_node->last_ttvn, ttvn); } /** @@ -3729,7 +3727,7 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, if (!vlan) return false; - if (!atomic_read(&vlan->ap_isolation)) + if (!READ_ONCE(vlan->ap_isolation)) goto vlan_put; tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); @@ -3768,7 +3766,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_change *tt_change, u16 tt_num_changes, u8 ttvn) { - u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); + u8 orig_ttvn = READ_ONCE(orig_node->last_ttvn); struct batadv_tvlv_tt_vlan_data *tt_vlan; bool full_table = true; bool has_tt_init; @@ -3910,7 +3908,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, BATADV_TT_CLIENT_TEMP, - atomic_read(&orig_node->last_ttvn))) + READ_ONCE(orig_node->last_ttvn))) return false; batadv_dbg(BATADV_DBG_TT, bat_priv, @@ -3931,7 +3929,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, void batadv_tt_local_resize_to_mtu(struct net_device *mesh_iface) { struct batadv_priv *bat_priv = netdev_priv(mesh_iface); - int packet_size_max = atomic_read(&bat_priv->packet_size_max); + int packet_size_max = READ_ONCE(bat_priv->packet_size_max); int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; bool reduced = false; @@ -4124,7 +4122,7 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, - atomic_read(&orig_node->last_ttvn) + 1); + READ_ONCE(orig_node->last_ttvn) + 1); out: batadv_orig_node_put(orig_node); diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c index cc6ac580c620..cd75daea478c 100644 --- a/net/batman-adv/tvlv.c +++ b/net/batman-adv/tvlv.c @@ -6,6 +6,7 @@ #include "main.h" +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -266,32 +268,48 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, /** * batadv_tvlv_realloc_packet_buff() - reallocate packet buffer to accommodate * requested packet size - * @packet_buff: packet buffer - * @packet_buff_len: packet buffer size - * @min_packet_len: requested packet minimum size + * @ogm_buff: ogm packet buffer * @additional_packet_len: requested additional packet size on top of minimum * size * * Return: true of the packet buffer could be changed to the requested size, * false otherwise. */ -static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, - int *packet_buff_len, - int min_packet_len, - int additional_packet_len) +static bool batadv_tvlv_realloc_packet_buff(struct batadv_ogm_buf *ogm_buff, + size_t additional_packet_len) { unsigned char *new_buff; + size_t newcapacity; + size_t newlen; - new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC); + newlen = ogm_buff->header_length + additional_packet_len; + newcapacity = roundup_pow_of_two(newlen); + + /* nothing to reallocate */ + if (newcapacity == ogm_buff->capacity) { + ogm_buff->len = newlen; + return true; + } + + new_buff = kmalloc(newcapacity, GFP_ATOMIC); /* keep old buffer if kmalloc should fail */ - if (!new_buff) - return false; + if (!new_buff) { + /* continue to use oversize buffer if new data fits */ + if (newlen <= ogm_buff->capacity) { + ogm_buff->len = newlen; + return true; + } - memcpy(new_buff, *packet_buff, min_packet_len); - kfree(*packet_buff); - *packet_buff = new_buff; - *packet_buff_len = min_packet_len + additional_packet_len; + return false; + } + + memcpy(new_buff, ogm_buff->buf, ogm_buff->header_length); + kfree(ogm_buff->buf); + + ogm_buff->buf = new_buff; + ogm_buff->len = newlen; + ogm_buff->capacity = newcapacity; return true; } @@ -300,10 +318,7 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, * batadv_tvlv_container_ogm_append() - append tvlv container content to given * OGM packet buffer * @bat_priv: the bat priv with all the mesh interface information - * @packet_buff: ogm packet buffer - * @packet_buff_len: ogm packet buffer size including ogm header and tvlv - * content - * @packet_min_len: ogm header size to be preserved for the OGM itself + * @ogm_buff: ogm packet buffer * * The ogm packet might be enlarged or shrunk depending on the current size * and the size of the to-be-appended tvlv containers. @@ -312,8 +327,7 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, * if operation failed */ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, int packet_min_len) + struct batadv_ogm_buf *ogm_buff) { struct batadv_tvlv_container *tvlv; struct batadv_tvlv_hdr *tvlv_hdr; @@ -329,8 +343,7 @@ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, goto end; } - ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len, - packet_min_len, tvlv_value_len); + ret = batadv_tvlv_realloc_packet_buff(ogm_buff, tvlv_value_len); if (!ret) { tvlv_len_ret = -ENOMEM; goto end; @@ -341,7 +354,7 @@ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, if (!tvlv_value_len) goto end; - tvlv_value = (*packet_buff) + packet_min_len; + tvlv_value = (u8 *)ogm_buff->buf + ogm_buff->header_length; hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { tvlv_hdr = tvlv_value; diff --git a/net/batman-adv/tvlv.h b/net/batman-adv/tvlv.h index f96f6b3f44a0..fc9783850443 100644 --- a/net/batman-adv/tvlv.h +++ b/net/batman-adv/tvlv.h @@ -17,8 +17,7 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, u8 type, u8 version, void *tvlv_value, u16 tvlv_value_len); int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, int packet_min_len); + struct batadv_ogm_buf *ogm_buff); void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_orig_node *orig_node); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index a01ee46d97f3..19c7316889b6 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -21,6 +21,7 @@ #include #include #include +#include #include /* for linux/wait.h */ #include #include @@ -70,15 +71,29 @@ enum batadv_dhcp_recipient { */ #define BATADV_TT_SYNC_MASK 0x00F0 +/** + * struct batadv_ogm_buf - Buffer to construct an OGM with TVLV + */ +struct batadv_ogm_buf { + /** @buf: buffer holding the OGM packet */ + void *buf; + + /** @len: length of the OGM packet buffer data */ + size_t len; + + /** @capacity: size of allocated buf */ + size_t capacity; + + /** @header_length: fixed size header length (must be <= len) */ + size_t header_length; +}; + /** * struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data */ struct batadv_hard_iface_bat_iv { /** @ogm_buff: buffer holding the OGM packet */ - unsigned char *ogm_buff; - - /** @ogm_buff_len: length of the OGM packet buffer */ - int ogm_buff_len; + struct batadv_ogm_buf ogm_buff; /** @ogm_seqno: OGM sequence number - used to identify each OGM */ atomic_t ogm_seqno; @@ -86,7 +101,7 @@ struct batadv_hard_iface_bat_iv { /** @reschedule_work: recover OGM schedule after schedule error */ struct delayed_work reschedule_work; - /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */ + /** @ogm_buff_mutex: lock protecting ogm_buff */ struct mutex ogm_buff_mutex; }; @@ -113,7 +128,7 @@ enum batadv_v_hard_iface_flags { */ struct batadv_hard_iface_bat_v { /** @elp_interval: time interval between two ELP transmissions */ - atomic_t elp_interval; + u32 elp_interval; /** @elp_seqno: current ELP sequence number */ atomic_t elp_seqno; @@ -137,7 +152,7 @@ struct batadv_hard_iface_bat_v { * @throughput_override: throughput override to disable link * auto-detection */ - atomic_t throughput_override; + u32 throughput_override; /** @flags: interface specific flags */ u8 flags; @@ -166,6 +181,29 @@ enum batadv_hard_iface_wifi_flags { BATADV_HARDIF_WIFI_CFG80211_INDIRECT = BIT(3), }; +/** + * struct batadv_wifi_net_device_state - cache of wifi information of net_devices + */ +struct batadv_wifi_net_device_state { + /** @l: anchor in rhashtable */ + struct rhash_head l; + + /** @netdev: pointer to the net_device */ + struct net_device *netdev; + + /** @dev_tracker: device tracker for @netdev */ + netdevice_tracker dev_tracker; + + /** + * @wifi_flags: flags whether this is (directly or indirectly) a wifi + * interface + */ + u32 wifi_flags; + + /** @rcu: struct used for freeing in an RCU-safe manner */ + struct rcu_head rcu; +}; + /** * struct batadv_hard_iface - network device known to batman-adv */ @@ -181,12 +219,6 @@ struct batadv_hard_iface { */ u8 num_bcasts; - /** - * @wifi_flags: flags whether this is (directly or indirectly) a wifi - * interface - */ - u32 wifi_flags; - /** @net_dev: pointer to the net_device */ struct net_device *net_dev; @@ -218,7 +250,7 @@ struct batadv_hard_iface { * @hop_penalty: penalty which will be applied to the tq-field * of an OGM received via this interface */ - atomic_t hop_penalty; + u8 hop_penalty; /** @bat_iv: per hard-interface B.A.T.M.A.N. IV data */ struct batadv_hard_iface_bat_iv bat_iv; @@ -446,7 +478,7 @@ struct batadv_orig_node { unsigned long capa_initialized; /** @last_ttvn: last seen translation table version number */ - atomic_t last_ttvn; + u8 last_ttvn; /** @tt_buff: last tt changeset this node received from the orig node */ unsigned char *tt_buff; @@ -631,8 +663,15 @@ struct batadv_neigh_node { /** @list: list node for &batadv_orig_node.neigh_list */ struct hlist_node list; - /** @orig_node: pointer to corresponding orig_node */ - struct batadv_orig_node *orig_node; +#ifdef CONFIG_BATMAN_ADV_BATMAN_V + /** + * @orig_node_id: pointer to corresponding orig_node. It must only be used + * to identify the node but must NEVER be dereferenced. The reference counter + * was not increased when this was assigned because it would otherwise create + * a reference cycle. + */ + struct batadv_orig_node *__private orig_node_id; +#endif /** @addr: the MAC address of the neighboring interface */ u8 addr[ETH_ALEN]; @@ -1101,21 +1140,21 @@ struct batadv_priv_gw { /** * @mode: gateway operation: off, client or server (see batadv_gw_modes) */ - atomic_t mode; + enum batadv_gw_modes mode; /** @sel_class: gateway selection class (applies if gw_mode client) */ - atomic_t sel_class; + u32 sel_class; /** * @bandwidth_down: advertised uplink download bandwidth (if gw_mode * server) */ - atomic_t bandwidth_down; + u32 bandwidth_down; /** * @bandwidth_up: advertised uplink upload bandwidth (if gw_mode server) */ - atomic_t bandwidth_up; + u32 bandwidth_up; /** @reselect: bool indicating a gateway re-selection is in progress */ atomic_t reselect; @@ -1441,7 +1480,7 @@ struct batadv_meshif_vlan { unsigned short vid; /** @ap_isolation: AP isolation state */ - atomic_t ap_isolation; /* boolean */ + u8 ap_isolation; /* boolean */ /** @tt: TT private attributes (VLAN specific) */ struct batadv_vlan_tt tt; @@ -1463,15 +1502,12 @@ struct batadv_meshif_vlan { */ struct batadv_priv_bat_v { /** @ogm_buff: buffer holding the OGM packet */ - unsigned char *ogm_buff; - - /** @ogm_buff_len: length of the OGM packet buffer */ - int ogm_buff_len; + struct batadv_ogm_buf ogm_buff; /** @ogm_seqno: OGM sequence number - used to identify each OGM */ atomic_t ogm_seqno; - /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */ + /** @ogm_buff_mutex: lock protecting ogm_buff */ struct mutex ogm_buff_mutex; /** @ogm_wq: workqueue used to schedule OGM transmissions */ @@ -1486,7 +1522,7 @@ struct batadv_priv { * @mesh_state: current status of the mesh * (inactive/active/deactivating) */ - atomic_t mesh_state; + enum batadv_mesh_state mesh_state; /** @mesh_iface: net device which holds this struct as private data */ struct net_device *mesh_iface; @@ -1506,36 +1542,23 @@ struct batadv_priv { /** * @aggregated_ogms: bool indicating whether OGM aggregation is enabled */ - atomic_t aggregated_ogms; + u8 aggregated_ogms; /** @bonding: bool indicating whether traffic bonding is enabled */ - atomic_t bonding; + u8 bonding; /** * @fragmentation: bool indicating whether traffic fragmentation is * enabled */ - atomic_t fragmentation; - - /** - * @packet_size_max: max packet size that can be transmitted via - * multiple fragmented skbs or a single frame if fragmentation is - * disabled - */ - atomic_t packet_size_max; - - /** - * @frag_seqno: incremental counter to identify chains of egress - * fragments - */ - atomic_t frag_seqno; + u8 fragmentation; #ifdef CONFIG_BATMAN_ADV_BLA /** * @bridge_loop_avoidance: bool indicating whether bridge loop * avoidance is enabled */ - atomic_t bridge_loop_avoidance; + u8 bridge_loop_avoidance; #endif #ifdef CONFIG_BATMAN_ADV_DAT @@ -1543,7 +1566,7 @@ struct batadv_priv { * @distributed_arp_table: bool indicating whether distributed ARP table * is enabled */ - atomic_t distributed_arp_table; + u8 distributed_arp_table; #endif #ifdef CONFIG_BATMAN_ADV_MCAST @@ -1551,27 +1574,40 @@ struct batadv_priv { * @multicast_mode: Enable or disable multicast optimizations on this * node's sender/originating side */ - atomic_t multicast_mode; + u8 multicast_mode; /** * @multicast_fanout: Maximum number of packet copies to generate for a * multicast-to-unicast conversion */ - atomic_t multicast_fanout; + u32 multicast_fanout; #endif + /** + * @packet_size_max: max packet size that can be transmitted via + * multiple fragmented skbs or a single frame if fragmentation is + * disabled + */ + int packet_size_max; + + /** + * @frag_seqno: incremental counter to identify chains of egress + * fragments + */ + atomic_t frag_seqno; + /** @orig_interval: OGM broadcast interval in milliseconds */ - atomic_t orig_interval; + u32 orig_interval; /** * @hop_penalty: penalty which will be applied to an OGM's tq-field on * every hop */ - atomic_t hop_penalty; + u8 hop_penalty; #ifdef CONFIG_BATMAN_ADV_DEBUG /** @log_level: configured log level (see batadv_dbg_level) */ - atomic_t log_level; + u32 log_level; #endif /** diff --git a/net/batman-adv/version.c b/net/batman-adv/version.c new file mode 100644 index 000000000000..2b8006fe85b5 --- /dev/null +++ b/net/batman-adv/version.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +/* WARNING userspace tools like batctl were relying on + * /sys/module/batman_adv/version to check if the module was loaded. If it + * isn't present, they usually error out before finishing setup of the batadv + * interface. It should be kept until it is unlikely that there are active + * installations of these "broken" versions of these tools with recent kernels. + */ +MODULE_VERSION(UTS_RELEASE);