diff options
Diffstat (limited to 'net/batman-adv/send.c')
-rw-r--r-- | net/batman-adv/send.c | 340 |
1 files changed, 70 insertions, 270 deletions
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 3377927..8a684eb 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -26,38 +26,16 @@ #include "soft-interface.h" #include "hard-interface.h" #include "vis.h" -#include "aggregation.h" #include "gateway_common.h" #include "originator.h" +#include "bat_ogm.h" static void send_outstanding_bcast_packet(struct work_struct *work); -/* apply hop penalty for a normal link */ -static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv) -{ - int hop_penalty = atomic_read(&bat_priv->hop_penalty); - return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); -} - -/* when do we schedule our own packet to be sent */ -static unsigned long own_send_time(struct bat_priv *bat_priv) -{ - return jiffies + msecs_to_jiffies( - atomic_read(&bat_priv->orig_interval) - - JITTER + (random32() % 2*JITTER)); -} - -/* when do we schedule a forwarded packet to be sent */ -static unsigned long forward_send_time(void) -{ - return jiffies + msecs_to_jiffies(random32() % (JITTER/2)); -} - /* send out an already prepared packet to the given address via the * specified batman interface */ -int send_skb_packet(struct sk_buff *skb, - struct hard_iface *hard_iface, - uint8_t *dst_addr) +int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface, + const uint8_t *dst_addr) { struct ethhdr *ethhdr; @@ -74,7 +52,7 @@ int send_skb_packet(struct sk_buff *skb, } /* push to the ethernet header. */ - if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0) + if (my_skb_head_push(skb, sizeof(*ethhdr)) < 0) goto send_skb_err; skb_reset_mac_header(skb); @@ -100,162 +78,67 @@ send_skb_err: return NET_XMIT_DROP; } -/* Send a packet to a given interface */ -static void send_packet_to_if(struct forw_packet *forw_packet, - struct hard_iface *hard_iface) +static void realloc_packet_buffer(struct hard_iface *hard_iface, + int new_len) { - struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - char *fwd_str; - uint8_t packet_num; - int16_t buff_pos; - struct batman_packet *batman_packet; - struct sk_buff *skb; + unsigned char *new_buff; - if (hard_iface->if_status != IF_ACTIVE) - return; + new_buff = kmalloc(new_len, GFP_ATOMIC); - packet_num = 0; - buff_pos = 0; - batman_packet = (struct batman_packet *)forw_packet->skb->data; - - /* adjust all flags and log packets */ - while (aggregated_packet(buff_pos, - forw_packet->packet_len, - batman_packet->num_tt)) { - - /* we might have aggregated direct link packets with an - * ordinary base packet */ - if ((forw_packet->direct_link_flags & (1 << packet_num)) && - (forw_packet->if_incoming == hard_iface)) - batman_packet->flags |= DIRECTLINK; - else - batman_packet->flags &= ~DIRECTLINK; - - fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ? - "Sending own" : - "Forwarding")); - bat_dbg(DBG_BATMAN, bat_priv, - "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," - " IDF %s) on interface %s [%pM]\n", - fwd_str, (packet_num > 0 ? "aggregated " : ""), - batman_packet->orig, ntohl(batman_packet->seqno), - batman_packet->tq, batman_packet->ttl, - (batman_packet->flags & DIRECTLINK ? - "on" : "off"), - hard_iface->net_dev->name, - hard_iface->net_dev->dev_addr); - - buff_pos += sizeof(struct batman_packet) + - (batman_packet->num_tt * ETH_ALEN); - packet_num++; - batman_packet = (struct batman_packet *) - (forw_packet->skb->data + buff_pos); - } + /* keep old buffer if kmalloc should fail */ + if (new_buff) { + memcpy(new_buff, hard_iface->packet_buff, + BATMAN_OGM_LEN); - /* create clone because function is called more than once */ - skb = skb_clone(forw_packet->skb, GFP_ATOMIC); - if (skb) - send_skb_packet(skb, hard_iface, broadcast_addr); + kfree(hard_iface->packet_buff); + hard_iface->packet_buff = new_buff; + hard_iface->packet_len = new_len; + } } -/* send a batman packet */ -static void send_packet(struct forw_packet *forw_packet) +/* when calling this function (hard_iface == primary_if) has to be true */ +static int prepare_packet_buffer(struct bat_priv *bat_priv, + struct hard_iface *hard_iface) { - struct hard_iface *hard_iface; - struct net_device *soft_iface; - struct bat_priv *bat_priv; - struct batman_packet *batman_packet = - (struct batman_packet *)(forw_packet->skb->data); - unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0); - - if (!forw_packet->if_incoming) { - pr_err("Error - can't forward packet: incoming iface not " - "specified\n"); - return; - } + int new_len; - soft_iface = forw_packet->if_incoming->soft_iface; - bat_priv = netdev_priv(soft_iface); + new_len = BATMAN_OGM_LEN + + tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes)); - if (forw_packet->if_incoming->if_status != IF_ACTIVE) - return; + /* if we have too many changes for one packet don't send any + * and wait for the tt table request which will be fragmented */ + if (new_len > hard_iface->soft_iface->mtu) + new_len = BATMAN_OGM_LEN; - /* multihomed peer assumed */ - /* non-primary OGMs are only broadcasted on their interface */ - if ((directlink && (batman_packet->ttl == 1)) || - (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) { + realloc_packet_buffer(hard_iface, new_len); - /* FIXME: what about aggregated packets ? */ - bat_dbg(DBG_BATMAN, bat_priv, - "%s packet (originator %pM, seqno %d, TTL %d) " - "on interface %s [%pM]\n", - (forw_packet->own ? "Sending own" : "Forwarding"), - batman_packet->orig, ntohl(batman_packet->seqno), - batman_packet->ttl, - forw_packet->if_incoming->net_dev->name, - forw_packet->if_incoming->net_dev->dev_addr); - - /* skb is only used once and than forw_packet is free'd */ - send_skb_packet(forw_packet->skb, forw_packet->if_incoming, - broadcast_addr); - forw_packet->skb = NULL; + atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv)); - return; - } + /* reset the sending counter */ + atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX); - /* broadcast on every interface */ - rcu_read_lock(); - list_for_each_entry_rcu(hard_iface, &hardif_list, list) { - if (hard_iface->soft_iface != soft_iface) - continue; - - send_packet_to_if(forw_packet, hard_iface); - } - rcu_read_unlock(); + return tt_changes_fill_buffer(bat_priv, + hard_iface->packet_buff + BATMAN_OGM_LEN, + hard_iface->packet_len - BATMAN_OGM_LEN); } -static void rebuild_batman_packet(struct bat_priv *bat_priv, - struct hard_iface *hard_iface) +static int reset_packet_buffer(struct bat_priv *bat_priv, + struct hard_iface *hard_iface) { - int new_len; - unsigned char *new_buff; - struct batman_packet *batman_packet; - - new_len = sizeof(struct batman_packet) + - (bat_priv->num_local_tt * ETH_ALEN); - new_buff = kmalloc(new_len, GFP_ATOMIC); - - /* keep old buffer if kmalloc should fail */ - if (new_buff) { - memcpy(new_buff, hard_iface->packet_buff, - sizeof(struct batman_packet)); - batman_packet = (struct batman_packet *)new_buff; - - batman_packet->num_tt = tt_local_fill_buffer(bat_priv, - new_buff + sizeof(struct batman_packet), - new_len - sizeof(struct batman_packet)); - - kfree(hard_iface->packet_buff); - hard_iface->packet_buff = new_buff; - hard_iface->packet_len = new_len; - } + realloc_packet_buffer(hard_iface, BATMAN_OGM_LEN); + return 0; } -void schedule_own_packet(struct hard_iface *hard_iface) +void schedule_bat_ogm(struct hard_iface *hard_iface) { struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct hard_iface *primary_if; - unsigned long send_time; - struct batman_packet *batman_packet; - int vis_server; + int tt_num_changes = -1; if ((hard_iface->if_status == IF_NOT_IN_USE) || (hard_iface->if_status == IF_TO_BE_REMOVED)) return; - vis_server = atomic_read(&bat_priv->vis_mode); - primary_if = primary_if_get_selected(bat_priv); - /** * the interface gets activated here to avoid race conditions between * the moment of activating the interface in @@ -266,111 +149,26 @@ void schedule_own_packet(struct hard_iface *hard_iface) if (hard_iface->if_status == IF_TO_BE_ACTIVATED) hard_iface->if_status = IF_ACTIVE; - /* if local tt has changed and interface is a primary interface */ - if ((atomic_read(&bat_priv->tt_local_changed)) && - (hard_iface == primary_if)) - rebuild_batman_packet(bat_priv, hard_iface); - - /** - * NOTE: packet_buff might just have been re-allocated in - * rebuild_batman_packet() - */ - batman_packet = (struct batman_packet *)hard_iface->packet_buff; - - /* change sequence number to network order */ - batman_packet->seqno = - htonl((uint32_t)atomic_read(&hard_iface->seqno)); - - if (vis_server == VIS_TYPE_SERVER_SYNC) - batman_packet->flags |= VIS_SERVER; - else - batman_packet->flags &= ~VIS_SERVER; - - if ((hard_iface == primary_if) && - (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) - batman_packet->gw_flags = - (uint8_t)atomic_read(&bat_priv->gw_bandwidth); - else - batman_packet->gw_flags = 0; - - atomic_inc(&hard_iface->seqno); - - slide_own_bcast_window(hard_iface); - send_time = own_send_time(bat_priv); - add_bat_packet_to_list(bat_priv, - hard_iface->packet_buff, - hard_iface->packet_len, - hard_iface, 1, send_time); - - if (primary_if) - hardif_free_ref(primary_if); -} - -void schedule_forward_packet(struct orig_node *orig_node, - struct ethhdr *ethhdr, - struct batman_packet *batman_packet, - uint8_t directlink, int tt_buff_len, - struct hard_iface *if_incoming) -{ - struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct neigh_node *router; - unsigned char in_tq, in_ttl, tq_avg = 0; - unsigned long send_time; - - if (batman_packet->ttl <= 1) { - bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); - return; - } - - router = orig_node_get_router(orig_node); - - in_tq = batman_packet->tq; - in_ttl = batman_packet->ttl; - - batman_packet->ttl--; - memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); - - /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast - * of our best tq value */ - if (router && router->tq_avg != 0) { - - /* rebroadcast ogm of best ranking neighbor as is */ - if (!compare_eth(router->addr, ethhdr->h_source)) { - batman_packet->tq = router->tq_avg; + primary_if = primary_if_get_selected(bat_priv); - if (router->last_ttl) - batman_packet->ttl = router->last_ttl - 1; + if (hard_iface == primary_if) { + /* if at least one change happened */ + if (atomic_read(&bat_priv->tt_local_changes) > 0) { + tt_commit_changes(bat_priv); + tt_num_changes = prepare_packet_buffer(bat_priv, + hard_iface); } - tq_avg = router->tq_avg; + /* if the changes have been sent often enough */ + if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt)) + tt_num_changes = reset_packet_buffer(bat_priv, + hard_iface); } - if (router) - neigh_node_free_ref(router); - - /* apply hop penalty */ - batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); - - bat_dbg(DBG_BATMAN, bat_priv, - "Forwarding packet: tq_orig: %i, tq_avg: %i, " - "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", - in_tq, tq_avg, batman_packet->tq, in_ttl - 1, - batman_packet->ttl); - - batman_packet->seqno = htonl(batman_packet->seqno); - - /* switch of primaries first hop flag when forwarding */ - batman_packet->flags &= ~PRIMARIES_FIRST_HOP; - if (directlink) - batman_packet->flags |= DIRECTLINK; - else - batman_packet->flags &= ~DIRECTLINK; + if (primary_if) + hardif_free_ref(primary_if); - send_time = forward_send_time(); - add_bat_packet_to_list(bat_priv, - (unsigned char *)batman_packet, - sizeof(struct batman_packet) + tt_buff_len, - if_incoming, 0, send_time); + bat_ogm_schedule(hard_iface, tt_num_changes); } static void forw_packet_free(struct forw_packet *forw_packet) @@ -401,18 +199,20 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, } /* add a broadcast packet to the queue and setup timers. broadcast packets - * are sent multiple times to increase probability for beeing received. + * are sent multiple times to increase probability for being received. * * This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on * errors. * * The skb is not consumed, so the caller should make sure that the * skb is freed. */ -int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) +int add_bcast_packet_to_list(struct bat_priv *bat_priv, + const struct sk_buff *skb, unsigned long delay) { struct hard_iface *primary_if = NULL; struct forw_packet *forw_packet; struct bcast_packet *bcast_packet; + struct sk_buff *newskb; if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) { bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n"); @@ -423,28 +223,28 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) if (!primary_if) goto out_and_inc; - forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); + forw_packet = kmalloc(sizeof(*forw_packet), GFP_ATOMIC); if (!forw_packet) goto out_and_inc; - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) + newskb = skb_copy(skb, GFP_ATOMIC); + if (!newskb) goto packet_free; /* as we have a copy now, it is safe to decrease the TTL */ - bcast_packet = (struct bcast_packet *)skb->data; + bcast_packet = (struct bcast_packet *)newskb->data; bcast_packet->ttl--; - skb_reset_mac_header(skb); + skb_reset_mac_header(newskb); - forw_packet->skb = skb; + forw_packet->skb = newskb; forw_packet->if_incoming = primary_if; /* how often did we send the bcast packet ? */ forw_packet->num_packets = 0; - _add_bcast_packet_to_list(bat_priv, forw_packet, 1); + _add_bcast_packet_to_list(bat_priv, forw_packet, delay); return NETDEV_TX_OK; packet_free: @@ -502,7 +302,7 @@ out: atomic_inc(&bat_priv->bcast_queue_left); } -void send_outstanding_bat_packet(struct work_struct *work) +void send_outstanding_bat_ogm_packet(struct work_struct *work) { struct delayed_work *delayed_work = container_of(work, struct delayed_work, work); @@ -518,7 +318,7 @@ void send_outstanding_bat_packet(struct work_struct *work) if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; - send_packet(forw_packet); + bat_ogm_emit(forw_packet); /** * we have to have at least one packet in the queue @@ -526,7 +326,7 @@ void send_outstanding_bat_packet(struct work_struct *work) * shutting down */ if (forw_packet->own) - schedule_own_packet(forw_packet->if_incoming); + schedule_bat_ogm(forw_packet->if_incoming); out: /* don't count own packet */ @@ -537,7 +337,7 @@ out: } void purge_outstanding_packets(struct bat_priv *bat_priv, - struct hard_iface *hard_iface) + const struct hard_iface *hard_iface) { struct forw_packet *forw_packet; struct hlist_node *tmp_node, *safe_tmp_node; @@ -557,7 +357,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, &bat_priv->forw_bcast_list, list) { /** - * if purge_outstanding_packets() was called with an argmument + * if purge_outstanding_packets() was called with an argument * we delete only packets belonging to the given interface */ if ((hard_iface) && @@ -586,7 +386,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, &bat_priv->forw_bat_list, list) { /** - * if purge_outstanding_packets() was called with an argmument + * if purge_outstanding_packets() was called with an argument * we delete only packets belonging to the given interface */ if ((hard_iface) && |