]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/batman-adv/bat_iv_ogm.c
batman-adv: register batman ogm receive function during protocol init
[karo-tx-linux.git] / net / batman-adv / bat_iv_ogm.c
index a6d5d63fb6ad9da8c7f82e87a44a2cb6f2b01935..e0aaf8c87d655099e761043950d2e4d6fd4cb046 100644 (file)
 #include "send.h"
 #include "bat_algo.h"
 
-static void bat_iv_ogm_init(struct hard_iface *hard_iface)
+static int bat_iv_ogm_iface_enable(struct hard_iface *hard_iface)
 {
        struct batman_ogm_packet *batman_ogm_packet;
+       uint32_t random_seqno;
+       int res = -1;
 
-       hard_iface->packet_len = BATMAN_OGM_LEN;
+       /* randomize initial seqno to avoid collision */
+       get_random_bytes(&random_seqno, sizeof(random_seqno));
+       atomic_set(&hard_iface->seqno, random_seqno);
+
+       hard_iface->packet_len = BATMAN_OGM_HLEN;
        hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);
 
+       if (!hard_iface->packet_buff)
+               goto out;
+
        batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
-       batman_ogm_packet->header.packet_type = BAT_OGM;
+       batman_ogm_packet->header.packet_type = BAT_IV_OGM;
        batman_ogm_packet->header.version = COMPAT_VERSION;
        batman_ogm_packet->header.ttl = 2;
        batman_ogm_packet->flags = NO_FLAGS;
        batman_ogm_packet->tq = TQ_MAX_VALUE;
        batman_ogm_packet->tt_num_changes = 0;
        batman_ogm_packet->ttvn = 0;
+
+       res = 0;
+
+out:
+       return res;
 }
 
-static void bat_iv_ogm_init_primary(struct hard_iface *hard_iface)
+static void bat_iv_ogm_iface_disable(struct hard_iface *hard_iface)
+{
+       kfree(hard_iface->packet_buff);
+       hard_iface->packet_buff = NULL;
+}
+
+static void bat_iv_ogm_primary_iface_set(struct hard_iface *hard_iface)
 {
        struct batman_ogm_packet *batman_ogm_packet;
 
@@ -92,7 +112,7 @@ static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
 static int bat_iv_ogm_aggr_packet(int buff_pos, int packet_len,
                                  int tt_num_changes)
 {
-       int next_buff_pos = buff_pos + BATMAN_OGM_LEN + tt_len(tt_num_changes);
+       int next_buff_pos = buff_pos + BATMAN_OGM_HLEN + tt_len(tt_num_changes);
 
        return (next_buff_pos <= packet_len) &&
                (next_buff_pos <= MAX_AGGREGATION_BYTES);
@@ -132,7 +152,7 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
                                                            "Sending own" :
                                                            "Forwarding"));
                bat_dbg(DBG_BATMAN, bat_priv,
-                       "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
+                       "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
                        fwd_str, (packet_num > 0 ? "aggregated " : ""),
                        batman_ogm_packet->orig,
                        ntohl(batman_ogm_packet->seqno),
@@ -142,7 +162,7 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
                        batman_ogm_packet->ttvn, hard_iface->net_dev->name,
                        hard_iface->net_dev->dev_addr);
 
-               buff_pos += BATMAN_OGM_LEN +
+               buff_pos += BATMAN_OGM_HLEN +
                                tt_len(batman_ogm_packet->tt_num_changes);
                packet_num++;
                batman_ogm_packet = (struct batman_ogm_packet *)
@@ -191,7 +211,7 @@ static void bat_iv_ogm_emit(struct forw_packet *forw_packet)
 
                /* FIXME: what about aggregated packets ? */
                bat_dbg(DBG_BATMAN, bat_priv,
-                       "%s packet (originator %pM, seqno %d, TTL %d) on interface %s [%pM]\n",
+                       "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
                        (forw_packet->own ? "Sending own" : "Forwarding"),
                        batman_ogm_packet->orig,
                        ntohl(batman_ogm_packet->seqno),
@@ -335,10 +355,9 @@ static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff,
        if ((atomic_read(&bat_priv->aggregated_ogms)) &&
            (packet_len < MAX_AGGREGATION_BYTES))
                forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
-                                                     sizeof(struct ethhdr));
+                                                     ETH_HLEN);
        else
-               forw_packet_aggr->skb = dev_alloc_skb(packet_len +
-                                                     sizeof(struct ethhdr));
+               forw_packet_aggr->skb = dev_alloc_skb(packet_len + ETH_HLEN);
 
        if (!forw_packet_aggr->skb) {
                if (!own_packet)
@@ -346,7 +365,7 @@ static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff,
                kfree(forw_packet_aggr);
                goto out;
        }
-       skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
+       skb_reserve(forw_packet_aggr->skb, ETH_HLEN);
 
        INIT_HLIST_NODE(&forw_packet_aggr->list);
 
@@ -461,7 +480,8 @@ static void bat_iv_ogm_queue_add(struct bat_priv *bat_priv,
 static void bat_iv_ogm_forward(struct orig_node *orig_node,
                               const struct ethhdr *ethhdr,
                               struct batman_ogm_packet *batman_ogm_packet,
-                              int directlink, struct hard_iface *if_incoming)
+                              bool is_single_hop_neigh,
+                              struct hard_iface *if_incoming)
 {
        struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
        struct neigh_node *router;
@@ -514,13 +534,13 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node,
 
        /* switch of primaries first hop flag when forwarding */
        batman_ogm_packet->flags &= ~PRIMARIES_FIRST_HOP;
-       if (directlink)
+       if (is_single_hop_neigh)
                batman_ogm_packet->flags |= DIRECTLINK;
        else
                batman_ogm_packet->flags &= ~DIRECTLINK;
 
        bat_iv_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet,
-                            BATMAN_OGM_LEN + tt_len(tt_num_changes),
+                            BATMAN_OGM_HLEN + tt_len(tt_num_changes),
                             if_incoming, 0, bat_iv_ogm_fwd_send_time());
 }
 
@@ -842,7 +862,8 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
        seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
 
        /* signalize caller that the packet is to be dropped. */
-       if (window_protected(bat_priv, seq_diff,
+       if (!hlist_empty(&orig_node->neigh_list) &&
+           window_protected(bat_priv, seq_diff,
                             &orig_node->batman_seqno_reset))
                goto out;
 
@@ -850,9 +871,9 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
        hlist_for_each_entry_rcu(tmp_neigh_node, node,
                                 &orig_node->neigh_list, list) {
 
-               is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
-                                              orig_node->last_real_seqno,
-                                              batman_ogm_packet->seqno);
+               is_duplicate |= bat_test_bit(tmp_neigh_node->real_bits,
+                                            orig_node->last_real_seqno,
+                                            batman_ogm_packet->seqno);
 
                if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
                    (tmp_neigh_node->if_incoming == if_incoming))
@@ -866,13 +887,14 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
                                              seq_diff, set_mark);
 
                tmp_neigh_node->real_packet_count =
-                       bit_packet_count(tmp_neigh_node->real_bits);
+                       bitmap_weight(tmp_neigh_node->real_bits,
+                                     TQ_LOCAL_WINDOW_SIZE);
        }
        rcu_read_unlock();
 
        if (need_update) {
                bat_dbg(DBG_BATMAN, bat_priv,
-                       "updating last_seqno: old %d, new %d\n",
+                       "updating last_seqno: old %u, new %u\n",
                        orig_node->last_real_seqno, batman_ogm_packet->seqno);
                orig_node->last_real_seqno = batman_ogm_packet->seqno;
        }
@@ -897,7 +919,8 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
        struct neigh_node *orig_neigh_router = NULL;
        int has_directlink_flag;
        int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
-       int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
+       int is_broadcast = 0, is_bidirectional;
+       bool is_single_hop_neigh = false;
        int is_duplicate;
        uint32_t if_incoming_seqno;
 
@@ -913,7 +936,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
         * packet in an aggregation.  Here we expect that the padding
         * is always zero (or not 0x01)
         */
-       if (batman_ogm_packet->header.packet_type != BAT_OGM)
+       if (batman_ogm_packet->header.packet_type != BAT_IV_OGM)
                return;
 
        /* could be changed by schedule_own_packet() */
@@ -921,11 +944,11 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
 
        has_directlink_flag = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
 
-       is_single_hop_neigh = (compare_eth(ethhdr->h_source,
-                                          batman_ogm_packet->orig) ? 1 : 0);
+       if (compare_eth(ethhdr->h_source, batman_ogm_packet->orig))
+               is_single_hop_neigh = true;
 
        bat_dbg(DBG_BATMAN, bat_priv,
-               "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
+               "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
                ethhdr->h_source, if_incoming->net_dev->name,
                if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
                batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
@@ -998,11 +1021,11 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
 
                        spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
                        word = &(orig_neigh_node->bcast_own[offset]);
-                       bit_mark(word,
-                                if_incoming_seqno -
+                       bat_set_bit(word,
+                                   if_incoming_seqno -
                                                batman_ogm_packet->seqno - 2);
                        orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
-                               bit_packet_count(word);
+                               bitmap_weight(word, TQ_LOCAL_WINDOW_SIZE);
                        spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
                }
 
@@ -1093,7 +1116,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
 
                /* mark direct link on incoming interface */
                bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
-                                  1, if_incoming);
+                                  is_single_hop_neigh, if_incoming);
 
                bat_dbg(DBG_BATMAN, bat_priv,
                        "Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
@@ -1116,7 +1139,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
        bat_dbg(DBG_BATMAN, bat_priv,
                "Forwarding packet: rebroadcast originator packet\n");
        bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
-                          0, if_incoming);
+                          is_single_hop_neigh, if_incoming);
 
 out_neigh:
        if ((orig_neigh_node) && (!is_single_hop_neigh))
@@ -1132,13 +1155,18 @@ out:
        orig_node_free_ref(orig_node);
 }
 
-static void bat_iv_ogm_receive(struct hard_iface *if_incoming,
-                              struct sk_buff *skb)
+static int bat_iv_ogm_receive(struct sk_buff *skb,
+                             struct hard_iface *if_incoming)
 {
        struct batman_ogm_packet *batman_ogm_packet;
        struct ethhdr *ethhdr;
        int buff_pos = 0, packet_len;
        unsigned char *tt_buff, *packet_buff;
+       bool ret;
+
+       ret = check_management_packet(skb, if_incoming, BATMAN_OGM_HLEN);
+       if (!ret)
+               return NET_RX_DROP;
 
        packet_len = skb_headlen(skb);
        ethhdr = (struct ethhdr *)skb_mac_header(skb);
@@ -1152,31 +1180,50 @@ static void bat_iv_ogm_receive(struct hard_iface *if_incoming,
                batman_ogm_packet->seqno = ntohl(batman_ogm_packet->seqno);
                batman_ogm_packet->tt_crc = ntohs(batman_ogm_packet->tt_crc);
 
-               tt_buff = packet_buff + buff_pos + BATMAN_OGM_LEN;
+               tt_buff = packet_buff + buff_pos + BATMAN_OGM_HLEN;
 
                bat_iv_ogm_process(ethhdr, batman_ogm_packet,
                                   tt_buff, if_incoming);
 
-               buff_pos += BATMAN_OGM_LEN +
+               buff_pos += BATMAN_OGM_HLEN +
                                tt_len(batman_ogm_packet->tt_num_changes);
 
                batman_ogm_packet = (struct batman_ogm_packet *)
                                                (packet_buff + buff_pos);
        } while (bat_iv_ogm_aggr_packet(buff_pos, packet_len,
                                        batman_ogm_packet->tt_num_changes));
+
+       kfree_skb(skb);
+       return NET_RX_SUCCESS;
 }
 
 static struct bat_algo_ops batman_iv __read_mostly = {
        .name = "BATMAN IV",
-       .bat_ogm_init = bat_iv_ogm_init,
-       .bat_ogm_init_primary = bat_iv_ogm_init_primary,
+       .bat_iface_enable = bat_iv_ogm_iface_enable,
+       .bat_iface_disable = bat_iv_ogm_iface_disable,
+       .bat_primary_iface_set = bat_iv_ogm_primary_iface_set,
        .bat_ogm_update_mac = bat_iv_ogm_update_mac,
        .bat_ogm_schedule = bat_iv_ogm_schedule,
        .bat_ogm_emit = bat_iv_ogm_emit,
-       .bat_ogm_receive = bat_iv_ogm_receive,
 };
 
 int __init bat_iv_init(void)
 {
-       return bat_algo_register(&batman_iv);
+       int ret;
+
+       /* batman originator packet */
+       ret = recv_handler_register(BAT_IV_OGM, bat_iv_ogm_receive);
+       if (ret < 0)
+               goto out;
+
+       ret = bat_algo_register(&batman_iv);
+       if (ret < 0)
+               goto handler_unregister;
+
+       goto out;
+
+handler_unregister:
+       recv_handler_unregister(BAT_IV_OGM);
+out:
+       return ret;
 }