diff --git a/include/uapi/linux/batadv_packet.h b/include/uapi/linux/batadv_packet.h index 1241285b866c..32436560ecc8 100644 --- a/include/uapi/linux/batadv_packet.h +++ b/include/uapi/linux/batadv_packet.h @@ -192,13 +192,19 @@ enum batadv_tvlv_type { }; #pragma pack(2) -/* the destination hardware field in the ARP frame is used to - * transport the claim type and the group id +/** + * struct batadv_bla_claim_dst - layout of the destination MAC of a BLA claim + * frame + * @magic: fixed magic prefix (FF:43:05) identifying claim frames + * @type: claim frame type, see &enum batadv_bla_claimframe + * @group: group identifier of the announcing backbone gateway + * + * used in the destination hardware field of the ARP frame */ struct batadv_bla_claim_dst { - __u8 magic[3]; /* FF:43:05 */ - __u8 type; /* bla_claimframe */ - __be16 group; /* group id */ + __u8 magic[3]; + __u8 type; + __be16 group; }; /** diff --git a/net/batman-adv/bat_algo.c b/net/batman-adv/bat_algo.c index 49e5861b58ec..93cd77680e64 100644 --- a/net/batman-adv/bat_algo.c +++ b/net/batman-adv/bat_algo.c @@ -42,7 +42,8 @@ void batadv_algo_init(void) */ struct batadv_algo_ops *batadv_algo_get(const char *name) { - struct batadv_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; + struct batadv_algo_ops *bat_algo_ops = NULL; + struct batadv_algo_ops *bat_algo_ops_tmp; hlist_for_each_entry(bat_algo_ops_tmp, &batadv_algo_list, list) { if (strcmp(bat_algo_ops_tmp->name, name) != 0) @@ -116,12 +117,23 @@ int batadv_algo_select(struct batadv_priv *bat_priv, const char *name) return 0; } +/** + * batadv_param_set_ra() - Validate and store routing_algo module parameter + * @val: new value for the routing_algo module parameter + * @kp: kernel parameter description used to store the value + * + * Check that the requested algorithm is known to batman-adv and then store + * the name as the new default routing algorithm. + * + * Return: 0 on success or negative error number in case of failure + */ static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) { struct batadv_algo_ops *bat_algo_ops; char *algo_name = (char *)val; - size_t name_len = strlen(algo_name); + size_t name_len; + name_len = strlen(algo_name); if (name_len > 0 && algo_name[name_len - 1] == '\n') algo_name[name_len - 1] = '\0'; diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 22622283f59b..53fbdbbe8f4f 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -106,8 +106,8 @@ static u8 batadv_ring_buffer_avg(const u8 lq_recv[]) { const u8 *ptr; u16 count = 0; - u16 i = 0; u16 sum = 0; + u16 i = 0; ptr = lq_recv; @@ -171,6 +171,14 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) return NULL; } +/** + * batadv_iv_ogm_neigh_new() - retrieve or create a B.A.T.M.A.N. IV neighbour + * @hard_iface: the interface where the neighbour is connected to + * @neigh_addr: the mac address of the neighbour + * @orig_node: originator object representing the neighbour + * + * Return: pointer to the neigh_node or NULL in case of failure + */ static struct batadv_neigh_node * batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, const u8 *neigh_addr, @@ -183,6 +191,14 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, return neigh_node; } +/** + * batadv_iv_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. IV + * @hard_iface: the interface to prepare + * + * Allocate and prepare the per-interface OGM buffer + * + * Return: 0 on success or negative error number in case of failure + */ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) { struct batadv_ogm_packet *batadv_ogm_packet; @@ -220,6 +236,14 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) return 0; } +/** + * batadv_iv_ogm_iface_disable() - release B.A.T.M.A.N. IV resources of an + * interface + * @hard_iface: the interface which is shutting down + * + * Free the per-interface OGM buffer and cancel a possibly pending OGM + * rescheduling work. + */ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface) { mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); @@ -233,6 +257,11 @@ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface) disable_delayed_work_sync(&hard_iface->bat_iv.reschedule_work); } +/** + * batadv_iv_ogm_iface_update_mac() - update the originator MAC stored in the + * per-interface OGM buffer + * @hard_iface: the interface for which the OGM buffer should be updated + */ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface) { struct batadv_ogm_packet *batadv_ogm_packet; @@ -254,6 +283,14 @@ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface) mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); } +/** + * batadv_iv_ogm_primary_iface_set() - apply primary interface state to + * a batadv_hard_iface + * @hard_iface: interface which just became the primary + * + * The primary interface uses the full TTL for its own OGMs, so adjust the TTL + * stored in the OGM template buffer accordingly. + */ static void batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface) { @@ -273,7 +310,17 @@ batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface) mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); } -/* when do we schedule our own ogm to be sent */ +/** + * batadv_iv_ogm_emit_send_time() - calculate the jiffies when an own OGM + * should be sent next + * @bat_priv: the bat priv with all the mesh interface information + * + * The next emission point is the configured orig_interval randomised by + * +/- BATADV_JITTER milliseconds to reduce chance of potential collisions + * between neighbours. + * + * Return: jiffies value when the next OGM should be transmitted + */ static unsigned long batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv) { @@ -285,13 +332,24 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv) return jiffies + msecs_to_jiffies(msecs); } -/* when do we schedule a ogm packet to be sent */ +/** + * batadv_iv_ogm_fwd_send_time() - calculate the jiffies when a forwarded OGM + * should be sent next + * + * Return: jiffies value at which a forwarded OGM should be transmitted + */ static unsigned long batadv_iv_ogm_fwd_send_time(void) { return jiffies + msecs_to_jiffies(get_random_u32_below(BATADV_JITTER / 2)); } -/* apply hop penalty for a normal link */ +/** + * batadv_hop_penalty() - apply the configured hop penalty to a TQ value + * @tq: input TQ value to be reduced + * @bat_priv: the bat priv with all the mesh interface information + * + * Return: the TQ value after the hop penalty has been applied + */ static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv) { int hop_penalty = READ_ONCE(bat_priv->hop_penalty); @@ -337,17 +395,25 @@ batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len, return next_buff_pos <= packet_len; } -/* send a batman ogm to a given interface */ +/** + * batadv_iv_ogm_send_to_if() - send a batman OGM to a given interface + * @forw_packet: forward packet containing the OGM(s) to be transmitted + * @hard_iface: interface to send the OGM out on + * + * Update the direct link flags of each aggregated OGM for the outgoing + * interface, log the transmission and finally hand a clone of the skb to the + * lower layer for broadcast. + */ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, struct batadv_hard_iface *hard_iface) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); - const char *fwd_str; - u8 packet_num; - int buff_pos; struct batadv_ogm_packet *batadv_ogm_packet; + const char *fwd_str; struct sk_buff *skb; u8 *packet_pos; + u8 packet_num; + int buff_pos; if (hard_iface->if_status != BATADV_IF_ACTIVE) return; @@ -401,7 +467,13 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, } } -/* send a batman ogm packet */ +/** + * batadv_iv_ogm_emit() - emit an (aggregated) OGM packet + * @forw_packet: forward packet which should be emitted + * + * The @forw_packet will be emitted but not consumed. When the interface is + * no longer active, the transmission will be skipped. + */ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) { if (!forw_packet->if_incoming) { @@ -442,13 +514,13 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet, const struct batadv_hard_iface *if_outgoing, const struct batadv_forw_packet *forw_packet) { - struct batadv_ogm_packet *batadv_ogm_packet; unsigned int aggregated_bytes = forw_packet->packet_len + packet_len; + struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_hard_iface *primary_if = NULL; u8 packet_num = forw_packet->num_packets; - bool res = false; unsigned long aggregation_end_time; unsigned int max_bytes; + bool res = false; batadv_ogm_packet = (struct batadv_ogm_packet *)forw_packet->skb->data; aggregation_end_time = send_time; @@ -555,10 +627,10 @@ static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, { struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); struct batadv_forw_packet *forw_packet_aggr; - struct sk_buff *skb; unsigned char *skb_buff; unsigned int skb_size; - atomic_t *queue_left = own_packet ? NULL : &bat_priv->batman_queue_left; + atomic_t *queue_left; + struct sk_buff *skb; if (READ_ONCE(bat_priv->aggregated_ogms)) skb_size = max_t(unsigned int, BATADV_MAX_AGGREGATION_BYTES, @@ -572,6 +644,7 @@ static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, if (!skb) return false; + queue_left = own_packet ? NULL : &bat_priv->batman_queue_left; forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing, queue_left, bat_priv, skb); if (!forw_packet_aggr) { @@ -603,7 +676,14 @@ static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, return true; } -/* aggregate a new packet into the existing ogm packet */ +/** + * batadv_iv_ogm_aggregate() - append an OGM to an existing aggregated forward + * packet + * @forw_packet_aggr: aggregated forward packet to extend + * @packet_buff: pointer to the OGM to append + * @packet_len: length of the OGM to append + * @direct_link: true if @packet_buff was received as a direct link OGM + */ static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr, const unsigned char *packet_buff, int packet_len, bool direct_link) @@ -644,9 +724,9 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, struct batadv_forw_packet *forw_packet_aggr = NULL; struct batadv_forw_packet *forw_packet_pos = NULL; struct batadv_ogm_packet *batadv_ogm_packet; - bool direct_link; unsigned long max_aggregation_jiffies; bool aggregated_ogms; + bool direct_link; batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff; direct_link = !!(batadv_ogm_packet->flags & BATADV_DIRECTLINK); @@ -699,6 +779,21 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, } } +/** + * batadv_iv_ogm_forward() - rebroadcast a received OGM + * @orig_node: originator that sent the OGM + * @ethhdr: ethernet header of the OGM packet + * @batadv_ogm_packet: OGM packet to be forwarded + * @is_single_hop_neigh: true if the OGM was received via a one-hop neighbour + * @is_from_best_next_hop: true if the sender is the currently selected best + * next hop towards @orig_node + * @if_incoming: interface where the packet was received + * @if_outgoing: interface for which the retransmission should be considered + * + * Decrement the TTL, apply the hop penalty and queue the OGM for + * retransmission. OGMs that do not arrive over the best next hop are only + * forwarded for link-quality measurement reasons (and marked accordingly). + */ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, const struct ethhdr *ethhdr, struct batadv_ogm_packet *batadv_ogm_packet, @@ -762,9 +857,9 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); struct batadv_hashtable *hash = bat_priv->orig_hash; - struct hlist_head *head; - struct batadv_orig_node *orig_node; struct batadv_orig_ifinfo *orig_ifinfo; + struct batadv_orig_node *orig_node; + struct hlist_head *head; unsigned long *word; u32 i; u8 *w; @@ -802,13 +897,14 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); 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; - struct list_head *iter; - u32 seqno; - u16 tvlv_len = 0; + struct batadv_hard_iface *tmp_hard_iface; + struct batadv_hard_iface *primary_if; unsigned long send_time; bool reschedule = false; + struct list_head *iter; + u16 tvlv_len = 0; bool scheduled; + u32 seqno; int ret; lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex); @@ -899,6 +995,13 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) batadv_hardif_put(primary_if); } +/** + * batadv_iv_ogm_schedule() - schedule the next OGM transmission on an + * interface + * @hard_iface: interface for which the next OGM should be scheduled + * + * Take the OGM buffer mutex and prepare the next OGM for transmission. + */ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) { if (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED) @@ -909,6 +1012,13 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); } +/** + * batadv_iv_ogm_reschedule() - work-queue helper to rerun batadv_iv_ogm_schedule() + * @work: work item embedded in the hard interface + * + * Invoked from the per-interface reschedule_work delayed work when the + * previous attempt to enqueue the own OGM failed. + */ static void batadv_iv_ogm_reschedule(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); @@ -996,13 +1106,14 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_hard_iface *if_outgoing, enum batadv_dup_status dup_status) { - struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL; - struct batadv_neigh_node *neigh_node = NULL; + struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; struct batadv_neigh_node *tmp_neigh_node = NULL; + struct batadv_neigh_node *neigh_node = NULL; struct batadv_neigh_node *router = NULL; - u8 sum_orig, sum_neigh; u8 *neigh_addr; + u8 sum_neigh; + u8 sum_orig; u8 tq_avg; batadv_dbg(BATADV_DBG_BATMAN, bat_priv, @@ -1133,15 +1244,21 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); - struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node; - struct batadv_neigh_ifinfo *neigh_ifinfo; - u8 total_count; - u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int tq_iface_hop_penalty = BATADV_TQ_MAX_VALUE; - unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; - unsigned int tq_asym_penalty, inv_asym_penalty; + struct batadv_neigh_node *neigh_node = NULL; + struct batadv_neigh_node *tmp_neigh_node; + struct batadv_neigh_ifinfo *neigh_ifinfo; + unsigned int neigh_rq_inv_cube; + unsigned int neigh_rq_max_cube; + unsigned int inv_asym_penalty; + unsigned int tq_asym_penalty; unsigned int combined_tq; + u8 neigh_rq_count; + u8 orig_eq_count; bool ret = false; + u8 neigh_rq_inv; + u8 total_count; + u8 tq_own; /* find corresponding one hop neighbor */ rcu_read_lock(); @@ -1274,19 +1391,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); - struct batadv_orig_node *orig_node; struct batadv_orig_ifinfo *orig_ifinfo = NULL; - struct batadv_neigh_node *neigh_node; - struct batadv_neigh_ifinfo *neigh_ifinfo; - bool is_dup; - s32 seq_diff; - bool need_update = false; - int set_mark; - enum batadv_dup_status ret = BATADV_NO_DUP; u32 seqno = ntohl(batadv_ogm_packet->seqno); - u8 *neigh_addr; - u8 packet_count; + enum batadv_dup_status ret = BATADV_NO_DUP; + struct batadv_neigh_ifinfo *neigh_ifinfo; + struct batadv_neigh_node *neigh_node; + struct batadv_orig_node *orig_node; + bool need_update = false; unsigned long *bitmap; + u8 packet_count; + u8 *neigh_addr; + s32 seq_diff; + int set_mark; + bool is_dup; orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig); if (!orig_node) @@ -1403,21 +1520,22 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, { struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); struct batadv_hardif_neigh_node *hardif_neigh = NULL; - struct batadv_neigh_node *router = NULL; - struct batadv_neigh_node *router_router = NULL; - struct batadv_orig_node *orig_neigh_node; - struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *orig_neigh_router = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router_router = NULL; + struct batadv_orig_node *orig_neigh_node; + struct batadv_neigh_node *router = NULL; + struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_ogm_packet *ogm_packet; - enum batadv_dup_status dup_status; bool is_from_best_next_hop = false; + enum batadv_dup_status dup_status; bool is_single_hop_neigh = false; - bool sameseq, similar_ttl; struct sk_buff *skb_priv; struct ethhdr *ethhdr; - u8 *prev_sender; + bool similar_ttl; bool is_bidirect; + u8 *prev_sender; + bool sameseq; /* create a private copy of the skb, as some functions change tq value * and/or flags. @@ -1639,16 +1757,17 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, struct batadv_hard_iface *if_incoming) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); - struct batadv_orig_node *orig_neigh_node, *orig_node; + struct batadv_orig_node *orig_neigh_node; struct batadv_hard_iface *hard_iface; struct batadv_ogm_packet *ogm_packet; - u32 if_incoming_seqno; - bool has_directlink_flag; - struct ethhdr *ethhdr; + struct batadv_orig_node *orig_node; bool is_my_oldorig = false; + bool has_directlink_flag; bool is_my_addr = false; bool is_my_orig = false; struct list_head *iter; + u32 if_incoming_seqno; + struct ethhdr *ethhdr; ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset); ethhdr = eth_hdr(skb); @@ -1765,10 +1884,18 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, batadv_orig_node_put(orig_node); } +/** + * batadv_iv_send_outstanding_bat_ogm_packet() - work-queue helper to emit a + * queued forward packet + * @work: work item embedded in the forward packet + * + * Emit the queued OGM forward packet and, for own primary-interface packets, + * schedule the next periodic OGM. The forward packet is freed afterwards. + */ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) { - struct delayed_work *delayed_work; struct batadv_forw_packet *forw_packet; + struct delayed_work *delayed_work; struct batadv_priv *bat_priv; bool dropped = false; @@ -1803,15 +1930,26 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) batadv_forw_packet_free(forw_packet, dropped); } +/** + * batadv_iv_ogm_receive() - receive a B.A.T.M.A.N. IV OGM packet + * @skb: skb containing the OGM packet + * @if_incoming: interface where the packet was received + * + * Validate the packet, then split the aggregated OGM packet into individual + * OGMs and hand each of them to batadv_iv_ogm_process(). Ownership of @skb is + * always taken over by this function. + * + * Return: NET_RX_SUCCESS or NET_RX_DROP + */ static int batadv_iv_ogm_receive(struct sk_buff *skb, struct batadv_hard_iface *if_incoming) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); struct batadv_ogm_packet *ogm_packet; + int ret = NET_RX_DROP; u8 *packet_pos; int ogm_offset; bool res; - int ret = NET_RX_DROP; res = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); if (!res) @@ -1901,9 +2039,9 @@ batadv_iv_ogm_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, struct batadv_neigh_node *neigh_node, bool best) { + unsigned int last_seen_msecs; void *hdr; u8 tq_avg; - unsigned int last_seen_msecs; last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen); @@ -1965,9 +2103,9 @@ batadv_iv_ogm_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, { struct batadv_neigh_node *neigh_node_best; struct batadv_neigh_node *neigh_node; + u8 tq_avg_best; int sub = 0; bool best; - u8 tq_avg_best; neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing); if (!neigh_node_best) @@ -2060,11 +2198,11 @@ batadv_iv_ogm_orig_dump(struct sk_buff *msg, struct netlink_callback *cb, struct batadv_hard_iface *if_outgoing) { struct batadv_hashtable *hash = bat_priv->orig_hash; - struct hlist_head *head; + int portid = NETLINK_CB(cb->skb).portid; int bucket = cb->args[0]; + struct hlist_head *head; int idx = cb->args[1]; int sub = cb->args[2]; - int portid = NETLINK_CB(cb->skb).portid; while (bucket < hash->size) { head = &hash->table[bucket]; @@ -2103,9 +2241,11 @@ static bool batadv_iv_ogm_neigh_diff(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing2, int *diff) { - struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; - u8 tq1, tq2; + struct batadv_neigh_ifinfo *neigh1_ifinfo; + struct batadv_neigh_ifinfo *neigh2_ifinfo; bool ret = true; + u8 tq1; + u8 tq2; neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); @@ -2139,8 +2279,8 @@ static int batadv_iv_ogm_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq, struct batadv_hardif_neigh_node *hardif_neigh) { - void *hdr; unsigned int last_seen_msecs; + void *hdr; last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen); @@ -2218,12 +2358,12 @@ batadv_iv_ogm_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb, struct batadv_priv *bat_priv, struct batadv_hard_iface *single_hardif) { - struct batadv_hard_iface *hard_iface; - struct list_head *iter; - int i_hardif = 0; - int i_hardif_s = cb->args[0]; - int idx = cb->args[1]; int portid = NETLINK_CB(cb->skb).portid; + struct batadv_hard_iface *hard_iface; + int i_hardif_s = cb->args[0]; + struct list_head *iter; + int idx = cb->args[1]; + int i_hardif = 0; rcu_read_lock(); if (single_hardif) { @@ -2310,6 +2450,12 @@ batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1, return ret; } +/** + * batadv_iv_iface_enabled() - notification handler for activated interfaces + * @hard_iface: interface that was just activated + * + * Set up the per-interface reschedule work and start sending periodic OGMs. + */ static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface) { INIT_DELAYED_WORK(&hard_iface->bat_iv.reschedule_work, batadv_iv_ogm_reschedule); @@ -2328,17 +2474,26 @@ static void batadv_iv_init_sel_class(struct batadv_priv *bat_priv) WRITE_ONCE(bat_priv->gw.sel_class, 20); } +/** + * batadv_iv_gw_get_best_gw_node() - retrieve the best gateway node based on + * the B.A.T.M.A.N. IV metric and the configured GW selection class + * @bat_priv: the bat priv with all the mesh interface information + * + * Return: gateway node with the highest score for the current selection class, + * or NULL if no eligible gateway exists. + */ static struct batadv_gw_node * batadv_iv_gw_get_best_gw_node(struct batadv_priv *bat_priv) { - struct batadv_neigh_node *router; struct batadv_neigh_ifinfo *router_ifinfo; - struct batadv_gw_node *gw_node, *curr_gw = NULL; + struct batadv_gw_node *curr_gw = NULL; + struct batadv_orig_node *orig_node; + struct batadv_neigh_node *router; + struct batadv_gw_node *gw_node; u64 max_gw_factor = 0; u64 tmp_gw_factor = 0; u8 max_tq = 0; u8 tq_avg; - struct batadv_orig_node *orig_node; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) { @@ -2405,6 +2560,19 @@ batadv_iv_gw_get_best_gw_node(struct batadv_priv *bat_priv) return curr_gw; } +/** + * batadv_iv_gw_is_eligible() - check whether a new gateway should replace the + * currently selected one + * @bat_priv: the bat priv with all the mesh interface information + * @curr_gw_orig: originator of the currently selected gateway + * @orig_node: originator of the gateway candidate + * + * Compare the TQ values of @curr_gw_orig and @orig_node, taking the configured + * gateway selection class into account. + * + * Return: true if @orig_node should take over as the active gateway, false + * otherwise + */ static bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv, struct batadv_orig_node *curr_gw_orig, struct batadv_orig_node *orig_node) @@ -2412,10 +2580,11 @@ 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; + struct batadv_neigh_node *router_gw = NULL; bool ret = false; + u8 orig_tq_avg; + u8 gw_tq_avg; /* dynamic re-election is performed only on fast or late switch */ if (sel_class <= 2) @@ -2486,8 +2655,8 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, struct batadv_gw_node *gw_node) { struct batadv_neigh_ifinfo *router_ifinfo = NULL; - struct batadv_neigh_node *router; struct batadv_gw_node *curr_gw = NULL; + struct batadv_neigh_node *router; int ret = 0; void *hdr; @@ -2633,3 +2802,11 @@ int __init batadv_iv_init(void) out: return ret; } + +/** + * batadv_iv_deinit() - B.A.T.M.A.N. IV deinitialization function + */ +void batadv_iv_deinit(void) +{ + batadv_recv_handler_unregister(BATADV_IV_OGM); +} diff --git a/net/batman-adv/bat_iv_ogm.h b/net/batman-adv/bat_iv_ogm.h index 04b01bd684e8..90318801aeaf 100644 --- a/net/batman-adv/bat_iv_ogm.h +++ b/net/batman-adv/bat_iv_ogm.h @@ -10,5 +10,6 @@ #include "main.h" int batadv_iv_init(void); +void batadv_iv_deinit(void); #endif /* _NET_BATMAN_ADV_BAT_IV_OGM_H_ */ diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index db6f5bdcaa98..0c27447cf688 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -41,6 +41,13 @@ #include "netlink.h" #include "originator.h" +/** + * batadv_v_iface_activate() - finalise the activation of a hard interface + * @hard_iface: interface to activate + * + * Reuse the currently selected primary interface to seed the ELP packet. + * Immediately activate the interface. + */ static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); @@ -61,6 +68,16 @@ static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface) hard_iface->if_status = BATADV_IF_ACTIVE; } +/** + * batadv_v_iface_enable() - enable the B.A.T.M.A.N. V protocol on an + * interface + * @hard_iface: interface to enable + * + * Enable the ELP and OGM components for @hard_iface. On error, the partially + * enabled state is rolled back before returning. + * + * Return: 0 on success or negative error number in case of failure + */ static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface) { int ret; @@ -76,12 +93,21 @@ static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface) return ret; } +/** + * batadv_v_iface_disable() - disable the B.A.T.M.A.N. V protocol on an + * interface + * @hard_iface: interface to disable + */ static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface) { batadv_v_ogm_iface_disable(hard_iface); batadv_v_elp_iface_disable(hard_iface); } +/** + * batadv_v_primary_iface_set() - apply primary interface state + * @hard_iface: interface which just became the primary + */ static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface) { batadv_v_elp_primary_iface_set(hard_iface); @@ -109,6 +135,11 @@ static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface) batadv_hardif_put(primary_if); } +/** + * batadv_v_hardif_neigh_init() - initialise the B.A.T.M.A.N. V state of a + * hard interface neighbour + * @hardif_neigh: hard interface neighbour to initialise + */ static void batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh) { @@ -128,9 +159,9 @@ static int batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq, struct batadv_hardif_neigh_node *hardif_neigh) { - void *hdr; unsigned int last_seen_msecs; u32 throughput; + void *hdr; last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen); throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput); @@ -211,12 +242,12 @@ batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb, struct batadv_priv *bat_priv, struct batadv_hard_iface *single_hardif) { - struct batadv_hard_iface *hard_iface; - struct list_head *iter; - int i_hardif = 0; - int i_hardif_s = cb->args[0]; - int idx = cb->args[1]; int portid = NETLINK_CB(cb->skb).portid; + struct batadv_hard_iface *hard_iface; + int i_hardif_s = cb->args[0]; + struct list_head *iter; + int idx = cb->args[1]; + int i_hardif = 0; rcu_read_lock(); if (single_hardif) { @@ -421,11 +452,11 @@ batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb, struct batadv_hard_iface *if_outgoing) { struct batadv_hashtable *hash = bat_priv->orig_hash; - struct hlist_head *head; + int portid = NETLINK_CB(cb->skb).portid; int bucket = cb->args[0]; + struct hlist_head *head; int idx = cb->args[1]; int sub = cb->args[2]; - int portid = NETLINK_CB(cb->skb).portid; while (bucket < hash->size) { head = &hash->table[bucket]; @@ -444,12 +475,23 @@ batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb, cb->args[2] = sub; } +/** + * batadv_v_neigh_cmp() - compare two B.A.T.M.A.N. V neighbours by throughput + * @neigh1: first neighbour to compare + * @if_outgoing1: outgoing interface to use for @neigh1 + * @neigh2: second neighbour to compare + * @if_outgoing2: outgoing interface to use for @neigh2 + * + * Return: a positive value if @neigh1 is better, a negative value if @neigh2 + * is better and 0 if both have equal throughput + */ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing1, struct batadv_neigh_node *neigh2, struct batadv_hard_iface *if_outgoing2) { - struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; + struct batadv_neigh_ifinfo *ifinfo1; + struct batadv_neigh_ifinfo *ifinfo2; int ret = 0; ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); @@ -469,14 +511,26 @@ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1, return ret; } +/** + * batadv_v_neigh_is_sob() - check whether two B.A.T.M.A.N. V neighbours have + * a similar or better throughput + * @neigh1: first neighbour to compare + * @if_outgoing1: outgoing interface to use for @neigh1 + * @neigh2: second neighbour to compare + * @if_outgoing2: outgoing interface to use for @neigh2 + * + * Return: true if the throughput of @neigh2 is at least 3/4 of the + * @neigh1 throughput + */ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing1, struct batadv_neigh_node *neigh2, struct batadv_hard_iface *if_outgoing2) { - struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; - u32 threshold; + struct batadv_neigh_ifinfo *ifinfo1; + struct batadv_neigh_ifinfo *ifinfo2; bool ret = false; + u32 threshold; ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); if (!ifinfo1) @@ -558,8 +612,10 @@ static int batadv_v_gw_throughput_get(struct batadv_gw_node *gw_node, u32 *bw) static struct batadv_gw_node * batadv_v_gw_get_best_gw_node(struct batadv_priv *bat_priv) { - struct batadv_gw_node *gw_node, *curr_gw = NULL; - u32 max_bw = 0, bw; + struct batadv_gw_node *curr_gw = NULL; + struct batadv_gw_node *gw_node; + u32 max_bw = 0; + u32 bw; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) { @@ -598,9 +654,12 @@ static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv, struct batadv_orig_node *curr_gw_orig, struct batadv_orig_node *orig_node) { - struct batadv_gw_node *curr_gw, *orig_gw = NULL; - u32 gw_throughput, orig_throughput, threshold; + struct batadv_gw_node *orig_gw = NULL; + struct batadv_gw_node *curr_gw; + u32 orig_throughput; + u32 gw_throughput; bool ret = false; + u32 threshold; threshold = READ_ONCE(bat_priv->gw.sel_class); @@ -656,8 +715,8 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, struct batadv_gw_node *gw_node) { struct batadv_neigh_ifinfo *router_ifinfo = NULL; - struct batadv_neigh_node *router; struct batadv_gw_node *curr_gw = NULL; + struct batadv_neigh_node *router; int ret = 0; void *hdr; @@ -888,3 +947,12 @@ int __init batadv_v_init(void) return ret; } + +/** + * batadv_v_deinit() - B.A.T.M.A.N. V deinitialization function + */ +void batadv_v_deinit(void) +{ + batadv_recv_handler_unregister(BATADV_OGM2); + batadv_recv_handler_unregister(BATADV_ELP); +} diff --git a/net/batman-adv/bat_v.h b/net/batman-adv/bat_v.h index 964431f4dc8d..76bd969e79a2 100644 --- a/net/batman-adv/bat_v.h +++ b/net/batman-adv/bat_v.h @@ -12,6 +12,7 @@ #ifdef CONFIG_BATMAN_ADV_BATMAN_V int batadv_v_init(void); +void batadv_v_deinit(void); void batadv_v_hardif_init(struct batadv_hard_iface *hardif); int batadv_v_mesh_init(struct batadv_priv *bat_priv); void batadv_v_mesh_free(struct batadv_priv *bat_priv); @@ -23,6 +24,10 @@ static inline int batadv_v_init(void) return 0; } +static inline void batadv_v_deinit(void) +{ +} + static inline void batadv_v_hardif_init(struct batadv_hard_iface *hardif) { } diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 262e40040007..6ad6042a5d9b 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -230,11 +230,14 @@ static bool batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node *neigh) { struct batadv_hard_iface *hard_iface = neigh->if_incoming; - struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); + struct batadv_priv *bat_priv; unsigned long last_tx_diff; struct sk_buff *skb; - int probe_len, i; int elp_skb_len; + int probe_len; + int i; + + bat_priv = netdev_priv(hard_iface->mesh_iface); /* this probing routine is for Wifi neighbours only */ if (!batadv_is_wifi_hardif(hard_iface)) @@ -289,8 +292,8 @@ static void batadv_v_elp_periodic_work(struct work_struct *work) struct batadv_v_metric_queue_entry *metric_entry; struct batadv_v_metric_queue_entry *metric_safe; struct batadv_hardif_neigh_node *hardif_neigh; - struct batadv_hard_iface *hard_iface; struct batadv_hard_iface_bat_v *bat_v; + struct batadv_hard_iface *hard_iface; struct batadv_elp_packet *elp_packet; struct list_head metric_queue; struct batadv_priv *bat_priv; @@ -395,9 +398,9 @@ int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface) static const size_t tvlv_padding = sizeof(__be32); struct batadv_elp_packet *elp_packet; unsigned char *elp_buff; + int res = -ENOMEM; u32 random_seqno; size_t size; - int res = -ENOMEM; size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN + tvlv_padding; hard_iface->bat_v.elp_skb = dev_alloc_skb(size); @@ -500,11 +503,11 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv, struct batadv_elp_packet *elp_packet) { - struct batadv_neigh_node *neigh; - struct batadv_orig_node *orig_neigh; struct batadv_hardif_neigh_node *hardif_neigh; - s32 seqno_diff; + struct batadv_orig_node *orig_neigh; + struct batadv_neigh_node *neigh; s32 elp_latest_seqno; + s32 seqno_diff; orig_neigh = batadv_v_ogm_orig_get(bat_priv, elp_packet->orig); if (!orig_neigh) @@ -556,8 +559,8 @@ int batadv_v_elp_packet_recv(struct sk_buff *skb, struct batadv_elp_packet *elp_packet; struct batadv_hard_iface *primary_if; struct ethhdr *ethhdr; - bool res; int ret = NET_RX_DROP; + bool res; res = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN); if (!res) diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index e921d49f7ece..70846c997410 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -101,6 +101,7 @@ static void batadv_v_ogm_start_queue_timer(struct batadv_hard_iface *hard_iface) static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv) { unsigned long msecs; + /* this function may be invoked in different contexts (ogm rescheduling * or hard_iface activation), but the work timer should not be reset */ @@ -268,11 +269,12 @@ static void batadv_v_ogm_queue_on_if(struct sk_buff *skb, */ 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_hard_iface *hard_iface; struct batadv_ogm_buf *ogm_buff; - struct sk_buff *skb, *skb_tmp; + struct sk_buff *skb_tmp; struct list_head *iter; + struct sk_buff *skb; u16 tvlv_len; int ret; @@ -621,11 +623,11 @@ static int batadv_v_ogm_metric_update(struct batadv_priv *bat_priv, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing) { - struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; + struct batadv_orig_ifinfo *orig_ifinfo; bool protection_started = false; - int ret = -EINVAL; u32 path_throughput; + int ret = -EINVAL; s32 seq_diff; orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); @@ -703,15 +705,17 @@ static bool batadv_v_ogm_route_update(struct batadv_priv *bat_priv, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing) { - struct batadv_neigh_node *router = NULL; - struct batadv_orig_node *orig_neigh_node; struct batadv_neigh_node *orig_neigh_router = NULL; - struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL; - u32 router_throughput, neigh_throughput; + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; + struct batadv_orig_node *orig_neigh_node; + struct batadv_neigh_node *router = NULL; + u32 router_throughput; u32 router_last_seqno; + u32 neigh_throughput; u32 neigh_last_seqno; - s32 neigh_seq_diff; bool forward = false; + s32 neigh_seq_diff; orig_neigh_node = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source); if (!orig_neigh_node) @@ -871,14 +875,16 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset, struct batadv_hard_iface *if_incoming) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); - struct ethhdr *ethhdr; - struct batadv_orig_node *orig_node = NULL; struct batadv_hardif_neigh_node *hardif_neigh = NULL; struct batadv_neigh_node *neigh_node = NULL; - struct batadv_hard_iface *hard_iface; + struct batadv_orig_node *orig_node = NULL; struct batadv_ogm2_packet *ogm_packet; - u32 ogm_throughput, link_throughput, path_throughput; + struct batadv_hard_iface *hard_iface; struct list_head *iter; + struct ethhdr *ethhdr; + u32 link_throughput; + u32 path_throughput; + u32 ogm_throughput; int ret; ethhdr = eth_hdr(skb); @@ -1004,9 +1010,9 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb, struct batadv_priv *bat_priv = netdev_priv(if_incoming->mesh_iface); struct batadv_ogm2_packet *ogm_packet; struct ethhdr *ethhdr; + int ret = NET_RX_DROP; int ogm_offset; u8 *packet_pos; - int ret = NET_RX_DROP; /* did we receive a OGM2 packet on an interface that does not have * B.A.T.M.A.N. V enabled ? diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c index 67cb356332bf..f814756d9533 100644 --- a/net/batman-adv/bitarray.c +++ b/net/batman-adv/bitarray.c @@ -11,7 +11,14 @@ #include "log.h" -/* shift the packet array by n places. */ +/** + * batadv_bitmap_shift_left() - shift the sequence number bitmap left + * @seq_bits: the sequence number bitmap to shift + * @n: number of positions to shift left + * + * Shift @seq_bits by @n positions. No-op if @n is not within the bounds of + * the bitmap. + */ static void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n) { if (n <= 0 || n >= BATADV_TQ_LOCAL_WINDOW_SIZE) diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index f9a1fadf8de9..94e074235e15 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -177,8 +177,8 @@ static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw) */ static void batadv_claim_release(struct kref *ref) { - struct batadv_bla_claim *claim; struct batadv_bla_backbone_gw *old_backbone_gw; + struct batadv_bla_claim *claim; claim = container_of(ref, struct batadv_bla_claim, refcount); @@ -220,9 +220,9 @@ batadv_claim_hash_find(struct batadv_priv *bat_priv, struct batadv_bla_claim *data) { struct batadv_hashtable *hash = bat_priv->bla.claim_hash; - struct hlist_head *head; - struct batadv_bla_claim *claim; struct batadv_bla_claim *claim_tmp = NULL; + struct batadv_bla_claim *claim; + struct hlist_head *head; int index; if (!hash) @@ -260,9 +260,10 @@ batadv_backbone_hash_find(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid) { struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; - struct hlist_head *head; - struct batadv_bla_backbone_gw search_entry, *backbone_gw; struct batadv_bla_backbone_gw *backbone_gw_tmp = NULL; + struct batadv_bla_backbone_gw search_entry; + struct batadv_bla_backbone_gw *backbone_gw; + struct hlist_head *head; int index; if (!hash) @@ -298,12 +299,12 @@ batadv_backbone_hash_find(struct batadv_priv *bat_priv, const u8 *addr, static void batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw) { + spinlock_t *list_lock; /* protects write access to the hash lists */ + struct batadv_bla_claim *claim; struct batadv_hashtable *hash; struct hlist_node *node_tmp; struct hlist_head *head; - struct batadv_bla_claim *claim; int i; - spinlock_t *list_lock; /* protects write access to the hash lists */ hash = backbone_gw->bat_priv->bla.claim_hash; if (!hash) @@ -341,12 +342,12 @@ batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw) static void batadv_bla_send_claim(struct batadv_priv *bat_priv, const u8 *mac, unsigned short vid, int claimtype) { - struct sk_buff *skb; - struct ethhdr *ethhdr; - struct batadv_hard_iface *primary_if; - u8 *hw_src; struct batadv_bla_claim_dst local_claim_dest; + struct batadv_hard_iface *primary_if; + struct ethhdr *ethhdr; + struct sk_buff *skb; __be32 zeroip = 0; + u8 *hw_src; primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) @@ -593,10 +594,10 @@ static void batadv_bla_answer_request(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, unsigned short vid) { - struct hlist_head *head; - struct batadv_hashtable *hash; - struct batadv_bla_claim *claim; struct batadv_bla_backbone_gw *backbone_gw; + struct batadv_bla_claim *claim; + struct batadv_hashtable *hash; + struct hlist_head *head; int i; batadv_dbg(BATADV_DBG_BLA, bat_priv, @@ -692,8 +693,8 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, struct batadv_bla_backbone_gw *backbone_gw) { struct batadv_bla_backbone_gw *old_backbone_gw; - struct batadv_bla_claim *claim; struct batadv_bla_claim search_claim; + struct batadv_bla_claim *claim; bool remove_crc = false; int hash_added; @@ -800,9 +801,10 @@ batadv_bla_claim_get_backbone_gw(struct batadv_bla_claim *claim) static void batadv_bla_del_claim(struct batadv_priv *bat_priv, const u8 *mac, const unsigned short vid) { - struct batadv_bla_claim search_claim, *claim; struct batadv_bla_claim *claim_removed_entry; struct hlist_node *claim_removed_node; + struct batadv_bla_claim search_claim; + struct batadv_bla_claim *claim; ether_addr_copy(search_claim.addr, mac); search_claim.vid = vid; @@ -842,7 +844,8 @@ static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr, u8 *backbone_addr, unsigned short vid) { struct batadv_bla_backbone_gw *backbone_gw; - u16 backbone_crc, crc; + u16 backbone_crc; + u16 crc; if (memcmp(an_addr, batadv_announce_mac, 4) != 0) return false; @@ -1019,9 +1022,10 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv, u8 *hw_src, u8 *hw_dst, struct ethhdr *ethhdr) { - u8 *backbone_addr; + struct batadv_bla_claim_dst *bla_dst_own; + struct batadv_bla_claim_dst *bla_dst; struct batadv_orig_node *orig_node; - struct batadv_bla_claim_dst *bla_dst, *bla_dst_own; + u8 *backbone_addr; bla_dst = (struct batadv_bla_claim_dst *)hw_dst; bla_dst_own = &bat_priv->bla.claim_dest; @@ -1078,6 +1082,11 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv, * @primary_if: the primary hard interface of this batman mesh interface * @skb: the frame to be checked * + * Warning: This function may reallocate the skb data buffer via + * batadv_get_vid()/... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Return: true if it was a claim frame, otherwise return false to * tell the callee that it can use the frame on its own. */ @@ -1085,15 +1094,18 @@ static bool batadv_bla_process_claim(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, struct sk_buff *skb) { - struct batadv_bla_claim_dst *bla_dst, *bla_dst_own; - u8 *hw_src, *hw_dst; - struct vlan_hdr *vhdr, vhdr_buf; + struct batadv_bla_claim_dst *bla_dst_own; + struct batadv_bla_claim_dst *bla_dst; + struct vlan_hdr vhdr_buf; + struct vlan_hdr *vhdr; struct ethhdr *ethhdr; struct arphdr *arphdr; unsigned short vid; int vlan_depth = 0; __be16 proto; int headlen; + u8 *hw_src; + u8 *hw_dst; int ret; vid = batadv_get_vid(skb, 0); @@ -1225,11 +1237,11 @@ static bool batadv_bla_process_claim(struct batadv_priv *bat_priv, */ static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now) { + spinlock_t *list_lock; /* protects write access to the hash lists */ struct batadv_bla_backbone_gw *backbone_gw; + struct batadv_hashtable *hash; struct hlist_node *node_tmp; struct hlist_head *head; - struct batadv_hashtable *hash; - spinlock_t *list_lock; /* protects write access to the hash lists */ bool purged; int i; @@ -1302,8 +1314,8 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, { struct batadv_bla_backbone_gw *backbone_gw; struct batadv_bla_claim *claim; - struct hlist_head *head; struct batadv_hashtable *hash; + struct hlist_head *head; int i; hash = bat_priv->bla.claim_hash; @@ -1365,8 +1377,8 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, struct batadv_hard_iface *oldif) { struct batadv_bla_backbone_gw *backbone_gw; - struct hlist_head *head; struct batadv_hashtable *hash; + struct hlist_head *head; __be16 group; int i; @@ -1459,14 +1471,14 @@ void batadv_bla_status_update(struct net_device *net_dev) */ static void batadv_bla_periodic_work(struct work_struct *work) { - struct delayed_work *delayed_work; - struct batadv_priv *bat_priv; - struct batadv_priv_bla *priv_bla; - struct hlist_head *head; struct batadv_bla_backbone_gw *backbone_gw; - struct batadv_hashtable *hash; struct batadv_hard_iface *primary_if; + struct delayed_work *delayed_work; + struct batadv_priv_bla *priv_bla; + struct batadv_hashtable *hash; + struct batadv_priv *bat_priv; bool send_loopdetect = false; + struct hlist_head *head; int i; delayed_work = to_delayed_work(work); @@ -1568,11 +1580,11 @@ static struct lock_class_key batadv_backbone_hash_lock_class_key; */ int batadv_bla_init(struct batadv_priv *bat_priv) { - int i; u8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00}; struct batadv_hard_iface *primary_if; - u16 crc; unsigned long entrytime; + u16 crc; + int i; spin_lock_init(&bat_priv->bla.bcast_duplist_lock); @@ -1651,8 +1663,9 @@ static bool batadv_bla_check_duplist(struct batadv_priv *bat_priv, struct batadv_bcast_duplist_entry *entry; bool ret = false; int payload_len; - int i, curr; + int curr; u32 crc; + int i; /* calculate the crc ... */ payload_len = skb->len - payload_offset; @@ -1774,8 +1787,8 @@ bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, unsigned short vid) { struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; - struct hlist_head *head; struct batadv_bla_backbone_gw *backbone_gw; + struct hlist_head *head; int i; if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) @@ -1807,6 +1820,11 @@ bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, * @orig_node: the orig_node of the frame * @hdr_size: maximum length of the frame * + * Warning: This function may reallocate the skb data buffer via + * pskb_may_pull()/batadv_get_vid()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Return: true if the orig_node is also a gateway on the mesh interface, * otherwise it returns false. */ @@ -1936,9 +1954,10 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short vid, int packet_type) { struct batadv_bla_backbone_gw *backbone_gw; - struct ethhdr *ethhdr; - struct batadv_bla_claim search_claim, *claim = NULL; + struct batadv_bla_claim *claim = NULL; + struct batadv_bla_claim search_claim; struct batadv_hard_iface *primary_if; + struct ethhdr *ethhdr; bool own_claim; bool ret; @@ -2061,7 +2080,10 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, * * in these cases, the skb is further handled by this function. * - * This call might reallocate skb data. + * Warning: This function may reallocate the skb data buffer via + * batadv_bla_process_claim()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. * * Return: true if handled, otherwise it returns false and the caller shall * further process the skb. @@ -2069,10 +2091,11 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short vid) { - struct ethhdr *ethhdr; - struct batadv_bla_claim search_claim, *claim = NULL; struct batadv_bla_backbone_gw *backbone_gw; + struct batadv_bla_claim *claim = NULL; + struct batadv_bla_claim search_claim; struct batadv_hard_iface *primary_if; + struct ethhdr *ethhdr; bool client_roamed; bool ret = false; @@ -2173,10 +2196,10 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, { const u8 *primary_addr = primary_if->net_dev->dev_addr; struct batadv_bla_backbone_gw *backbone_gw; + int ret = -EINVAL; u16 backbone_crc; bool is_own; void *hdr; - int ret = -EINVAL; hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq, &batadv_netlink_family, NLM_F_MULTI, @@ -2335,11 +2358,11 @@ batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid, struct batadv_bla_backbone_gw *backbone_gw) { const u8 *primary_addr = primary_if->net_dev->dev_addr; + int ret = -EINVAL; u16 backbone_crc; bool is_own; int msecs; void *hdr; - int ret = -EINVAL; hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq, &batadv_netlink_family, NLM_F_MULTI, @@ -2494,10 +2517,10 @@ int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb) bool batadv_bla_check_claim(struct batadv_priv *bat_priv, u8 *addr, unsigned short vid) { - struct batadv_bla_backbone_gw *backbone_gw; - struct batadv_bla_claim search_claim; - struct batadv_bla_claim *claim = NULL; struct batadv_hard_iface *primary_if = NULL; + struct batadv_bla_backbone_gw *backbone_gw; + struct batadv_bla_claim *claim = NULL; + struct batadv_bla_claim search_claim; bool ret = true; if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index a6fe4820f65b..0d5a9cb0affe 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -50,27 +50,65 @@ #include "translation-table.h" #include "tvlv.h" +/** + * enum batadv_bootpop - BOOTP/DHCP message op codes + */ enum batadv_bootpop { + /** @BATADV_BOOTREPLY: server-to-client reply */ BATADV_BOOTREPLY = 2, }; +/** + * enum batadv_boothtype - BOOTP/DHCP hardware address types + */ enum batadv_boothtype { + /** @BATADV_HTYPE_ETHERNET: Ethernet (10Mb) */ BATADV_HTYPE_ETHERNET = 1, }; +/** + * enum batadv_dhcpoptioncode - DHCP option codes relevant for batman-adv DAT + */ enum batadv_dhcpoptioncode { + /** @BATADV_DHCP_OPT_PAD: pad option */ BATADV_DHCP_OPT_PAD = 0, + + /** @BATADV_DHCP_OPT_MSG_TYPE: DHCP message type option */ BATADV_DHCP_OPT_MSG_TYPE = 53, + + /** @BATADV_DHCP_OPT_END: end of options marker */ BATADV_DHCP_OPT_END = 255, }; +/** + * enum batadv_dhcptype - DHCP message types relevant for batman-adv DAT + */ enum batadv_dhcptype { + /** @BATADV_DHCPACK: DHCPACK message */ BATADV_DHCPACK = 5, }; /* { 99, 130, 83, 99 } */ #define BATADV_DHCP_MAGIC 1669485411 +/** + * struct batadv_dhcp_packet - BOOTP/DHCP packet header + * @op: message op code / message type + * @htype: hardware address type + * @hlen: hardware address length + * @hops: number of relay hops + * @xid: transaction identifier + * @secs: seconds elapsed since client started trying to boot + * @flags: BOOTP/DHCP flags + * @ciaddr: client IP address + * @yiaddr: "your" (client) IP address as assigned by the server + * @siaddr: IP address of next server to use in bootstrap + * @giaddr: relay agent IP address + * @chaddr: client hardware address + * @sname: optional server host name + * @file: boot file name + * @magic: BOOTP/DHCP magic cookie identifying the start of options + */ struct batadv_dhcp_packet { __u8 op; __u8 htype; @@ -90,6 +128,34 @@ struct batadv_dhcp_packet { /* __u8 options[]; */ }; +/** + * struct batadv_dhcp_header - minimal BOOTP/DHCP packet header + */ +struct batadv_dhcp_header { + /** @op: message op code / message type */ + __u8 op; + + /** @htype: hardware address type */ + __u8 htype; + + /** @hlen: hardware address length */ + __u8 hlen; + + /** @hops: number of relay hops */ + __u8 hops; +}; + +/** + * struct batadv_dhcp_option_header - BOOTP/DHCP option header + */ +struct batadv_dhcp_option_header { + /** @type: type of option */ + __u8 type; + + /** @len: length of option */ + __u8 len; +}; + #define BATADV_DHCP_YIADDR_LEN sizeof(((struct batadv_dhcp_packet *)0)->yiaddr) #define BATADV_DHCP_CHADDR_LEN sizeof(((struct batadv_dhcp_packet *)0)->chaddr) @@ -288,9 +354,9 @@ static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size) */ static u32 batadv_hash_dat(const void *data, u32 size) { - u32 hash = 0; const struct batadv_dat_entry *dat = data; const unsigned char *key; + u32 hash = 0; __be16 vid; u32 i; @@ -329,9 +395,11 @@ static struct batadv_dat_entry * batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, unsigned short vid) { - struct hlist_head *head; - struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL; struct batadv_hashtable *hash = bat_priv->dat.hash; + struct batadv_dat_entry *dat_entry_tmp = NULL; + struct batadv_dat_entry *dat_entry; + struct batadv_dat_entry to_find; + struct hlist_head *head; u32 index; if (!hash) @@ -432,7 +500,8 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb, struct batadv_unicast_4addr_packet *unicast_4addr_packet; struct batadv_bcast_packet *bcast_pkt; u8 *orig_addr; - __be32 ip_src, ip_dst; + __be32 ip_src; + __be32 ip_dst; if (msg) batadv_dbg(BATADV_DBG_DAT, bat_priv, "%s\n", msg); @@ -567,10 +636,11 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv, int select, batadv_dat_addr_t ip_key, batadv_dat_addr_t *last_max) { - batadv_dat_addr_t max = 0; - batadv_dat_addr_t tmp_max = 0; - struct batadv_orig_node *orig_node, *max_orig_node = NULL; struct batadv_hashtable *hash = bat_priv->orig_hash; + struct batadv_orig_node *max_orig_node = NULL; + struct batadv_orig_node *orig_node; + batadv_dat_addr_t tmp_max = 0; + batadv_dat_addr_t max = 0; struct hlist_head *head; int i; @@ -634,10 +704,11 @@ static struct batadv_dat_candidate * batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst, unsigned short vid) { - int select; - batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key; + batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX; struct batadv_dat_candidate *res; struct batadv_dat_entry dat; + batadv_dat_addr_t ip_key; + int select; if (!bat_priv->orig_hash) return NULL; @@ -680,12 +751,12 @@ static bool batadv_dat_forward_data(struct batadv_priv *bat_priv, struct sk_buff *skb, __be32 ip, unsigned short vid, int packet_subtype) { - int i; + struct batadv_neigh_node *neigh_node = NULL; + struct batadv_dat_candidate *cand; + struct sk_buff *tmp_skb; bool ret = false; int send_status; - struct batadv_neigh_node *neigh_node = NULL; - struct sk_buff *tmp_skb; - struct batadv_dat_candidate *cand; + int i; cand = batadv_dat_select_candidates(bat_priv, ip, vid); if (!cand) @@ -993,6 +1064,11 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) * @skb: packet to analyse * @hdr_size: size of the possible header before the ARP packet in the skb * + * Warning: This function may reallocate the skb data buffer via + * pskb_may_pull()/... Any pointer into the skb data (e.g. obtained from skb->data + * or eth_hdr()) before this call must be considered invalid afterwards and has + * to be reacquired. + * * Return: the ARP type if the skb contains a valid ARP packet, 0 otherwise. */ static u16 batadv_arp_get_type(struct batadv_priv *bat_priv, @@ -1000,9 +1076,11 @@ static u16 batadv_arp_get_type(struct batadv_priv *bat_priv, { struct arphdr *arphdr; struct ethhdr *ethhdr; - __be32 ip_src, ip_dst; - u8 *hw_src, *hw_dst; + __be32 ip_src; + __be32 ip_dst; u16 type = 0; + u8 *hw_src; + u8 *hw_dst; /* pull the ethernet header */ if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN))) @@ -1069,6 +1147,11 @@ static u16 batadv_arp_get_type(struct batadv_priv *bat_priv, * The caller must ensure that at least @hdr_size + ETH_HLEN bytes are * accessible after skb->data. * + * Warning: This function calls batadv_get_vid() and may therefore reallocate + * the skb data buffer. Any pointer into the skb data (e.g. obtained from + * skb->data or eth_hdr()) before this call must be considered invalid + * afterwards and has to be reacquired. + * * Return: If the packet embedded in the skb is vlan tagged this function * returns the VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS * is returned. @@ -1131,6 +1214,11 @@ batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src, * @bat_priv: the bat priv with all the mesh interface information * @skb: packet to check * + * Warning: This function may reallocate the skb data buffer via + * batadv_dat_get_vid()/.... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Return: true if the message has been sent to the dht candidates, false * otherwise. In case of a positive return value the message has to be enqueued * to permit the fallback. @@ -1138,15 +1226,16 @@ batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src, bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, struct sk_buff *skb) { - u16 type = 0; - __be32 ip_dst, ip_src; - u8 *hw_src; - bool ret = false; + struct net_device *mesh_iface = bat_priv->mesh_iface; struct batadv_dat_entry *dat_entry = NULL; struct sk_buff *skb_new; - struct net_device *mesh_iface = bat_priv->mesh_iface; - int hdr_size = 0; unsigned short vid; + bool ret = false; + int hdr_size = 0; + __be32 ip_dst; + __be32 ip_src; + u16 type = 0; + u8 *hw_src; if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; @@ -1233,18 +1322,24 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, * @skb: packet to check * @hdr_size: size of the encapsulation header * + * Warning: This function may reallocate the skb data buffer via + * batadv_dat_get_vid()/... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Return: true if the request has been answered, false otherwise. */ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, struct sk_buff *skb, int hdr_size) { - u16 type; - __be32 ip_src, ip_dst; - u8 *hw_src; - struct sk_buff *skb_new; struct batadv_dat_entry *dat_entry = NULL; - bool ret = false; + struct sk_buff *skb_new; unsigned short vid; + bool ret = false; + __be32 ip_src; + __be32 ip_dst; + u8 *hw_src; + u16 type; int err; if (!READ_ONCE(bat_priv->distributed_arp_table)) @@ -1277,17 +1372,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, if (!skb_new) goto out; - /* To preserve backwards compatibility, the node has choose the outgoing - * format based on the incoming request packet type. The assumption is - * that a node not using the 4addr packet format doesn't support it. - */ - if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) - err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new, - BATADV_P_DAT_CACHE_REPLY, - NULL, vid); - else - err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid); - + err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new, + BATADV_P_DAT_CACHE_REPLY, + NULL, vid); if (err != NET_XMIT_DROP) { batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); ret = true; @@ -1303,15 +1390,22 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, * batadv_dat_snoop_outgoing_arp_reply() - snoop the ARP reply and fill the DHT * @bat_priv: the bat priv with all the mesh interface information * @skb: packet to check + * + * Warning: This function may reallocate the skb data buffer via + * batadv_dat_get_vid()/... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. */ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, struct sk_buff *skb) { - u16 type; - __be32 ip_src, ip_dst; - u8 *hw_src, *hw_dst; - int hdr_size = 0; unsigned short vid; + int hdr_size = 0; + __be32 ip_src; + __be32 ip_dst; + u8 *hw_src; + u8 *hw_dst; + u16 type; if (!READ_ONCE(bat_priv->distributed_arp_table)) return; @@ -1352,6 +1446,11 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, * @skb: packet to check * @hdr_size: size of the encapsulation header * + * Warning: This function may reallocate the skb data buffer via + * batadv_dat_get_vid()/... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Return: true if the packet was snooped and consumed by DAT. False if the * packet has to be delivered to the interface */ @@ -1359,11 +1458,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, struct sk_buff *skb, int hdr_size) { struct batadv_dat_entry *dat_entry = NULL; - u16 type; - __be32 ip_src, ip_dst; - u8 *hw_src, *hw_dst; bool dropped = false; unsigned short vid; + __be32 ip_src; + __be32 ip_dst; + u8 *hw_src; + u8 *hw_dst; + u16 type; if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; @@ -1454,8 +1555,10 @@ static bool batadv_dat_check_dhcp_ipudp(struct sk_buff *skb, __be32 *ip_src) { unsigned int offset = skb_network_offset(skb); - struct udphdr *udphdr, _udphdr; - struct iphdr *iphdr, _iphdr; + struct udphdr *udphdr; + struct udphdr _udphdr; + struct iphdr *iphdr; + struct iphdr _iphdr; iphdr = skb_header_pointer(skb, offset, sizeof(_iphdr), &_iphdr); if (!iphdr || iphdr->version != 4 || iphdr->ihl * 4 < sizeof(_iphdr)) @@ -1493,14 +1596,11 @@ batadv_dat_check_dhcp_ipudp(struct sk_buff *skb, __be32 *ip_src) static int batadv_dat_check_dhcp(struct sk_buff *skb, __be16 proto, __be32 *ip_src) { - __be32 *magic, _magic; + struct batadv_dhcp_header *dhcp_h; + struct batadv_dhcp_header _dhcp_h; unsigned int offset; - struct { - __u8 op; - __u8 htype; - __u8 hlen; - __u8 hops; - } *dhcp_h, _dhcp_h; + __be32 *magic; + __be32 _magic; if (proto != htons(ETH_P_IP)) return -EINVAL; @@ -1541,11 +1641,10 @@ batadv_dat_check_dhcp(struct sk_buff *skb, __be16 proto, __be32 *ip_src) static int batadv_dat_get_dhcp_message_type(struct sk_buff *skb) { unsigned int offset = skb_transport_offset(skb) + sizeof(struct udphdr); - u8 *type, _type; - struct { - u8 type; - u8 len; - } *tl, _tl; + struct batadv_dhcp_option_header *tl; + struct batadv_dhcp_option_header _tl; + u8 *type; + u8 _type; offset += sizeof(struct batadv_dhcp_packet); @@ -1737,7 +1836,8 @@ void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv, unsigned short vid) { u8 chaddr[BATADV_DHCP_CHADDR_LEN]; - __be32 ip_src, yiaddr; + __be32 ip_src; + __be32 yiaddr; if (!READ_ONCE(bat_priv->distributed_arp_table)) return; @@ -1758,15 +1858,21 @@ void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv, * This function first checks whether the given skb is a valid DHCPACK. If * so then its source MAC and IP as well as its DHCP Client Hardware Address * field and DHCP Your IP Address field are added to the local DAT cache. + * + * Warning: This function may reallocate the skb data buffer via + * pskb_may_pull()/batadv_dat_get_vid()/... Any pointer into the skb data + * (e.g.obtained from skb->data or eth_hdr()) before this call must be + * considered invalid afterwards and has to be reacquired. */ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv, struct sk_buff *skb, int hdr_size) { u8 chaddr[BATADV_DHCP_CHADDR_LEN]; struct ethhdr *ethhdr; - __be32 ip_src, yiaddr; unsigned short vid; int hdr_size_tmp; + __be32 ip_src; + __be32 yiaddr; __be16 proto; u8 *hw_src; @@ -1805,17 +1911,22 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv, * @bat_priv: the bat priv with all the mesh interface information * @forw_packet: the broadcast packet * + * Warning: This function may reallocate the skb data buffer via + * batadv_dat_get_vid()/... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Return: true if the node can drop the packet, false otherwise. */ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, struct batadv_forw_packet *forw_packet) { - u16 type; - __be32 ip_dst; - struct batadv_dat_entry *dat_entry = NULL; - bool ret = false; int hdr_size = sizeof(struct batadv_bcast_packet); + struct batadv_dat_entry *dat_entry = NULL; unsigned short vid; + bool ret = false; + __be32 ip_dst; + u16 type; if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index 2e20a2cb64cb..493af3091aa8 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -139,15 +139,17 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, struct sk_buff *skb, struct hlist_head *chain_out) { - struct batadv_frag_table_entry *chain; - struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr; struct batadv_frag_list_entry *frag_entry_last = NULL; + struct batadv_frag_list_entry *frag_entry_new = NULL; + u16 hdr_size = sizeof(struct batadv_frag_packet); + struct batadv_frag_list_entry *frag_entry_curr; struct batadv_frag_packet *frag_packet; - u8 bucket; - u16 seqno, hdr_size = sizeof(struct batadv_frag_packet); + struct batadv_frag_table_entry *chain; bool overflow = false; bool ret = false; size_t data_len; + u8 bucket; + u16 seqno; /* Linearize packet to avoid linearizing 16 packets in a row when doing * the later merge. Non-linear merge should be added to remove this @@ -258,11 +260,12 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, static struct sk_buff * batadv_frag_merge_packets(struct hlist_head *chain) { - struct batadv_frag_packet *packet; + int hdr_size = sizeof(struct batadv_frag_packet); struct batadv_frag_list_entry *entry; + struct batadv_frag_packet *packet; struct sk_buff *skb_out; - int size, hdr_size = sizeof(struct batadv_frag_packet); bool dropped = false; + int size; /* Remove first entry, as this is the destination for the rest of the * fragments. @@ -348,8 +351,8 @@ static bool batadv_skb_is_frag(struct sk_buff *skb) bool batadv_frag_skb_buffer(struct sk_buff **skb, struct batadv_orig_node *orig_node_src) { - struct sk_buff *skb_out = NULL; struct hlist_head head = HLIST_HEAD_INIT; + struct sk_buff *skb_out = NULL; bool ret = false; /* Add packet to buffer and table entry if merge is possible. */ @@ -403,8 +406,8 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb, struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); struct batadv_neigh_node *neigh_node = NULL; struct batadv_frag_packet *packet; - u16 total_size; bool ret = false; + u16 total_size; packet = (struct batadv_frag_packet *)skb->data; @@ -468,10 +471,11 @@ static struct sk_buff *batadv_frag_create(struct net_device *net_dev, { unsigned int ll_reserved = LL_RESERVED_SPACE(net_dev); unsigned int tailroom = net_dev->needed_tailroom; - struct sk_buff *skb_fragment; unsigned int header_size = sizeof(*frag_head); - unsigned int mtu = fragment_size + header_size; + struct sk_buff *skb_fragment; + unsigned int mtu; + mtu = fragment_size + header_size; skb_fragment = dev_alloc_skb(ll_reserved + mtu + tailroom); if (!skb_fragment) goto err; @@ -503,15 +507,18 @@ int batadv_frag_send_packet(struct sk_buff *skb, struct batadv_neigh_node *neigh_node) { struct net_device *net_dev = neigh_node->if_incoming->net_dev; - struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; struct batadv_frag_packet frag_header; - struct sk_buff *skb_fragment; unsigned int mtu = net_dev->mtu; - unsigned int header_size = sizeof(frag_header); - unsigned int max_fragment_size, num_fragments; + unsigned int max_fragment_size; + struct batadv_priv *bat_priv; + struct sk_buff *skb_fragment; + unsigned int num_fragments; + unsigned int header_size; int ret; + header_size = sizeof(frag_header); + /* To avoid merge and refragmentation at next-hops we never send * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE */ diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index a5ac82eabd25..e6e97c0478cc 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -103,8 +103,8 @@ batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv) struct batadv_orig_node * batadv_gw_get_selected_orig(struct batadv_priv *bat_priv) { - struct batadv_gw_node *gw_node; struct batadv_orig_node *orig_node = NULL; + struct batadv_gw_node *gw_node; gw_node = batadv_gw_get_selected_gw_node(bat_priv); if (!gw_node) @@ -125,6 +125,14 @@ batadv_gw_get_selected_orig(struct batadv_priv *bat_priv) return orig_node; } +/** + * batadv_gw_select() - select a new currently active gateway + * @bat_priv: the bat priv with all the mesh interface information + * @new_gw_node: gateway node to be set as the current gateway, may be NULL + * + * Atomically replace the currently active gateway with @new_gw_node and drop + * the reference to the previous one. + */ static void batadv_gw_select(struct batadv_priv *bat_priv, struct batadv_gw_node *new_gw_node) { @@ -197,10 +205,10 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv) */ void batadv_gw_election(struct batadv_priv *bat_priv) { + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router = NULL; struct batadv_gw_node *curr_gw = NULL; struct batadv_gw_node *next_gw = NULL; - struct batadv_neigh_node *router = NULL; - struct batadv_neigh_ifinfo *router_ifinfo = NULL; char gw_addr[18] = { '\0' }; if (READ_ONCE(bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) @@ -370,7 +378,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, struct batadv_gw_node *batadv_gw_node_get(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { - struct batadv_gw_node *gw_node_tmp, *gw_node = NULL; + struct batadv_gw_node *gw_node = NULL; + struct batadv_gw_node *gw_node_tmp; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.gateway_list, @@ -400,7 +409,8 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, struct batadv_tvlv_gateway_data *gateway) { - struct batadv_gw_node *gw_node, *curr_gw = NULL; + struct batadv_gw_node *curr_gw = NULL; + struct batadv_gw_node *gw_node; spin_lock_bh(&bat_priv->gw.list_lock); gw_node = batadv_gw_node_get(bat_priv, orig_node); @@ -545,7 +555,10 @@ int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb) * @chaddr: buffer where the client address will be stored. Valid * only if the function returns BATADV_DHCP_TO_CLIENT * - * This function may re-allocate the data buffer of the skb passed as argument. + * Warning: This function may reallocate the skb data buffer via + * pskb_may_pull()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. * * Return: * - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error @@ -558,11 +571,11 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, u8 *chaddr) { enum batadv_dhcp_recipient ret = BATADV_DHCP_NO; - struct ethhdr *ethhdr; - struct iphdr *iphdr; - struct ipv6hdr *ipv6hdr; - struct udphdr *udphdr; struct vlan_ethhdr *vhdr; + struct ipv6hdr *ipv6hdr; + struct ethhdr *ethhdr; + struct udphdr *udphdr; + struct iphdr *iphdr; int chaddr_offset; __be16 proto; u8 *p; @@ -669,7 +682,11 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, * server. Due to topology changes it may be the case that the GW server * previously selected is not the best one anymore. * - * This call might reallocate skb data. + * Warning: This function may reallocate the skb data buffer via + * batadv_get_vid()/... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Must be invoked only when the DHCP packet is going TO a DHCP SERVER. * * Return: true if the packet destination is unicast and it is not the best gw, @@ -678,16 +695,17 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb) { + struct batadv_orig_node *orig_dst_node = NULL; struct batadv_neigh_node *neigh_curr = NULL; struct batadv_neigh_node *neigh_old = NULL; - struct batadv_orig_node *orig_dst_node = NULL; + struct batadv_neigh_ifinfo *curr_ifinfo; + struct batadv_neigh_ifinfo *old_ifinfo; struct batadv_gw_node *gw_node = NULL; struct batadv_gw_node *curr_gw = NULL; - struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; - struct ethhdr *ethhdr; bool out_of_range = false; - u8 curr_tq_avg; + struct ethhdr *ethhdr; unsigned short vid; + u8 curr_tq_avg; vid = batadv_get_vid(skb, 0); ethhdr = (struct ethhdr *)skb->data; diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 675ebf098d4e..65d339205090 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -26,7 +26,8 @@ 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; + u32 down; + u32 up; gw_mode = READ_ONCE(bat_priv->gw.mode); @@ -59,7 +60,8 @@ static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, u8 flags, void *tvlv_value, u16 tvlv_value_len) { - struct batadv_tvlv_gateway_data gateway, *gateway_ptr; + struct batadv_tvlv_gateway_data *gateway_ptr; + struct batadv_tvlv_gateway_data gateway; /* only fetch the tvlv value if the handler wasn't called via the * CIFNOTFND flag and if there is data to fetch diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index b6867576bbaf..e7ad295504e4 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -197,6 +197,17 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) return ret; } +/** + * batadv_is_valid_iface() - check whether a net_device can be used as a hard + * interface + * @net_dev: the net_device to check + * + * Refuse loopback devices, non-Ethernet devices, devices with a non-Ethernet + * address length and any device that is already part of a batman-adv mesh + * interface stack. + * + * Return: true if @net_dev can be used as a hard interface, false otherwise + */ static bool batadv_is_valid_iface(const struct net_device *net_dev) { if (net_dev->flags & IFF_LOOPBACK) @@ -339,8 +350,8 @@ static bool batadv_is_cfg80211_netdev(struct net_device *net_device) */ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device) { - u32 wifi_flags = 0; struct net_device *real_netdev; + u32 wifi_flags = 0; if (batadv_is_wext_netdev(net_device)) wifi_flags |= BATADV_HARDIF_WIFI_WEXT_DIRECT; @@ -434,8 +445,8 @@ 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; + struct hlist_node *first; rcu_read_lock(); @@ -467,6 +478,14 @@ int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, return ret; } +/** + * batadv_hardif_get_active() - retrieve an active hard interface for a mesh + * interface + * @mesh_iface: mesh interface to search + * + * Return: first hard interface in BATADV_IF_ACTIVE state attached to + * @mesh_iface, or NULL if none is active. + */ static struct batadv_hard_iface * batadv_hardif_get_active(struct net_device *mesh_iface) { @@ -487,6 +506,15 @@ batadv_hardif_get_active(struct net_device *mesh_iface) return hard_iface; } +/** + * batadv_primary_if_update_addr() - propagate the new primary interface MAC + * address to all dependent components + * @bat_priv: the bat priv with all the mesh interface information + * @oldif: previously used primary interface, or NULL if none + * + * Inform DAT and BLA that the originator address has changed so they can + * adjust their state accordingly. + */ static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv, struct batadv_hard_iface *oldif) { @@ -502,6 +530,15 @@ static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv, batadv_hardif_put(primary_if); } +/** + * batadv_primary_if_select() - select the new primary interface + * @bat_priv: the bat priv with all the mesh interface information + * @new_hard_iface: new primary interface, may be NULL + * + * Replace the currently selected primary interface with @new_hard_iface, + * invoke the algorithm-specific primary_set hook and update the originator + * MAC address. + */ static void batadv_primary_if_select(struct batadv_priv *bat_priv, struct batadv_hard_iface *new_hard_iface) { @@ -525,6 +562,13 @@ static void batadv_primary_if_select(struct batadv_priv *bat_priv, batadv_hardif_put(curr_hard_iface); } +/** + * batadv_hardif_is_iface_up() - check whether the underlying net_device of a + * hard interface is up + * @hard_iface: the hard interface to check + * + * Return: true if the underlying net_device has the IFF_UP flag set + */ static bool batadv_hardif_is_iface_up(const struct batadv_hard_iface *hard_iface) { @@ -534,6 +578,15 @@ batadv_hardif_is_iface_up(const struct batadv_hard_iface *hard_iface) return false; } +/** + * batadv_check_known_mac_addr() - warn about duplicate hard interface MAC + * addresses + * @hard_iface: hard interface that was just added or had its MAC changed + * + * Iterate over all hard interfaces of the same mesh interface and emit a + * warning if another in-use interface shares the same MAC address as + * @hard_iface. + */ static void batadv_check_known_mac_addr(const struct batadv_hard_iface *hard_iface) { struct net_device *mesh_iface = hard_iface->mesh_iface; @@ -666,11 +719,20 @@ void batadv_update_min_mtu(struct net_device *mesh_iface) batadv_tt_local_resize_to_mtu(mesh_iface); } +/** + * batadv_hardif_activate_interface() - move a hard interface to the active + * state + * @hard_iface: the interface that has come up + * + * Activate an interface, select it as the primary interface if no + * primary is currently active and invoke the algorithm-specific + * activate hook. + */ static void batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface) { - struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; + struct batadv_priv *bat_priv; if (hard_iface->if_status != BATADV_IF_INACTIVE) goto out; @@ -699,6 +761,14 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface) batadv_hardif_put(primary_if); } +/** + * batadv_hardif_deactivate_interface() - move a hard interface to the + * inactive state + * @hard_iface: the interface that went down + * + * Demote @hard_iface to BATADV_IF_INACTIVE and recalculate the mesh minimum + * MTU based on the remaining active interfaces. + */ static void batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface) { @@ -724,10 +794,10 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface) int batadv_hardif_enable_interface(struct net_device *net_dev, struct net_device *mesh_iface) { - struct batadv_priv *bat_priv; - __be16 ethertype = htons(ETH_P_BATMAN); int max_header_len = batadv_max_header_len(); + __be16 ethertype = htons(ETH_P_BATMAN); struct batadv_hard_iface *hard_iface; + struct batadv_priv *bat_priv; unsigned int required_mtu; unsigned int hardif_mtu; bool fragmentation; @@ -1020,12 +1090,24 @@ static void batadv_wifi_net_device_event(unsigned long event, } } +/** + * batadv_hard_if_event() - netdevice notifier callback for hard interfaces + * @this: notifier block (unused) + * @event: the NETDEV_* event to handle + * @ptr: notifier info pointing to the affected net_device + * + * Dispatch netdevice events that affect potential or existing hard + * interfaces. Mesh interfaces are handled separately by + * batadv_hard_if_event_meshif(). + * + * Return: NOTIFY_DONE + */ static int batadv_hard_if_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); - struct batadv_hard_iface *hard_iface; struct batadv_hard_iface *primary_if = NULL; + struct batadv_hard_iface *hard_iface; struct batadv_priv *bat_priv; if (batadv_meshif_is_valid(net_dev)) diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c index 759fa29176db..b9a652bd523b 100644 --- a/net/batman-adv/hash.c +++ b/net/batman-adv/hash.c @@ -11,7 +11,10 @@ #include #include -/* clears the hash */ +/** + * batadv_hash_init() - clear all buckets of a hashtable + * @hash: hashtable to clear + */ static void batadv_hash_init(struct batadv_hashtable *hash) { u32 i; diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h index 86a2c20000dc..e67afe01304c 100644 --- a/net/batman-adv/hash.h +++ b/net/batman-adv/hash.h @@ -18,21 +18,35 @@ #include #include -/* callback to a compare function. should compare 2 element data for their - * keys +/** + * typedef batadv_hashdata_compare_cb - hash element comparison callback + * @node: hlist node of the element currently stored in the bucket + * @key: opaque payload to compare @node's key against * - * Return: true if same and false if not same + * Compare hash element by its keys. + * + * Return: true if both elements are considered equal, false otherwise. */ -typedef bool (*batadv_hashdata_compare_cb)(const struct hlist_node *, - const void *); +typedef bool (*batadv_hashdata_compare_cb)(const struct hlist_node *node, + const void *key); -/* the hashfunction +/** + * typedef batadv_hashdata_choose_cb - hash bucket selection callback + * @key: opaque payload whose key selects the bucket + * @size: number of buckets in the hash table * - * Return: an index based on the key in the data of the first argument and the - * size the second + * Return: bucket index derived from the key in @key and the table @size. */ -typedef u32 (*batadv_hashdata_choose_cb)(const void *, u32); -typedef void (*batadv_hashdata_free_cb)(struct hlist_node *, void *); +typedef u32 (*batadv_hashdata_choose_cb)(const void *key, u32 size); + +/** + * typedef batadv_hashdata_free_cb - hash element free callback + * @node: hlist node of the element being removed + * @arg: opaque caller-supplied argument forwarded from the caller + * + * Release a previously inserted hash element. + */ +typedef void (*batadv_hashdata_free_cb)(struct hlist_node *node, void *arg); /** * struct batadv_hashtable - Wrapper of simple hlist based hashtable @@ -78,11 +92,11 @@ static inline int batadv_hash_add(struct batadv_hashtable *hash, const void *data, struct hlist_node *data_node) { - u32 index; - int ret = -1; + spinlock_t *list_lock; /* spinlock to protect write access */ struct hlist_head *head; struct hlist_node *node; - spinlock_t *list_lock; /* spinlock to protect write access */ + int ret = -1; + u32 index; if (!hash) goto out; @@ -131,10 +145,10 @@ static inline void *batadv_hash_remove(struct batadv_hashtable *hash, batadv_hashdata_choose_cb choose, void *data) { - u32 index; struct hlist_node *node; struct hlist_head *head; void *data_save = NULL; + u32 index; index = choose(data, hash->size); head = &hash->table[index]; diff --git a/net/batman-adv/log.h b/net/batman-adv/log.h index a0d2b0d64b2b..9f3aed826dea 100644 --- a/net/batman-adv/log.h +++ b/net/batman-adv/log.h @@ -117,8 +117,12 @@ static inline void _batadv_dbg(int type __always_unused, */ #define batadv_info(net_dev, fmt, arg...) \ do { \ - struct net_device *_netdev = (net_dev); \ - struct batadv_priv *_batpriv = netdev_priv(_netdev); \ + struct batadv_priv *_batpriv; \ + struct net_device *_netdev; \ + \ + _netdev = (net_dev); \ + _batpriv = netdev_priv(_netdev); \ + \ batadv_dbg(BATADV_DBG_ALL, _batpriv, fmt, ## arg); \ pr_info("%s: " fmt, _netdev->name, ## arg); \ } while (0) @@ -131,8 +135,12 @@ static inline void _batadv_dbg(int type __always_unused, */ #define batadv_err(net_dev, fmt, arg...) \ do { \ - struct net_device *_netdev = (net_dev); \ - struct batadv_priv *_batpriv = netdev_priv(_netdev); \ + struct batadv_priv *_batpriv; \ + struct net_device *_netdev; \ + \ + _netdev = (net_dev); \ + _batpriv = netdev_priv(_netdev); \ + \ batadv_dbg(BATADV_DBG_ALL, _batpriv, fmt, ## arg); \ pr_err("%s: " fmt, _netdev->name, ## arg); \ } while (0) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 73becb054948..77597171d637 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -82,6 +82,14 @@ static char *batadv_uev_type_str[] = { "bla", }; +/** + * batadv_init() - batman-adv module init function + * + * Initialise the global state used by all mesh interfaces, register the + * netdevice notifier and the netlink/rtnl family. + * + * Return: 0 on success or negative error number in case of failure + */ static int __init batadv_init(void) { int ret; @@ -94,40 +102,69 @@ static int __init batadv_init(void) batadv_recv_handler_init(); - batadv_v_init(); - batadv_iv_init(); + ret = batadv_v_init(); + if (ret < 0) + goto err_tt; + + ret = batadv_iv_init(); + if (ret < 0) + goto err_v; + batadv_tp_meter_init(); + ret = batadv_wifi_net_devices_init(); + if (ret < 0) + goto err_iv; + batadv_event_workqueue = create_singlethread_workqueue("bat_events"); if (!batadv_event_workqueue) { ret = -ENOMEM; - goto err_create_wq; + goto err_wifi; } - ret = batadv_wifi_net_devices_init(); + ret = register_netdevice_notifier(&batadv_hard_if_notifier); if (ret < 0) - goto err_init_wifi; + goto err_wq; - register_netdevice_notifier(&batadv_hard_if_notifier); - rtnl_link_register(&batadv_link_ops); - batadv_netlink_register(); + ret = rtnl_link_register(&batadv_link_ops); + if (ret < 0) + goto err_notifier; + + ret = batadv_netlink_register(); + if (ret < 0) + goto err_rtnl; pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n", init_utsname()->release, BATADV_COMPAT_VERSION); return 0; -err_init_wifi: +err_rtnl: + rtnl_link_unregister(&batadv_link_ops); +err_notifier: + unregister_netdevice_notifier(&batadv_hard_if_notifier); +err_wq: destroy_workqueue(batadv_event_workqueue); batadv_event_workqueue = NULL; rcu_barrier(); - -err_create_wq: +err_wifi: + batadv_wifi_net_devices_deinit(); +err_iv: + batadv_iv_deinit(); +err_v: + batadv_v_deinit(); +err_tt: batadv_tt_cache_destroy(); return ret; } +/** + * batadv_exit() - batman-adv module exit function + * + * Unregister the netdevice notifier and tear down all global state allocated + * by batadv_init(). + */ static void __exit batadv_exit(void) { batadv_netlink_unregister(); @@ -354,10 +391,14 @@ int batadv_max_header_len(void) */ void batadv_skb_set_priority(struct sk_buff *skb, int offset) { - struct iphdr ip_hdr_tmp, *ip_hdr; - struct ipv6hdr ip6_hdr_tmp, *ip6_hdr; - struct ethhdr ethhdr_tmp, *ethhdr; - struct vlan_ethhdr *vhdr, vhdr_tmp; + struct vlan_ethhdr vhdr_tmp; + struct ipv6hdr ip6_hdr_tmp; + struct ethhdr ethhdr_tmp; + struct vlan_ethhdr *vhdr; + struct iphdr ip_hdr_tmp; + struct ipv6hdr *ip6_hdr; + struct ethhdr *ethhdr; + struct iphdr *ip_hdr; u32 prio; /* already set, do nothing */ @@ -398,6 +439,17 @@ void batadv_skb_set_priority(struct sk_buff *skb, int offset) skb->priority = prio + 256; } +/** + * batadv_recv_unhandled_packet() - default RX handler for unsupported packet + * types + * @skb: incoming packet + * @recv_if: interface on which the packet was received (unused) + * + * Drop incoming packets whose packet_type has no dedicated RX handler + * registered. + * + * Return: NET_RX_DROP + */ static int batadv_recv_unhandled_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) { @@ -406,10 +458,6 @@ static int batadv_recv_unhandled_packet(struct sk_buff *skb, return NET_RX_DROP; } -/* incoming packets with the batman ethertype received on any active hard - * interface - */ - /** * batadv_batman_skb_recv() - Handle incoming message from an hard interface * @skb: the received packet @@ -423,9 +471,9 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { - struct batadv_priv *bat_priv; struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_hard_iface *hard_iface; + struct batadv_priv *bat_priv; u8 idx; hard_iface = container_of(ptype, struct batadv_hard_iface, @@ -492,6 +540,13 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, return NET_RX_DROP; } +/** + * batadv_recv_handler_init() - initialise the RX handler dispatch table + * + * Initialise all entries of the RX handler table as either "unhandled" or with + * protocol indepentend handlers, and perform compile-time size sanity checks on + * all on-wire packet structs. + */ static void batadv_recv_handler_init(void) { int i; @@ -582,6 +637,11 @@ void batadv_recv_handler_unregister(u8 packet_type) * The caller must ensure that at least @header_len + ETH_HLEN bytes are * accessible after skb->data. * + * Warning: This function may reallocate the skb data buffer via + * pskb_may_pull()/... Any pointer into the skb data (e.g. obtained from skb->data + * or eth_hdr()) before this call must be considered invalid afterwards and has + * to be reacquired. + * * Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the * skb is vlan tagged. Otherwise BATADV_NO_FLAGS. */ @@ -650,9 +710,9 @@ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid) int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, enum batadv_uev_action action, const char *data) { - int ret = -ENOMEM; - struct kobject *bat_kobj; char *uevent_env[4] = { NULL, NULL, NULL, NULL }; + struct kobject *bat_kobj; + int ret = -ENOMEM; bat_kobj = &bat_priv->mesh_iface->dev.kobj; diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index 1dc6cfae9e9a..8e55b61dd2a6 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -57,6 +57,11 @@ * @skb: packet buffer which should be modified * @len: number of bytes to add * + * Warning: This function may reallocate the skb data buffer via + * skb_cow_head()/... Any pointer into the skb data (e.g. obtained + * from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * * Return: 0 on success or negative error number in case of failure */ int batadv_skb_head_push(struct sk_buff *skb, unsigned int len) @@ -87,7 +92,8 @@ int batadv_skb_head_push(struct sk_buff *skb, unsigned int len) */ static u64 batadv_sum_counter(struct batadv_priv *bat_priv, size_t idx) { - u64 *counters, sum = 0; + u64 *counters; + u64 sum = 0; int cpu; for_each_possible_cpu(cpu) { @@ -98,6 +104,15 @@ static u64 batadv_sum_counter(struct batadv_priv *bat_priv, size_t idx) return sum; } +/** + * batadv_interface_stats() - return netdev stats for a mesh interface + * @dev: the mesh interface to query + * + * Aggregate the per-CPU traffic counters into the standard netdev stats + * structure. + * + * Return: pointer to the populated net_device_stats structure + */ static struct net_device_stats *batadv_interface_stats(struct net_device *dev) { struct batadv_priv *bat_priv = netdev_priv(dev); @@ -111,6 +126,18 @@ static struct net_device_stats *batadv_interface_stats(struct net_device *dev) return stats; } +/** + * batadv_interface_set_mac_addr() - change the MAC address of a mesh + * interface + * @dev: the mesh interface to modify + * @p: pointer to a struct sockaddr holding the new MAC address + * + * Replace the MAC address of the mesh interface. If the mesh is already + * active, also update the local translation table entries for all configured + * VLANs so that the new MAC is announced and the old one is removed. + * + * Return: 0 on success or negative error number in case of failure + */ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) { struct batadv_priv *bat_priv = netdev_priv(dev); @@ -140,6 +167,16 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) return 0; } +/** + * batadv_interface_change_mtu() - change the MTU of a mesh interface + * @dev: the mesh interface to modify + * @new_mtu: requested new MTU value + * + * Validate that @new_mtu fits within the range supported by the configured + * hard interfaces and remember it as the user-configured MTU. + * + * Return: 0 on success or -EINVAL if @new_mtu is out of range + */ static int batadv_interface_change_mtu(struct net_device *dev, int new_mtu) { struct batadv_priv *bat_priv = netdev_priv(dev); @@ -166,31 +203,39 @@ static void batadv_interface_set_rx_mode(struct net_device *dev) { } +/** + * batadv_interface_tx() - transmit a frame on a mesh interface + * @skb: the frame to send + * @mesh_iface: the mesh interface the frame was queued on + * + * Return: NETDEV_TX_OK on success + */ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, struct net_device *mesh_iface) { - struct ethhdr *ethhdr; + static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, 0x00, 0x00}; + static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}; struct batadv_priv *bat_priv = netdev_priv(mesh_iface); + enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO; + enum batadv_forw_mode forw_mode = BATADV_FORW_BCAST; struct batadv_hard_iface *primary_if = NULL; struct batadv_bcast_packet *bcast_packet; - static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, - 0x00, 0x00}; - static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, - 0x00, 0x00}; - enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO; - u8 *dst_hint = NULL, chaddr[ETH_ALEN]; - struct vlan_ethhdr *vhdr; - unsigned int header_len = 0; - int data_len = skb->len, ret; - unsigned long brd_delay = 0; - bool do_bcast = false, client_added; - unsigned short vid; - u32 seqno; - int gw_mode; - enum batadv_forw_mode forw_mode = BATADV_FORW_BCAST; - int mcast_is_routable = 0; int network_offset = ETH_HLEN; + unsigned int header_len = 0; + unsigned long brd_delay = 0; + int mcast_is_routable = 0; + struct vlan_ethhdr *vhdr; + int data_len = skb->len; + struct ethhdr *ethhdr; + bool do_bcast = false; + u8 *dst_hint = NULL; + u8 chaddr[ETH_ALEN]; + unsigned short vid; + bool client_added; __be16 proto; + int gw_mode; + u32 seqno; + int ret; if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto dropped; @@ -408,8 +453,8 @@ void batadv_interface_rx(struct net_device *mesh_iface, struct sk_buff *skb, int hdr_size, struct batadv_orig_node *orig_node) { - struct batadv_bcast_packet *batadv_bcast_packet; struct batadv_priv *bat_priv = netdev_priv(mesh_iface); + struct batadv_bcast_packet *batadv_bcast_packet; struct vlan_ethhdr *vhdr; struct ethhdr *ethhdr; unsigned short vid; @@ -523,7 +568,8 @@ void batadv_meshif_vlan_release(struct kref *ref) struct batadv_meshif_vlan *batadv_meshif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid) { - struct batadv_meshif_vlan *vlan_tmp, *vlan = NULL; + struct batadv_meshif_vlan *vlan = NULL; + struct batadv_meshif_vlan *vlan_tmp; rcu_read_lock(); hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->meshif_vlan_list, list) { @@ -741,10 +787,10 @@ static void batadv_set_lockdep_class(struct net_device *dev) */ static int batadv_meshif_init_late(struct net_device *dev) { + size_t cnt_len = sizeof(u64) * BATADV_CNT_NUM; struct batadv_priv *bat_priv; u32 random_seqno; int ret; - size_t cnt_len = sizeof(u64) * BATADV_CNT_NUM; batadv_set_lockdep_class(dev); @@ -883,6 +929,11 @@ static const struct net_device_ops batadv_netdev_ops = { .ndo_del_slave = batadv_meshif_slave_del, }; +/** + * batadv_get_drvinfo() - ethtool driver info handler for mesh interfaces + * @dev: the mesh interface (unused) + * @info: ethtool_drvinfo struct to populate + */ static void batadv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -943,6 +994,12 @@ static const struct { #endif }; +/** + * batadv_get_strings() - ethtool string handler for mesh interfaces + * @dev: the mesh interface (unused) + * @stringset: ethtool string set to retrieve + * @data: buffer to copy the requested string set into + */ static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data) { if (stringset == ETH_SS_STATS) @@ -950,6 +1007,12 @@ static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data) sizeof(batadv_counters_strings)); } +/** + * batadv_get_ethtool_stats() - ethtool stats handler for mesh interfaces + * @dev: the mesh interface to query + * @stats: ethtool_stats struct (unused) + * @data: destination array for the gathered counter values + */ static void batadv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { @@ -960,6 +1023,14 @@ static void batadv_get_ethtool_stats(struct net_device *dev, data[i] = batadv_sum_counter(bat_priv, i); } +/** + * batadv_get_sset_count() - ethtool stringset size handler for mesh interfaces + * @dev: the mesh interface (unused) + * @stringset: ethtool string set to query + * + * Return: number of entries in @stringset or -EOPNOTSUPP if @stringset is not + * supported + */ static int batadv_get_sset_count(struct net_device *dev, int stringset) { if (stringset == ETH_SS_STATS) diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 1c5315e55c04..82fd527b61c0 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -274,8 +274,9 @@ static struct batadv_mcast_mla_flags batadv_mcast_mla_flags_get(struct batadv_priv *bat_priv) { struct net_device *dev = bat_priv->mesh_iface; - struct batadv_mcast_querier_state *qr4, *qr6; struct batadv_mcast_mla_flags mla_flags; + struct batadv_mcast_querier_state *qr4; + struct batadv_mcast_querier_state *qr6; struct net_device *bridge; bridge = batadv_mcast_get_bridge(dev); @@ -521,7 +522,8 @@ batadv_mcast_mla_meshif_get(struct net_device *dev, struct batadv_mcast_mla_flags *flags) { struct net_device *bridge = batadv_mcast_get_bridge(dev); - int ret4, ret6 = 0; + int ret6 = 0; + int ret4; if (bridge) dev = bridge; @@ -585,10 +587,11 @@ static int batadv_mcast_mla_bridge_get(struct net_device *dev, struct batadv_mcast_mla_flags *flags) { struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list); - struct br_ip_list *br_ip_entry, *tmp; u8 tvlv_flags = flags->tvlv_flags; + struct br_ip_list *br_ip_entry; struct batadv_hw_addr *new; u8 mcast_addr[ETH_ALEN]; + struct br_ip_list *tmp; int ret; /* we don't need to detect these devices/listeners, the IGMP/MLD @@ -935,8 +938,8 @@ static void __batadv_mcast_mla_update(struct batadv_priv *bat_priv) */ static void batadv_mcast_mla_update(struct work_struct *work) { - struct delayed_work *delayed_work; struct batadv_priv_mcast *priv_mcast; + struct delayed_work *delayed_work; struct batadv_priv *bat_priv; delayed_work = to_delayed_work(work); @@ -951,7 +954,10 @@ static void batadv_mcast_mla_update(struct work_struct *work) * batadv_mcast_is_report_ipv4() - check for IGMP reports * @skb: the ethernet frame destined for the mesh * - * This call might reallocate skb data. + * Warning: This function may reallocate the skb data buffer via + * ip_mc_check_igmp()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. * * Checks whether the given frame is a valid IGMP report. * @@ -1017,7 +1023,10 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv, * batadv_mcast_is_report_ipv6() - check for MLD reports * @skb: the ethernet frame destined for the mesh * - * This call might reallocate skb data. + * Warning: This function may reallocate the skb data buffer via + * ipv6_mc_check_mld()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. * * Checks whether the given frame is a valid MLD report. * @@ -1223,10 +1232,14 @@ enum batadv_forw_mode batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short vid, int *is_routable) { - int ret, tt_count, ip_count, unsnoop_count, total_count; bool is_unsnoopable = false; struct ethhdr *ethhdr; + int unsnoop_count; int rtr_count = 0; + int total_count; + int tt_count; + int ip_count; + int ret; ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable, is_routable); @@ -1301,13 +1314,11 @@ static int batadv_mcast_forw_tt(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short vid) { - int ret = NET_XMIT_SUCCESS; - struct sk_buff *newskb; - struct batadv_tt_orig_list_entry *orig_entry; - struct batadv_tt_global_entry *tt_global; const u8 *addr = eth_hdr(skb)->h_dest; + int ret = NET_XMIT_SUCCESS; + struct sk_buff *newskb; tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global) @@ -1602,8 +1613,8 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, u8 mcast_flags) { - struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node; struct hlist_head *head = &bat_priv->mcast.want_all_unsnoopables_list; + struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node; lockdep_assert_held(&orig->mcast_handler_lock); @@ -1647,8 +1658,8 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, u8 mcast_flags) { - struct hlist_node *node = &orig->mcast_want_all_ipv4_node; struct hlist_head *head = &bat_priv->mcast.want_all_ipv4_list; + struct hlist_node *node = &orig->mcast_want_all_ipv4_node; lockdep_assert_held(&orig->mcast_handler_lock); @@ -1692,8 +1703,8 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, u8 mcast_flags) { - struct hlist_node *node = &orig->mcast_want_all_ipv6_node; struct hlist_head *head = &bat_priv->mcast.want_all_ipv6_list; + struct hlist_node *node = &orig->mcast_want_all_ipv6_node; lockdep_assert_held(&orig->mcast_handler_lock); @@ -1737,8 +1748,8 @@ static void batadv_mcast_want_rtr4_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, u8 mcast_flags) { - struct hlist_node *node = &orig->mcast_want_all_rtr4_node; struct hlist_head *head = &bat_priv->mcast.want_all_rtr4_list; + struct hlist_node *node = &orig->mcast_want_all_rtr4_node; lockdep_assert_held(&orig->mcast_handler_lock); @@ -1782,8 +1793,8 @@ static void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, u8 mcast_flags) { - struct hlist_node *node = &orig->mcast_want_all_rtr6_node; struct hlist_head *head = &bat_priv->mcast.want_all_rtr6_list; + struct hlist_node *node = &orig->mcast_want_all_rtr6_node; lockdep_assert_held(&orig->mcast_handler_lock); diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c index 1404a3b7adfb..bae2a8110976 100644 --- a/net/batman-adv/multicast_forw.c +++ b/net/batman-adv/multicast_forw.c @@ -195,8 +195,8 @@ static int batadv_mcast_forw_push_dests_list(struct batadv_priv *bat_priv, unsigned short *num_dests, unsigned short *tvlv_len) { - struct hlist_node *node; struct batadv_orig_node *orig_node; + struct hlist_node *node; rcu_read_lock(); __hlist_for_each_rcu(node, head) { @@ -232,12 +232,9 @@ batadv_mcast_forw_push_tt(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short *tvlv_len) { struct batadv_tt_orig_list_entry *orig_entry; - struct batadv_tt_global_entry *tt_global; const u8 *addr = eth_hdr(skb)->h_dest; - - /* ok */ - int ret = true; + int ret = true; /* ok */ tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global) @@ -368,7 +365,8 @@ static void batadv_mcast_forw_scrape(struct sk_buff *skb, unsigned short offset, unsigned short len) { - char *to, *from; + char *from; + char *to; SKB_LINEAR_ASSERT(skb); @@ -411,7 +409,8 @@ static bool batadv_mcast_forw_push_insert_padding(struct sk_buff *skb, unsigned short *tvlv_len) { unsigned short offset = *tvlv_len; - char *to, *from = skb->data; + char *from = skb->data; + char *to; to = batadv_mcast_forw_push_padding(skb, tvlv_len); if (!to) @@ -933,8 +932,9 @@ static int batadv_mcast_forw_packet(struct batadv_priv *bat_priv, unsigned int tvlv_len; unsigned long offset; bool xmitted = false; - u8 *dest, *next_dest; + u8 *next_dest; u16 num_dests; + u8 *dest; int ret; /* (at least) TVLV part needs to be linearized */ @@ -1080,6 +1080,11 @@ unsigned int batadv_mcast_forw_packet_hdrlen(unsigned int num_dests) * Tries to expand an skb's headroom so that its head to tail is 1298 * bytes (minimum IPv6 MTU + vlan ethernet header size) large. * + * Warning: This function may reallocate the skb data buffer via + * skb_cow()/skb_linearize()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be + * considered invalid afterwards and has to be reacquired. + * * Return: -EINVAL if the given skb's length is too large or -ENOMEM on memory * allocation failure. Otherwise, on success, zero is returned. */ @@ -1120,6 +1125,11 @@ static int batadv_mcast_forw_expand_head(struct batadv_priv *bat_priv, * that signaled interest in it, that is either via the translation table or the * according want-all flags, is attached accordingly. * + * Warning: This function may reallocate the skb data buffer via + * batadv_mcast_forw_expand_head()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be + * considered invalid afterwards and has to be reacquired. + * * Return: true on success, false otherwise. */ bool batadv_mcast_forw_push(struct batadv_priv *bat_priv, struct sk_buff *skb, diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index d2bc48c70714..107647c9bada 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -52,9 +52,15 @@ struct genl_family batadv_netlink_family; -/* multicast groups */ +/** + * enum batadv_netlink_multicast_groups - batman-adv generic netlink multicast + * groups + */ enum batadv_netlink_multicast_groups { + /** @BATADV_NL_MCGRP_CONFIG: configuration change notifications */ BATADV_NL_MCGRP_CONFIG, + + /** @BATADV_NL_MCGRP_TPMETER: throughput meter result notifications */ BATADV_NL_MCGRP_TPMETER, }; @@ -746,8 +752,8 @@ static int batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info) { struct batadv_priv *bat_priv = info->user_ptr[0]; - u8 *dst; int ret = 0; + u8 *dst; if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS]) return -EINVAL; @@ -953,10 +959,10 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, static int batadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb) { - struct net_device *mesh_iface; - struct batadv_hard_iface *hard_iface; - struct batadv_priv *bat_priv; int portid = NETLINK_CB(cb->skb).portid; + struct batadv_hard_iface *hard_iface; + struct net_device *mesh_iface; + struct batadv_priv *bat_priv; int skip = cb->args[0]; struct list_head *iter; int i = 0; @@ -1550,14 +1556,18 @@ struct genl_family batadv_netlink_family __ro_after_init = { /** * batadv_netlink_register() - register batadv genl netlink family + * + * Return: 0 on success or negative error number in case of failure */ -void __init batadv_netlink_register(void) +int __init batadv_netlink_register(void) { int ret; ret = genl_register_family(&batadv_netlink_family); if (ret) pr_warn("unable to register netlink family\n"); + + return ret; } /** diff --git a/net/batman-adv/netlink.h b/net/batman-adv/netlink.h index 4eae9e5ff135..f92d3ea7d06c 100644 --- a/net/batman-adv/netlink.h +++ b/net/batman-adv/netlink.h @@ -12,7 +12,7 @@ #include #include -void batadv_netlink_register(void); +int batadv_netlink_register(void); void batadv_netlink_unregister(void); struct net_device *batadv_netlink_get_meshif(struct netlink_callback *cb); struct batadv_hard_iface * diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 48f837cf665a..f06583ef9b3f 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -53,8 +53,9 @@ struct batadv_orig_node * batadv_orig_hash_find(struct batadv_priv *bat_priv, const void *data) { struct batadv_hashtable *hash = bat_priv->orig_hash; + struct batadv_orig_node *orig_node_tmp = NULL; + struct batadv_orig_node *orig_node; struct hlist_head *head; - struct batadv_orig_node *orig_node, *orig_node_tmp = NULL; int index; if (!hash) @@ -108,7 +109,8 @@ struct batadv_orig_node_vlan * batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, unsigned short vid) { - struct batadv_orig_node_vlan *vlan = NULL, *tmp; + struct batadv_orig_node_vlan *vlan = NULL; + struct batadv_orig_node_vlan *tmp; rcu_read_lock(); hlist_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) { @@ -282,9 +284,9 @@ void batadv_hardif_neigh_release(struct kref *ref) */ void batadv_neigh_node_release(struct kref *ref) { - struct hlist_node *node_tmp; - struct batadv_neigh_node *neigh_node; struct batadv_neigh_ifinfo *neigh_ifinfo; + struct batadv_neigh_node *neigh_node; + struct hlist_node *node_tmp; neigh_node = container_of(ref, struct batadv_neigh_node, refcount); @@ -314,8 +316,8 @@ struct batadv_neigh_node * batadv_orig_router_get(struct batadv_orig_node *orig_node, const struct batadv_hard_iface *if_outgoing) { - struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *router = NULL; + struct batadv_orig_ifinfo *orig_ifinfo; rcu_read_lock(); hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) { @@ -373,7 +375,8 @@ struct batadv_orig_ifinfo * batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_outgoing) { - struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL; + struct batadv_orig_ifinfo *orig_ifinfo = NULL; + struct batadv_orig_ifinfo *tmp; rcu_read_lock(); hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list, @@ -451,8 +454,8 @@ struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing) { - struct batadv_neigh_ifinfo *neigh_ifinfo = NULL, - *tmp_neigh_ifinfo; + struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; + struct batadv_neigh_ifinfo *tmp_neigh_ifinfo; rcu_read_lock(); hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list, @@ -530,7 +533,8 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node, const struct batadv_hard_iface *hard_iface, const u8 *addr) { - struct batadv_neigh_node *tmp_neigh_node, *res = NULL; + struct batadv_neigh_node *tmp_neigh_node; + struct batadv_neigh_node *res = NULL; rcu_read_lock(); hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) { @@ -634,7 +638,8 @@ struct batadv_hardif_neigh_node * batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface, const u8 *neigh_addr) { - struct batadv_hardif_neigh_node *tmp_hardif_neigh, *hardif_neigh = NULL; + struct batadv_hardif_neigh_node *hardif_neigh = NULL; + struct batadv_hardif_neigh_node *tmp_hardif_neigh; rcu_read_lock(); hlist_for_each_entry_rcu(tmp_hardif_neigh, @@ -668,8 +673,8 @@ batadv_neigh_node_create(struct batadv_orig_node *orig_node, struct batadv_hard_iface *hard_iface, const u8 *neigh_addr) { - struct batadv_neigh_node *neigh_node; struct batadv_hardif_neigh_node *hardif_neigh = NULL; + struct batadv_neigh_node *neigh_node; spin_lock_bh(&orig_node->neigh_list_lock); @@ -753,7 +758,8 @@ batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node, */ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct batadv_hard_iface *primary_if, *hard_iface; + struct batadv_hard_iface *primary_if; + struct batadv_hard_iface *hard_iface; struct net_device *mesh_iface; struct batadv_priv *bat_priv; int ret; @@ -850,12 +856,12 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) */ void batadv_orig_node_release(struct kref *ref) { - struct hlist_node *node_tmp; + struct batadv_orig_ifinfo *last_candidate; + struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *neigh_node; struct batadv_orig_node *orig_node; - struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_orig_node_vlan *vlan; - struct batadv_orig_ifinfo *last_candidate; + struct hlist_node *node_tmp; orig_node = container_of(ref, struct batadv_orig_node, refcount); @@ -898,11 +904,11 @@ void batadv_orig_node_release(struct kref *ref) */ void batadv_originator_free(struct batadv_priv *bat_priv) { + spinlock_t *list_lock; /* spinlock to protect write access */ struct batadv_hashtable *hash = bat_priv->orig_hash; + struct batadv_orig_node *orig_node; struct hlist_node *node_tmp; struct hlist_head *head; - spinlock_t *list_lock; /* spinlock to protect write access */ - struct batadv_orig_node *orig_node; u32 i; if (!hash) @@ -1109,11 +1115,11 @@ static bool batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { - struct hlist_node *node_tmp; + struct batadv_hard_iface *if_incoming; struct batadv_neigh_node *neigh_node; + struct hlist_node *node_tmp; bool neigh_purged = false; unsigned long last_seen; - struct batadv_hard_iface *if_incoming; spin_lock_bh(&orig_node->neigh_list_lock); @@ -1167,8 +1173,9 @@ batadv_find_best_neighbor(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_outgoing) { - struct batadv_neigh_node *best = NULL, *neigh; struct batadv_algo_ops *bao = bat_priv->algo_ops; + struct batadv_neigh_node *best = NULL; + struct batadv_neigh_node *neigh; rcu_read_lock(); hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) { @@ -1203,8 +1210,9 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, { struct batadv_neigh_node *best_neigh_node; struct batadv_hard_iface *hard_iface; - bool changed_ifinfo, changed_neigh; struct list_head *iter; + bool changed_ifinfo; + bool changed_neigh; if (batadv_has_timed_out(orig_node->last_seen, 2 * BATADV_PURGE_TIMEOUT)) { @@ -1256,11 +1264,11 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, */ void batadv_purge_orig_ref(struct batadv_priv *bat_priv) { + spinlock_t *list_lock; /* spinlock to protect write access */ struct batadv_hashtable *hash = bat_priv->orig_hash; + struct batadv_orig_node *orig_node; struct hlist_node *node_tmp; struct hlist_head *head; - spinlock_t *list_lock; /* spinlock to protect write access */ - struct batadv_orig_node *orig_node; u32 i; if (!hash) @@ -1295,6 +1303,13 @@ void batadv_purge_orig_ref(struct batadv_priv *bat_priv) batadv_gw_election(bat_priv); } +/** + * batadv_purge_orig() - periodic worker to purge stale originator entries + * @work: delayed work embedded in the bat_priv + * + * Invoke batadv_purge_orig_ref() to drop stale originators and reschedule the + * next run after BATADV_ORIG_WORK_PERIOD milliseconds. + */ static void batadv_purge_orig(struct work_struct *work) { struct delayed_work *delayed_work; @@ -1318,7 +1333,8 @@ static void batadv_purge_orig(struct work_struct *work) */ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct batadv_hard_iface *primary_if, *hard_iface; + struct batadv_hard_iface *primary_if; + struct batadv_hard_iface *hard_iface; struct net_device *mesh_iface; struct batadv_priv *bat_priv; int ret; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index bbd40fe3a8e5..6442f5d0cc93 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -172,6 +172,11 @@ bool batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff, * @hard_iface: incoming hard interface * @header_len: minimal header length of packet type * + * Warning: This function may reallocate the skb data buffer via + * skb_cow()/skb_linearize()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be + * considered invalid afterwards and has to be reacquired. + * * Return: true when management preconditions are met, false otherwise */ bool batadv_check_management_packet(struct sk_buff *skb, @@ -263,8 +268,7 @@ static bool batadv_skb_decrement_ttl(struct sk_buff *skb) * @bat_priv: the bat priv with all the mesh interface information * @skb: icmp packet to process * - * Return: NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP - * otherwise. + * Return: NET_RX_SUCCESS on success or NET_RX_DROP in case of failure */ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, struct sk_buff *skb) @@ -272,7 +276,8 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if = NULL; struct batadv_orig_node *orig_node = NULL; struct batadv_icmp_header *icmph; - int res, ret = NET_RX_DROP; + int ret = NET_RX_DROP; + int res; icmph = (struct batadv_icmp_header *)skb->data; @@ -328,13 +333,24 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, return ret; } +/** + * batadv_recv_icmp_ttl_exceeded() - handle an ICMP packet that hit TTL 0 + * @bat_priv: the bat priv with all the mesh interface information + * @skb: ICMP packet whose TTL has expired + * + * For traceroute-style ICMP echo requests, send a TTL exceeded reply back to + * the source. Other ICMP types are simply dropped. + * + * Return: NET_RX_SUCCESS if the reply was queued, NET_RX_DROP otherwise + */ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, struct sk_buff *skb) { struct batadv_hard_iface *primary_if = NULL; struct batadv_orig_node *orig_node = NULL; struct batadv_icmp_packet *icmp_packet; - int res, ret = NET_RX_DROP; + int ret = NET_RX_DROP; + int res; icmp_packet = (struct batadv_icmp_packet *)skb->data; @@ -366,8 +382,8 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, icmp_packet->ttl = BATADV_TTL; res = batadv_send_skb_to_orig(skb, orig_node, NULL); - if (res == NET_RX_SUCCESS) - ret = NET_XMIT_SUCCESS; + if (res == NET_XMIT_SUCCESS) + ret = NET_RX_SUCCESS; /* skb was consumed */ skb = NULL; @@ -392,12 +408,13 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) { struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); - struct batadv_icmp_header *icmph; - struct batadv_icmp_packet_rr *icmp_packet_rr; - struct ethhdr *ethhdr; - struct batadv_orig_node *orig_node = NULL; int hdr_size = sizeof(struct batadv_icmp_header); - int res, ret = NET_RX_DROP; + struct batadv_icmp_packet_rr *icmp_packet_rr; + struct batadv_orig_node *orig_node = NULL; + struct batadv_icmp_header *icmph; + struct ethhdr *ethhdr; + int ret = NET_RX_DROP; + int res; /* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) @@ -576,15 +593,17 @@ batadv_find_router(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, struct batadv_hard_iface *recv_if) { - struct batadv_algo_ops *bao = bat_priv->algo_ops; struct batadv_neigh_node *first_candidate_router = NULL; struct batadv_neigh_node *next_candidate_router = NULL; - struct batadv_neigh_node *router, *cand_router = NULL; struct batadv_neigh_node *last_cand_router = NULL; - struct batadv_orig_ifinfo *cand, *first_candidate = NULL; + struct batadv_orig_ifinfo *first_candidate = NULL; + struct batadv_algo_ops *bao = bat_priv->algo_ops; struct batadv_orig_ifinfo *next_candidate = NULL; + struct batadv_neigh_node *cand_router = NULL; struct batadv_orig_ifinfo *last_candidate; bool last_candidate_found = false; + struct batadv_neigh_node *router; + struct batadv_orig_ifinfo *cand; if (!orig_node) return NULL; @@ -706,15 +725,29 @@ batadv_find_router(struct batadv_priv *bat_priv, return router; } +/** + * batadv_route_unicast_packet() - forward a unicast packet towards its + * destination originator + * @skb: the received unicast packet + * @recv_if: interface on which the packet was received + * + * Decrement the TTL, look up the originator for the destination address and + * hand the packet over to batadv_send_skb_to_orig() for transmission. Drop + * the packet when the TTL is exhausted or no route exists. + * + * Return: NET_RX_SUCCESS if the packet was forwarded, NET_RX_DROP otherwise + */ static int batadv_route_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) { struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); - struct batadv_orig_node *orig_node = NULL; struct batadv_unicast_packet *unicast_packet; + struct batadv_orig_node *orig_node = NULL; struct ethhdr *ethhdr = eth_hdr(skb); - int res, hdr_len, ret = NET_RX_DROP; + int ret = NET_RX_DROP; unsigned int len; + int hdr_len; + int res; unicast_packet = (struct batadv_unicast_packet *)skb->data; @@ -797,10 +830,10 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, struct batadv_unicast_packet *unicast_packet, u8 *dst_addr, unsigned short vid) { - struct batadv_orig_node *orig_node = NULL; struct batadv_hard_iface *primary_if = NULL; - bool ret = false; + struct batadv_orig_node *orig_node = NULL; const u8 *orig_addr; + bool ret = false; u8 orig_ttvn; if (batadv_is_my_client(bat_priv, dst_addr, vid)) { @@ -836,16 +869,31 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, return ret; } +/** + * batadv_check_unicast_ttvn() - check and adjust the TTVN of a unicast packet + * @bat_priv: the bat priv with all the mesh interface information + * @skb: the unicast packet to check + * @hdr_len: length of the unicast header preceding the payload + * + * Warning: This function may reallocate the skb data buffer via + * pskb_may_pull()/batadv_get_vid()/... Any pointer into the skb data (e.g. + * obtained from skb->data or eth_hdr()) before this call must be considered + * invalid afterwards and has to be reacquired. + * + * Return: true if the packet may be processed further, false if has to be + * dropped by the caller + */ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, struct sk_buff *skb, int hdr_len) { struct batadv_unicast_packet *unicast_packet; struct batadv_hard_iface *primary_if; struct batadv_orig_node *orig_node; - u8 curr_ttvn, old_ttvn; struct ethhdr *ethhdr; unsigned short vid; int is_old_ttvn; + u8 curr_ttvn; + u8 old_ttvn; /* check if there is enough data before accessing it */ if (!pskb_may_pull(skb, hdr_len + ETH_HLEN)) @@ -955,15 +1003,15 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, * @skb: unicast tvlv packet to process * @recv_if: pointer to interface this packet was received on * - * Return: NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP - * otherwise. + * Return: NET_RX_SUCCESS on success or NET_RX_DROP in case of failure */ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) { - struct batadv_unicast_packet *unicast_packet; struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); - int check, hdr_size = sizeof(*unicast_packet); + struct batadv_unicast_packet *unicast_packet; + int hdr_size = sizeof(*unicast_packet); + int check; check = batadv_check_unicast_packet(bat_priv, skb, hdr_size); if (check < 0) @@ -992,14 +1040,18 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) { struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); - struct batadv_unicast_packet *unicast_packet; struct batadv_unicast_4addr_packet *unicast_4addr_packet; - u8 *orig_addr, *orig_addr_gw; - struct batadv_orig_node *orig_node = NULL, *orig_node_gw = NULL; - int check, hdr_size = sizeof(*unicast_packet); + struct batadv_unicast_packet *unicast_packet; + struct batadv_orig_node *orig_node_gw = NULL; + struct batadv_orig_node *orig_node = NULL; + int hdr_size = sizeof(*unicast_packet); enum batadv_subtype subtype; int ret = NET_RX_DROP; - bool is4addr, is_gw; + u8 *orig_addr_gw; + u8 *orig_addr; + bool is4addr; + bool is_gw; + int check; unicast_packet = (struct batadv_unicast_packet *)skb->data; is4addr = unicast_packet->packet_type == BATADV_UNICAST_4ADDR; @@ -1089,18 +1141,17 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, * @skb: unicast tvlv packet to process * @recv_if: pointer to interface this packet was received on * - * Return: NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP - * otherwise. + * Return: NET_RX_SUCCESS on success or NET_RX_DROP in case of failure */ int batadv_recv_unicast_tvlv(struct sk_buff *skb, struct batadv_hard_iface *recv_if) { struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; - unsigned char *tvlv_buff; - u16 tvlv_buff_len; int hdr_size = sizeof(*unicast_tvlv_packet); + unsigned char *tvlv_buff; int ret = NET_RX_DROP; + u16 tvlv_buff_len; if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) goto free_skb; @@ -1146,7 +1197,7 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb, * the assembled packet will exceed our MTU; 2) Buffer fragment, if we still * lack further fragments; 3) Merge fragments, if we have all needed parts. * - * Return: NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise. + * Return: NET_RX_SUCCESS on success or NET_RX_DROP in case of failure */ int batadv_recv_frag_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) @@ -1215,8 +1266,8 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); struct batadv_orig_node *orig_node = NULL; struct batadv_bcast_packet *bcast_packet; - struct ethhdr *ethhdr; int hdr_size = sizeof(*bcast_packet); + struct ethhdr *ethhdr; s32 seq_diff; u32 seqno; int ret; @@ -1334,7 +1385,9 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, * contents of its TVLV forwards it and/or decapsulates it to hand it to the * mesh interface. * - * Return: NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise. + * Return: NET_RX_SUCCESS if the skb was locally received, NET_RX_DROP otherwise + * or a negative errno code when the multicast tracker TVLV could not be + * processed */ int batadv_recv_mcast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 7f449338a490..929b6dd34c10 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -271,8 +271,8 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, int packet_subtype) { - struct batadv_hard_iface *primary_if; struct batadv_unicast_4addr_packet *uc_4addr_packet; + struct batadv_hard_iface *primary_if; bool ret = false; primary_if = batadv_primary_if_get_selected(bat_priv); @@ -322,8 +322,9 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv, unsigned short vid) { struct batadv_unicast_packet *unicast_packet; - struct ethhdr *ethhdr; int ret = NET_XMIT_DROP; + struct ethhdr *ethhdr; + int res; if (!orig_node) goto out; @@ -360,7 +361,10 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv, if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) unicast_packet->ttvn = unicast_packet->ttvn - 1; - ret = batadv_send_skb_to_orig(skb, orig_node, NULL); + res = batadv_send_skb_to_orig(skb, orig_node, NULL); + if (res == NET_XMIT_SUCCESS) + ret = NET_XMIT_SUCCESS; + /* skb was consumed */ skb = NULL; @@ -394,7 +398,8 @@ int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batadv_orig_node *orig_node; - u8 *src, *dst; + u8 *src; + u8 *dst; int ret; src = ethhdr->h_source; diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c index 00467aa79de9..022eb13e8ec4 100644 --- a/net/batman-adv/tp_meter.c +++ b/net/batman-adv/tp_meter.c @@ -221,9 +221,9 @@ static void batadv_tp_batctl_notify(enum batadv_tp_meter_reason reason, unsigned long start_time, u64 total_sent, u32 cookie) { + u32 total_bytes; u32 test_time; u8 result; - u32 total_bytes; if (!batadv_tp_is_error(reason)) { result = BATADV_TP_REASON_COMPLETE; @@ -267,7 +267,8 @@ static void batadv_tp_batctl_error_notify(enum batadv_tp_meter_reason reason, static struct batadv_tp_sender * batadv_tp_list_find_sender(struct batadv_priv *bat_priv, const u8 *dst) { - struct batadv_tp_sender *pos, *tp_vars = NULL; + struct batadv_tp_sender *tp_vars = NULL; + struct batadv_tp_sender *pos; rcu_read_lock(); hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) { @@ -332,7 +333,8 @@ static struct batadv_tp_sender * batadv_tp_list_find_sender_session(struct batadv_priv *bat_priv, const u8 *dst, const u8 *session) { - struct batadv_tp_sender *pos, *tp_vars = NULL; + struct batadv_tp_sender *tp_vars = NULL; + struct batadv_tp_sender *pos; rcu_read_lock(); hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) { @@ -578,8 +580,8 @@ static void batadv_tp_sender_timeout(struct timer_list *t) static void batadv_tp_fill_prerandom(struct batadv_tp_sender *tp_vars, u8 *buf, size_t nbytes) { - u32 local_offset; size_t bytes_inbuf; + u32 local_offset; size_t to_copy; size_t pos = 0; @@ -625,9 +627,9 @@ static int batadv_tp_send_msg(struct batadv_tp_sender *tp_vars, const u8 *src, { struct batadv_icmp_tp_packet *icmp; struct sk_buff *skb; - int r; - u8 *data; size_t data_len; + u8 *data; + int r; skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); if (unlikely(!skb)) @@ -864,7 +866,8 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv, static bool batadv_tp_avail(struct batadv_tp_sender *tp_vars, size_t payload_len) { - u32 win_left, win_limit; + u32 win_limit; + u32 win_left; spin_lock_bh(&tp_vars->cc_lock); @@ -910,14 +913,16 @@ static int batadv_tp_wait_available(struct batadv_tp_sender *tp_vars, size_t ple */ static int batadv_tp_send(void *arg) { - struct batadv_tp_sender *tp_vars = arg; - struct batadv_priv *bat_priv = tp_vars->common.bat_priv; struct batadv_hard_iface *primary_if = NULL; struct batadv_orig_node *orig_node = NULL; - size_t payload_len, packet_len; + struct batadv_tp_sender *tp_vars = arg; + struct batadv_priv *bat_priv; + size_t payload_len; + size_t packet_len; u32 last_sent; int err = 0; + bat_priv = tp_vars->common.bat_priv; orig_node = batadv_orig_hash_find(bat_priv, tp_vars->common.other_end); if (unlikely(!orig_node)) { err = BATADV_TP_REASON_DST_UNREACHABLE; @@ -1005,8 +1010,8 @@ static int batadv_tp_send(void *arg) */ static void batadv_tp_start_kthread(struct batadv_tp_sender *tp_vars) { - struct task_struct *kthread; struct batadv_priv *bat_priv = tp_vars->common.bat_priv; + struct task_struct *kthread; u32 session_cookie; kref_get(&tp_vars->common.refcount); @@ -1042,9 +1047,9 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, u32 test_length, u32 *cookie) { struct batadv_tp_sender *tp_vars; + u32 session_cookie; u8 session_id[2]; u8 icmp_uid; - u32 session_cookie; get_random_bytes(session_id, sizeof(session_id)); get_random_bytes(&icmp_uid, 1); @@ -1211,7 +1216,8 @@ static struct batadv_tp_receiver * batadv_tp_list_find_receiver_session(struct batadv_priv *bat_priv, const u8 *dst, const u8 *session) { - struct batadv_tp_receiver *pos, *tp_vars = NULL; + struct batadv_tp_receiver *tp_vars = NULL; + struct batadv_tp_receiver *pos; rcu_read_lock(); hlist_for_each_entry_rcu(pos, &bat_priv->tp_receiver_list, common.list) { @@ -1296,7 +1302,8 @@ static void batadv_tp_reset_receiver_timer(struct batadv_tp_receiver *tp_vars) static void batadv_tp_receiver_shutdown(struct timer_list *t) { struct batadv_tp_receiver *tp_vars = timer_container_of(tp_vars, t, common.timer); - struct batadv_tp_unacked *un, *safe; + struct batadv_tp_unacked *safe; + struct batadv_tp_unacked *un; struct batadv_priv *bat_priv; bat_priv = tp_vars->common.bat_priv; @@ -1351,7 +1358,8 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst, struct batadv_orig_node *orig_node; struct batadv_icmp_tp_packet *icmp; struct sk_buff *skb; - int r, ret; + int ret; + int r; orig_node = batadv_orig_hash_find(bat_priv, dst); if (unlikely(!orig_node)) { @@ -1528,7 +1536,8 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars, static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars) __must_hold(&tp_vars->ack_seqno_lock) { - struct batadv_tp_unacked *un, *safe; + struct batadv_tp_unacked *safe; + struct batadv_tp_unacked *un; u32 to_ack; /* go through the unacked packet list and possibly ACK them as diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index dae5e1d8c038..68f79853032e 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -128,8 +128,10 @@ static struct batadv_tt_common_entry * batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr, unsigned short vid) { + struct batadv_tt_common_entry *tt_tmp = NULL; + struct batadv_tt_common_entry to_search; + struct batadv_tt_common_entry *tt; struct hlist_head *head; - struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; u32 index; if (!hash) @@ -173,8 +175,8 @@ static struct batadv_tt_local_entry * batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid) { - struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_local_entry *tt_local_entry = NULL; + struct batadv_tt_common_entry *tt_common_entry; tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, vid); @@ -198,8 +200,8 @@ struct batadv_tt_global_entry * batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid) { - struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_global_entry *tt_global_entry = NULL; + struct batadv_tt_common_entry *tt_common_entry; tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, vid); @@ -421,10 +423,13 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry, u8 event_flags) { - struct batadv_tt_change_node *tt_change_node, *entry, *safe; struct batadv_tt_common_entry *common = &tt_local_entry->common; + struct batadv_tt_change_node *tt_change_node; u8 flags = common->flags | event_flags; - bool del_op_requested, del_op_entry; + struct batadv_tt_change_node *entry; + struct batadv_tt_change_node *safe; + bool del_op_requested; + bool del_op_entry; size_t changes; tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC); @@ -514,9 +519,9 @@ static u16 batadv_tt_entries(u16 tt_len) */ static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) { - u16 num_vlan = 0; - u16 tt_local_entries = 0; struct batadv_meshif_vlan *vlan; + u16 tt_local_entries = 0; + u16 num_vlan = 0; int hdr_size; rcu_read_lock(); @@ -535,6 +540,12 @@ static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) return hdr_size + batadv_tt_len(tt_local_entries); } +/** + * batadv_tt_local_init() - allocate and initialise the local translation table + * @bat_priv: the bat priv with all the mesh interface information + * + * Return: 0 on success or -ENOMEM in case of allocation failure + */ static int batadv_tt_local_init(struct batadv_priv *bat_priv) { if (bat_priv->tt.local_hash) @@ -551,6 +562,15 @@ static int batadv_tt_local_init(struct batadv_priv *bat_priv) return 0; } +/** + * batadv_tt_global_free() - drop a global translation table entry + * @bat_priv: the bat priv with all the mesh interface information + * @tt_global: the global TT entry to remove + * @message: debug message explaining why the entry is being removed + * + * Remove @tt_global from the global TT hash and drop the reference held by + * the hash. + */ static void batadv_tt_global_free(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global, const char *message) @@ -594,18 +614,20 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr, unsigned short vid, int ifindex, u32 mark) { struct batadv_priv *bat_priv = netdev_priv(mesh_iface); - struct batadv_tt_local_entry *tt_local; struct batadv_tt_global_entry *tt_global = NULL; - struct net *net = dev_net(mesh_iface); - struct batadv_meshif_vlan *vlan; - struct net_device *in_dev = NULL; - struct hlist_head *head; struct batadv_tt_orig_list_entry *orig_entry; - int hash_added, table_size, packet_size_max; - bool ret = false; + struct batadv_tt_local_entry *tt_local; + struct net *net = dev_net(mesh_iface); + struct net_device *in_dev = NULL; + struct batadv_meshif_vlan *vlan; bool roamed_back = false; bool iif_is_wifi = false; + struct hlist_head *head; + int packet_size_max; + bool ret = false; u8 remote_flags; + int hash_added; + int table_size; u32 match_mark; if (ifindex != BATADV_NULL_IFINDEX) @@ -987,14 +1009,16 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, */ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) { - struct batadv_tt_change_node *entry, *safe; - struct batadv_tvlv_tt_data *tt_data; struct batadv_tvlv_tt_change *tt_change; - int tt_diff_len, tt_change_len = 0; - int tt_diff_entries_num = 0; + struct batadv_tt_change_node *entry; + struct batadv_tvlv_tt_data *tt_data; + struct batadv_tt_change_node *safe; int tt_diff_entries_count = 0; + int tt_diff_entries_num = 0; bool drop_changes = false; size_t tt_extra_len = 0; + int tt_change_len = 0; + int tt_diff_len; u16 tvlv_len; tt_diff_entries_num = READ_ONCE(bat_priv->tt.local_changes); @@ -1087,10 +1111,10 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, struct batadv_priv *bat_priv, struct batadv_tt_common_entry *common) { - void *hdr; - struct batadv_meshif_vlan *vlan; struct batadv_tt_local_entry *local; + struct batadv_meshif_vlan *vlan; unsigned int last_seen_msecs; + void *hdr; u32 crc; local = container_of(common, struct batadv_tt_local_entry, common); @@ -1181,14 +1205,14 @@ batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, */ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct net_device *mesh_iface; - struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; + int portid = NETLINK_CB(cb->skb).portid; + struct net_device *mesh_iface; struct batadv_hashtable *hash; - int ret; + struct batadv_priv *bat_priv; int bucket = cb->args[0]; int idx = cb->args[1]; - int portid = NETLINK_CB(cb->skb).portid; + int ret; mesh_iface = batadv_netlink_get_meshif(cb); if (IS_ERR(mesh_iface)) @@ -1224,6 +1248,17 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb) return ret; } +/** + * batadv_tt_local_set_pending() - mark a local TT entry as pending removal + * @bat_priv: the bat priv with all the mesh interface information + * @tt_local_entry: local TT entry to mark + * @flags: TT change flags to announce together with the pending removal + * @message: debug message describing the reason for the change + * + * Schedule the TT change announcement and set BATADV_TT_CLIENT_PENDING on the + * entry. The entry is kept in the local table until the next TTVN increment + * so that a consistency-check response can still be answered. + */ static void batadv_tt_local_set_pending(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry, @@ -1259,8 +1294,9 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, { struct batadv_tt_local_entry *tt_removed_entry; struct batadv_tt_local_entry *tt_local_entry; - u16 flags, curr_flags = BATADV_NO_FLAGS; struct hlist_node *tt_removed_node; + u16 curr_flags = BATADV_NO_FLAGS; + u16 flags; tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) @@ -1319,8 +1355,8 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, struct hlist_head *head, int timeout) { - struct batadv_tt_local_entry *tt_local_entry; struct batadv_tt_common_entry *tt_common_entry; + struct batadv_tt_local_entry *tt_local_entry; struct hlist_node *node_tmp; hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, @@ -1352,9 +1388,9 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, static void batadv_tt_local_purge(struct batadv_priv *bat_priv, int timeout) { + spinlock_t *list_lock; /* protects write access to the hash lists */ struct batadv_hashtable *hash = bat_priv->tt.local_hash; struct hlist_head *head; - spinlock_t *list_lock; /* protects write access to the hash lists */ u32 i; for (i = 0; i < hash->size; i++) { @@ -1367,12 +1403,19 @@ static void batadv_tt_local_purge(struct batadv_priv *bat_priv, } } +/** + * batadv_tt_local_table_free() - release the local translation table + * @bat_priv: the bat priv with all the mesh interface information + * + * Drop every entry of the local TT hash, free their references and finally + * release the hashtable itself. + */ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) { - struct batadv_hashtable *hash; spinlock_t *list_lock; /* protects write access to the hash lists */ struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_local_entry *tt_local; + struct batadv_hashtable *hash; struct hlist_node *node_tmp; struct hlist_head *head; u32 i; @@ -1404,6 +1447,13 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) bat_priv->tt.local_hash = NULL; } +/** + * batadv_tt_global_init() - allocate and initialise the global translation + * table + * @bat_priv: the bat priv with all the mesh interface information + * + * Return: 0 on success or -ENOMEM in case of allocation failure + */ static int batadv_tt_global_init(struct batadv_priv *bat_priv) { if (bat_priv->tt.global_hash) @@ -1420,9 +1470,16 @@ static int batadv_tt_global_init(struct batadv_priv *bat_priv) return 0; } +/** + * batadv_tt_changes_list_free() - drop all pending local TT changes + * @bat_priv: the bat priv with all the mesh interface information + * + * Discard every queued local TT change and reset the pending change counter. + */ static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) { - struct batadv_tt_change_node *entry, *safe; + struct batadv_tt_change_node *entry; + struct batadv_tt_change_node *safe; spin_lock_bh(&bat_priv->tt.changes_list_lock); @@ -1451,7 +1508,8 @@ static struct batadv_tt_orig_list_entry * batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, const struct batadv_orig_node *orig_node) { - struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; + struct batadv_tt_orig_list_entry *orig_entry = NULL; + struct batadv_tt_orig_list_entry *tmp_orig_entry; const struct hlist_head *head; rcu_read_lock(); @@ -1604,10 +1662,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, { struct batadv_tt_global_entry *tt_global_entry; struct batadv_tt_local_entry *tt_local_entry; - bool ret = false; - int hash_added; struct batadv_tt_common_entry *common; + bool ret = false; u16 local_flags; + int hash_added; /* ignore global entries from backbone nodes */ if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) @@ -1763,10 +1821,12 @@ static struct batadv_tt_orig_list_entry * batadv_transtable_best_orig(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global_entry) { - struct batadv_neigh_node *router, *best_router = NULL; + struct batadv_tt_orig_list_entry *best_entry = NULL; struct batadv_algo_ops *bao = bat_priv->algo_ops; + struct batadv_neigh_node *best_router = NULL; + struct batadv_tt_orig_list_entry *orig_entry; + struct batadv_neigh_node *router; struct hlist_head *head; - struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; head = &tt_global_entry->orig_list; hlist_for_each_entry_rcu(orig_entry, head, list) { @@ -1812,9 +1872,9 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, bool best) { u16 flags = (common->flags & (~BATADV_TT_SYNC_MASK)) | orig->flags; - void *hdr; struct batadv_orig_node_vlan *vlan; u8 last_ttvn; + void *hdr; u32 crc; vlan = batadv_orig_node_vlan_get(orig->orig_node, @@ -1873,7 +1933,8 @@ batadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, struct batadv_priv *bat_priv, struct batadv_tt_common_entry *common, int *sub_s) { - struct batadv_tt_orig_list_entry *orig_entry, *best_entry; + struct batadv_tt_orig_list_entry *orig_entry; + struct batadv_tt_orig_list_entry *best_entry; struct batadv_tt_global_entry *global; struct hlist_head *head; int sub = 0; @@ -1948,16 +2009,16 @@ batadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, */ int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct net_device *mesh_iface; - struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; + int portid = NETLINK_CB(cb->skb).portid; + struct net_device *mesh_iface; struct batadv_hashtable *hash; - struct hlist_head *head; - int ret; + struct batadv_priv *bat_priv; int bucket = cb->args[0]; + struct hlist_head *head; int idx = cb->args[1]; int sub = cb->args[2]; - int portid = NETLINK_CB(cb->skb).portid; + int ret; mesh_iface = batadv_netlink_get_meshif(cb); if (IS_ERR(mesh_iface)) @@ -2024,13 +2085,17 @@ _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, batadv_tt_orig_list_entry_put(orig_entry); } -/* deletes the orig list of a tt_global_entry */ +/** + * batadv_tt_global_del_orig_list() - drop every orig_list_entry of a global + * TT entry + * @tt_global_entry: the global TT entry to clear + */ static void batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) { + struct batadv_tt_orig_list_entry *orig_entry; struct hlist_head *head; struct hlist_node *safe; - struct batadv_tt_orig_list_entry *orig_entry; spin_lock_bh(&tt_global_entry->list_lock); head = &tt_global_entry->orig_list; @@ -2055,9 +2120,9 @@ batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const char *message) { + struct batadv_tt_orig_list_entry *orig_entry; struct hlist_head *head; struct hlist_node *safe; - struct batadv_tt_orig_list_entry *orig_entry; unsigned short vid; spin_lock_bh(&tt_global_entry->list_lock); @@ -2077,9 +2142,17 @@ batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, spin_unlock_bh(&tt_global_entry->list_lock); } -/* If the client is to be deleted, we check if it is the last origantor entry - * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the - * timer, otherwise we simply remove the originator scheduled for deletion. +/** + * batadv_tt_global_del_roaming() - remove a roaming client from a global TT + * entry + * @bat_priv: the bat priv with all the mesh interface information + * @tt_global_entry: the global TT entry of the roaming client + * @orig_node: the originator that the client has roamed away from + * @message: debug message describing the reason for the change + * + * If @orig_node was the last announced source for the client, mark the entry + * for roaming so it can be cleaned up after the roaming timer expires. + * Otherwise simply remove the orig_node entry from the announcer list. */ static void batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, @@ -2087,9 +2160,9 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const char *message) { - bool last_entry = true; - struct hlist_head *head; struct batadv_tt_orig_list_entry *orig_entry; + struct hlist_head *head; + bool last_entry = true; /* no local entry exists, case 1: * Check if this is the last one or if other entries exist. @@ -2133,8 +2206,8 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv, const unsigned char *addr, unsigned short vid, const char *message, bool roaming) { - struct batadv_tt_global_entry *tt_global_entry; struct batadv_tt_local_entry *local_entry = NULL; + struct batadv_tt_global_entry *tt_global_entry; tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global_entry) @@ -2196,14 +2269,14 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, s32 match_vid, const char *message) { - struct batadv_tt_global_entry *tt_global; - struct batadv_tt_common_entry *tt_common_entry; - u32 i; + spinlock_t *list_lock; /* protects write access to the hash lists */ struct batadv_hashtable *hash = bat_priv->tt.global_hash; + struct batadv_tt_common_entry *tt_common_entry; + struct batadv_tt_global_entry *tt_global; struct hlist_node *safe; struct hlist_head *head; - spinlock_t *list_lock; /* protects write access to the hash lists */ unsigned short vid; + u32 i; if (!hash) return; @@ -2241,12 +2314,21 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); } +/** + * batadv_tt_global_to_purge() - check whether a global TT entry has to be + * purged + * @tt_global: global TT entry under consideration + * @msg: storage for a pointer to a human readable reason on return + * + * Return: true if the entry should be purged because its roaming or temporary + * timer has elapsed; false otherwise + */ static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, char **msg) { - bool purge = false; unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; + bool purge = false; if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { @@ -2263,16 +2345,23 @@ static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, return purge; } +/** + * batadv_tt_global_purge() - purge expired global translation table entries + * @bat_priv: the bat priv with all the mesh interface information + * + * Iterate over the global translation table and drop every entry that the + * roaming or temporary timer has expired for. + */ static void batadv_tt_global_purge(struct batadv_priv *bat_priv) { - struct batadv_hashtable *hash = bat_priv->tt.global_hash; - struct hlist_head *head; - struct hlist_node *node_tmp; spinlock_t *list_lock; /* protects write access to the hash lists */ - u32 i; - char *msg = NULL; + struct batadv_hashtable *hash = bat_priv->tt.global_hash; struct batadv_tt_common_entry *tt_common; struct batadv_tt_global_entry *tt_global; + struct hlist_node *node_tmp; + struct hlist_head *head; + char *msg = NULL; + u32 i; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2302,12 +2391,19 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv) } } +/** + * batadv_tt_global_table_free() - release the global translation table + * @bat_priv: the bat priv with all the mesh interface information + * + * Drop every entry of the global TT hash, free their references and finally + * release the hashtable itself. + */ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) { - struct batadv_hashtable *hash; spinlock_t *list_lock; /* protects write access to the hash lists */ struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_global_entry *tt_global; + struct batadv_hashtable *hash; struct hlist_node *node_tmp; struct hlist_head *head; u32 i; @@ -2338,6 +2434,16 @@ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) bat_priv->tt.global_hash = NULL; } +/** + * _batadv_is_ap_isolated() - check whether two clients are AP-isolated from + * each other + * @tt_local_entry: local TT entry of the sending client + * @tt_global_entry: global TT entry of the destination client + * + * Return: true if traffic between the two clients should be dropped because + * either both are WiFi clients or both carry the ISOLATION flag; false + * otherwise + */ static bool _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, struct batadv_tt_global_entry *tt_global_entry) @@ -2373,10 +2479,10 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid) { - struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_global_entry *tt_global_entry = NULL; - struct batadv_orig_node *orig_node = NULL; + struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_orig_list_entry *best_entry; + struct batadv_orig_node *orig_node = NULL; if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); @@ -2445,9 +2551,11 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv, struct batadv_tt_common_entry *tt_common; struct batadv_tt_global_entry *tt_global; struct hlist_head *head; - u32 i, crc_tmp, crc = 0; - u8 flags; __be16 tmp_vid; + u32 crc_tmp; + u32 crc = 0; + u8 flags; + u32 i; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2523,9 +2631,11 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, struct batadv_hashtable *hash = bat_priv->tt.local_hash; struct batadv_tt_common_entry *tt_common; struct hlist_head *head; - u32 i, crc_tmp, crc = 0; - u8 flags; __be16 tmp_vid; + u32 crc_tmp; + u32 crc = 0; + u8 flags; + u32 i; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2590,6 +2700,10 @@ static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node) kref_put(&tt_req_node->refcount, batadv_tt_req_node_release); } +/** + * batadv_tt_req_list_free() - drop all pending TT requests + * @bat_priv: the bat priv with all the mesh interface information + */ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) { struct batadv_tt_req_node *node; @@ -2605,6 +2719,18 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) spin_unlock_bh(&bat_priv->tt.req_list_lock); } +/** + * batadv_tt_save_orig_buffer() - cache the latest TT TVLV payload of an + * originator + * @bat_priv: the bat priv with all the mesh interface information + * @orig_node: originator for which the buffer should be created + * @tt_buff: pointer to the TT TVLV payload to cache + * @tt_buff_len: length of @tt_buff in bytes + * + * Replace the previously cached TT payload of @orig_node with a copy of + * @tt_buff. The buffer is left untouched when @tt_buff_len is 0 so that + * empty OGM updates do not discard the previously cached data. + */ static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const void *tt_buff, @@ -2626,6 +2752,10 @@ static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, spin_unlock_bh(&orig_node->tt_buff_lock); } +/** + * batadv_tt_req_purge() - drop timed-out TT requests + * @bat_priv: the bat priv with all the mesh interface information + */ static void batadv_tt_req_purge(struct batadv_priv *bat_priv) { struct batadv_tt_req_node *node; @@ -2654,7 +2784,8 @@ static struct batadv_tt_req_node * batadv_tt_req_node_new(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { - struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; + struct batadv_tt_req_node *tt_req_node = NULL; + struct batadv_tt_req_node *tt_req_node_tmp; spin_lock_bh(&bat_priv->tt.req_list_lock); hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { @@ -2763,7 +2894,8 @@ static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, struct batadv_tt_common_entry *tt_common_entry; struct batadv_tvlv_tt_change *tt_change; struct hlist_head *head; - u16 tt_tot, tt_num_entries = 0; + u16 tt_num_entries = 0; + u16 tt_tot; u8 flags; bool ret; u32 i; @@ -2817,8 +2949,9 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, { struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; struct batadv_orig_node_vlan *vlan; - int i, orig_num_vlan; + int orig_num_vlan; u32 crc; + int i; /* check if each received CRC matches the locally stored one */ for (i = 0; i < num_vlan; i++) { @@ -2924,7 +3057,8 @@ static bool batadv_send_tt_request(struct batadv_priv *bat_priv, struct batadv_tt_req_node *tt_req_node = NULL; struct batadv_hard_iface *primary_if; bool ret = false; - int i, size; + int size; + int i; primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) @@ -3000,13 +3134,15 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, u8 *req_src, u8 *req_dst) { - struct batadv_orig_node *req_dst_orig_node; struct batadv_orig_node *res_dst_orig_node = NULL; - struct batadv_tvlv_tt_change *tt_change; struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; - bool ret = false, full_table; - u8 orig_ttvn, req_ttvn; + struct batadv_orig_node *req_dst_orig_node; + struct batadv_tvlv_tt_change *tt_change; + bool ret = false; + bool full_table; + u8 orig_ttvn; u16 tvlv_len; + u8 req_ttvn; s32 tt_len; batadv_dbg(BATADV_DBG_TT, bat_priv, @@ -3133,9 +3269,10 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if = NULL; struct batadv_tvlv_tt_change *tt_change; struct batadv_orig_node *orig_node; - u8 my_ttvn, req_ttvn; - u16 tvlv_len; bool full_table; + u16 tvlv_len; + u8 req_ttvn; + u8 my_ttvn; s32 tt_len; batadv_dbg(BATADV_DBG_TT, bat_priv, @@ -3253,13 +3390,25 @@ static bool batadv_send_tt_response(struct batadv_priv *bat_priv, req_dst); } +/** + * _batadv_tt_update_changes() - apply a list of TT changes to the global TT + * @bat_priv: the bat priv with all the mesh interface information + * @orig_node: originator announcing the changes + * @tt_change: array of TT change entries to apply + * @tt_num_changes: number of entries in @tt_change + * @ttvn: TTVN of @orig_node corresponding to @tt_change + * + * Walk @tt_change and add/remove the announced clients in the global TT. + * Abort early without marking the @orig_node TT as initialized if adding + * an entry fails, so that the next TT request can re-sync the full table. + */ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_change *tt_change, u16 tt_num_changes, u8 ttvn) { - int i; int roams; + int i; for (i = 0; i < tt_num_changes; i++) { if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { @@ -3286,6 +3435,18 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); } +/** + * batadv_tt_fill_gtable() - replace the cached TT of an originator with a + * full table response + * @bat_priv: the bat priv with all the mesh interface information + * @tt_change: array of TT change entries describing the full table + * @ttvn: TTVN announced together with the full table + * @resp_src: MAC address of the responder + * @num_entries: number of entries in @tt_change + * + * Drop the previously known global TT entries of @resp_src and replace them + * with the entries from a freshly received full TT response. + */ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_change *tt_change, u8 ttvn, u8 *resp_src, @@ -3316,6 +3477,15 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, batadv_orig_node_put(orig_node); } +/** + * batadv_tt_update_changes() - apply an incremental TT changeset to the + * global TT + * @bat_priv: the bat priv with all the mesh interface information + * @orig_node: originator announcing the changes + * @tt_num_changes: number of entries in @tt_change + * @ttvn: TTVN of @orig_node corresponding to @tt_change + * @tt_change: array of TT change entries to apply + */ static void batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, u16 tt_num_changes, u8 ttvn, @@ -3369,11 +3539,11 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, u8 *resp_src, u16 num_entries) { - struct batadv_tt_req_node *node; - struct hlist_node *safe; struct batadv_orig_node *orig_node = NULL; struct batadv_tvlv_tt_change *tt_change; + struct batadv_tt_req_node *node; u8 *tvlv_ptr = (u8 *)tt_data; + struct hlist_node *safe; batadv_dbg(BATADV_DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", @@ -3416,9 +3586,14 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, batadv_orig_node_put(orig_node); } +/** + * batadv_tt_roam_list_free() - drop all entries from the roaming clients list + * @bat_priv: the bat priv with all the mesh interface information + */ static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) { - struct batadv_tt_roam_node *node, *safe; + struct batadv_tt_roam_node *node; + struct batadv_tt_roam_node *safe; spin_lock_bh(&bat_priv->tt.roam_list_lock); @@ -3430,9 +3605,14 @@ static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) spin_unlock_bh(&bat_priv->tt.roam_list_lock); } +/** + * batadv_tt_roam_purge() - drop timed-out roaming clients + * @bat_priv: the bat priv with all the mesh interface information + */ static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) { - struct batadv_tt_roam_node *node, *safe; + struct batadv_tt_roam_node *node; + struct batadv_tt_roam_node *safe; spin_lock_bh(&bat_priv->tt.roam_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { @@ -3522,8 +3702,8 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, unsigned short vid, struct batadv_orig_node *orig_node) { - struct batadv_hard_iface *primary_if; struct batadv_tvlv_roam_adv tvlv_roam; + struct batadv_hard_iface *primary_if; primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) @@ -3552,6 +3732,14 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, batadv_hardif_put(primary_if); } +/** + * batadv_tt_purge() - periodic worker to maintain the translation table + * @work: delayed work embedded in the per-mesh-interface TT state + * + * Purge timed-out entries from the local and global TT, drop stale TT + * requests and roaming clients, and reschedule the next run after + * BATADV_TT_WORK_PERIOD milliseconds. + */ static void batadv_tt_purge(struct work_struct *work) { struct delayed_work *delayed_work; @@ -3638,15 +3826,22 @@ static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags, } } -/* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ +/** + * batadv_tt_local_purge_pending_clients() - finalise removal of pending local + * clients + * @bat_priv: the bat priv with all the mesh interface information + * + * Iterate over the local TT and physically remove every entry that has been + * marked as BATADV_TT_CLIENT_PENDING. + */ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) { + spinlock_t *list_lock; /* protects write access to the hash lists */ struct batadv_hashtable *hash = bat_priv->tt.local_hash; struct batadv_tt_common_entry *tt_common; struct batadv_tt_local_entry *tt_local; struct hlist_node *node_tmp; struct hlist_head *head; - spinlock_t *list_lock; /* protects write access to the hash lists */ u32 i; if (!hash) @@ -3736,8 +3931,8 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, unsigned short vid) { - struct batadv_tt_local_entry *tt_local_entry; struct batadv_tt_global_entry *tt_global_entry; + struct batadv_tt_local_entry *tt_local_entry; struct batadv_meshif_vlan *vlan; bool ret = false; @@ -3947,9 +4142,12 @@ 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 = READ_ONCE(bat_priv->packet_size_max); - int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; + int timeout = BATADV_TT_LOCAL_TIMEOUT / 2; bool reduced = false; + int packet_size_max; + int table_size; + + packet_size_max = READ_ONCE(bat_priv->packet_size_max); spin_lock_bh(&bat_priv->tt.commit_lock); @@ -3992,8 +4190,9 @@ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, { struct batadv_tvlv_tt_change *tt_change; struct batadv_tvlv_tt_data *tt_data; - u16 num_entries, num_vlan; size_t tt_data_sz; + u16 num_entries; + u16 num_vlan; if (tvlv_value_len < sizeof(*tt_data)) return; @@ -4115,8 +4314,8 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, void *tvlv_value, u16 tvlv_value_len) { - struct batadv_tvlv_roam_adv *roaming_adv; struct batadv_orig_node *orig_node = NULL; + struct batadv_tvlv_roam_adv *roaming_adv; /* If this node is not the intended recipient of the * roaming advertisement the packet is forwarded @@ -4219,12 +4418,12 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, */ int __init batadv_tt_cache_init(void) { - size_t tl_size = sizeof(struct batadv_tt_local_entry); - size_t tg_size = sizeof(struct batadv_tt_global_entry); size_t tt_orig_size = sizeof(struct batadv_tt_orig_list_entry); size_t tt_change_size = sizeof(struct batadv_tt_change_node); - size_t tt_req_size = sizeof(struct batadv_tt_req_node); size_t tt_roam_size = sizeof(struct batadv_tt_roam_node); + size_t tg_size = sizeof(struct batadv_tt_global_entry); + size_t tt_req_size = sizeof(struct batadv_tt_req_node); + size_t tl_size = sizeof(struct batadv_tt_local_entry); batadv_tl_cache = kmem_cache_create("batadv_tl_cache", tl_size, 0, SLAB_HWCACHE_ALIGN, NULL); diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c index 49bf2ed9ecdc..de907c07fa15 100644 --- a/net/batman-adv/tvlv.c +++ b/net/batman-adv/tvlv.c @@ -72,7 +72,8 @@ static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler) static struct batadv_tvlv_handler * batadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version) { - struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL; + struct batadv_tvlv_handler *tvlv_handler = NULL; + struct batadv_tvlv_handler *tvlv_handler_tmp; rcu_read_lock(); hlist_for_each_entry_rcu(tvlv_handler_tmp, @@ -134,7 +135,8 @@ static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv) static struct batadv_tvlv_container * batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version) { - struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL; + struct batadv_tvlv_container *tvlv = NULL; + struct batadv_tvlv_container *tvlv_tmp; lockdep_assert_held(&bat_priv->tvlv.container_list_lock); @@ -236,7 +238,8 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, u8 type, u8 version, void *tvlv_value, u16 tvlv_value_len) { - struct batadv_tvlv_container *tvlv_old, *tvlv_new; + struct batadv_tvlv_container *tvlv_old; + struct batadv_tvlv_container *tvlv_new; if (!tvlv_value) tvlv_value_len = 0; @@ -383,8 +386,9 @@ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, * @tvlv_value: tvlv content * @tvlv_value_len: tvlv content length * - * Return: success if the handler was not found or the return value of the - * handler callback. + * Return: NET_RX_SUCCESS if the handler was not found or the return value of + * the handler callback. The latter is NET_RX_SUCCESS or NET_RX_DROP for the + * unicast handler and additionally a negative errno code for the mcast handler. */ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, struct batadv_tvlv_handler *tvlv_handler, @@ -394,7 +398,8 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, u16 tvlv_value_len) { unsigned int tvlv_offset; - u8 *src, *dst; + u8 *src; + u8 *dst; if (!tvlv_handler) return NET_RX_SUCCESS; @@ -524,8 +529,9 @@ static bool batadv_tvlv_containers_contain(void *tvlv_value, * @tvlv_value: tvlv content * @tvlv_value_len: tvlv content length * - * Return: success when processing an OGM or the return value of all called - * handler callbacks. + * Return: NET_RX_SUCCESS when processing an OGM or the combined return value of + * all called handler callbacks. The latter is NET_RX_SUCCESS, NET_RX_DROP or, + * for BATADV_MCAST packets, a negative errno code. */ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, u8 packet_type, @@ -533,13 +539,14 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, struct sk_buff *skb, void *tvlv_value, u16 tvlv_value_len) { + u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; u16 tvlv_value_start_len = tvlv_value_len; struct batadv_tvlv_handler *tvlv_handler; void *tvlv_value_start = tvlv_value; struct batadv_tvlv_hdr *tvlv_hdr; - u16 tvlv_value_cont_len; - u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; int ret = NET_RX_SUCCESS; + u16 tvlv_value_cont_len; + int res; while ((tvlv_hdr = batadv_tvlv_hdr_next(&tvlv_value, &tvlv_value_len))) { tvlv_value_cont_len = ntohs(tvlv_hdr->len); @@ -548,10 +555,13 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, tvlv_hdr->type, tvlv_hdr->version); - ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler, - packet_type, orig_node, skb, - tvlv_hdr + 1, - tvlv_value_cont_len); + res = batadv_tvlv_call_handler(bat_priv, tvlv_handler, + packet_type, orig_node, skb, + tvlv_hdr + 1, + tvlv_value_cont_len); + if (ret == NET_RX_SUCCESS || res < 0) + ret = res; + batadv_tvlv_handler_put(tvlv_handler); } @@ -596,8 +606,8 @@ void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_orig_node *orig_node) { - void *tvlv_value; u16 tvlv_value_len; + void *tvlv_value; if (!batadv_ogm_packet) return; @@ -717,12 +727,12 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, const u8 *src, void *tvlv_value, u16 tvlv_value_len) { struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; - struct batadv_tvlv_hdr *tvlv_hdr; + ssize_t hdr_len = sizeof(*unicast_tvlv_packet); struct batadv_orig_node *orig_node; - struct sk_buff *skb; + struct batadv_tvlv_hdr *tvlv_hdr; unsigned char *tvlv_buff; unsigned int tvlv_len; - ssize_t hdr_len = sizeof(*unicast_tvlv_packet); + struct sk_buff *skb; orig_node = batadv_orig_hash_find(bat_priv, dst); if (!orig_node) diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index cd12755d21f3..42b631573512 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1827,10 +1827,10 @@ struct batadv_bla_claim { /** @hash_entry: hlist node for &batadv_priv_bla.claim_hash */ struct hlist_node hash_entry; - /** @refcount: number of contexts the object is used */ + /** @rcu: struct used for freeing in an RCU-safe manner */ struct rcu_head rcu; - /** @rcu: struct used for freeing in an RCU-safe manner */ + /** @refcount: number of contexts the object is used */ struct kref refcount; }; #endif