···11-/*22- * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:33- *44- * Marek Lindner, Simon Wunderlich55- *66- * This program is free software; you can redistribute it and/or77- * modify it under the terms of version 2 of the GNU General Public88- * License as published by the Free Software Foundation.99- *1010- * This program is distributed in the hope that it will be useful, but1111- * WITHOUT ANY WARRANTY; without even the implied warranty of1212- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1313- * General Public License for more details.1414- *1515- * You should have received a copy of the GNU General Public License1616- * along with this program; if not, write to the Free Software1717- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA1818- * 02110-1301, USA1919- *2020- */2121-2222-#include "main.h"2323-#include "translation-table.h"2424-#include "aggregation.h"2525-#include "send.h"2626-#include "routing.h"2727-#include "hard-interface.h"2828-2929-/* return true if new_packet can be aggregated with forw_packet */3030-static bool can_aggregate_with(const struct batman_packet *new_batman_packet,3131- struct bat_priv *bat_priv,3232- int packet_len,3333- unsigned long send_time,3434- bool directlink,3535- const struct hard_iface *if_incoming,3636- const struct forw_packet *forw_packet)3737-{3838- struct batman_packet *batman_packet =3939- (struct batman_packet *)forw_packet->skb->data;4040- int aggregated_bytes = forw_packet->packet_len + packet_len;4141- struct hard_iface *primary_if = NULL;4242- bool res = false;4343-4444- /**4545- * we can aggregate the current packet to this aggregated packet4646- * if:4747- *4848- * - the send time is within our MAX_AGGREGATION_MS time4949- * - the resulting packet wont be bigger than5050- * MAX_AGGREGATION_BYTES5151- */5252-5353- if (time_before(send_time, forw_packet->send_time) &&5454- time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),5555- forw_packet->send_time) &&5656- (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {5757-5858- /**5959- * check aggregation compatibility6060- * -> direct link packets are broadcasted on6161- * their interface only6262- * -> aggregate packet if the current packet is6363- * a "global" packet as well as the base6464- * packet6565- */6666-6767- primary_if = primary_if_get_selected(bat_priv);6868- if (!primary_if)6969- goto out;7070-7171- /* packets without direct link flag and high TTL7272- * are flooded through the net */7373- if ((!directlink) &&7474- (!(batman_packet->flags & DIRECTLINK)) &&7575- (batman_packet->ttl != 1) &&7676-7777- /* own packets originating non-primary7878- * interfaces leave only that interface */7979- ((!forw_packet->own) ||8080- (forw_packet->if_incoming == primary_if))) {8181- res = true;8282- goto out;8383- }8484-8585- /* if the incoming packet is sent via this one8686- * interface only - we still can aggregate */8787- if ((directlink) &&8888- (new_batman_packet->ttl == 1) &&8989- (forw_packet->if_incoming == if_incoming) &&9090-9191- /* packets from direct neighbors or9292- * own secondary interface packets9393- * (= secondary interface packets in general) */9494- (batman_packet->flags & DIRECTLINK ||9595- (forw_packet->own &&9696- forw_packet->if_incoming != primary_if))) {9797- res = true;9898- goto out;9999- }100100- }101101-102102-out:103103- if (primary_if)104104- hardif_free_ref(primary_if);105105- return res;106106-}107107-108108-/* create a new aggregated packet and add this packet to it */109109-static void new_aggregated_packet(const unsigned char *packet_buff,110110- int packet_len, unsigned long send_time,111111- bool direct_link,112112- struct hard_iface *if_incoming,113113- int own_packet)114114-{115115- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);116116- struct forw_packet *forw_packet_aggr;117117- unsigned char *skb_buff;118118-119119- if (!atomic_inc_not_zero(&if_incoming->refcount))120120- return;121121-122122- /* own packet should always be scheduled */123123- if (!own_packet) {124124- if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {125125- bat_dbg(DBG_BATMAN, bat_priv,126126- "batman packet queue full\n");127127- goto out;128128- }129129- }130130-131131- forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC);132132- if (!forw_packet_aggr) {133133- if (!own_packet)134134- atomic_inc(&bat_priv->batman_queue_left);135135- goto out;136136- }137137-138138- if ((atomic_read(&bat_priv->aggregated_ogms)) &&139139- (packet_len < MAX_AGGREGATION_BYTES))140140- forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +141141- sizeof(struct ethhdr));142142- else143143- forw_packet_aggr->skb = dev_alloc_skb(packet_len +144144- sizeof(struct ethhdr));145145-146146- if (!forw_packet_aggr->skb) {147147- if (!own_packet)148148- atomic_inc(&bat_priv->batman_queue_left);149149- kfree(forw_packet_aggr);150150- goto out;151151- }152152- skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));153153-154154- INIT_HLIST_NODE(&forw_packet_aggr->list);155155-156156- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);157157- forw_packet_aggr->packet_len = packet_len;158158- memcpy(skb_buff, packet_buff, packet_len);159159-160160- forw_packet_aggr->own = own_packet;161161- forw_packet_aggr->if_incoming = if_incoming;162162- forw_packet_aggr->num_packets = 0;163163- forw_packet_aggr->direct_link_flags = NO_FLAGS;164164- forw_packet_aggr->send_time = send_time;165165-166166- /* save packet direct link flag status */167167- if (direct_link)168168- forw_packet_aggr->direct_link_flags |= 1;169169-170170- /* add new packet to packet list */171171- spin_lock_bh(&bat_priv->forw_bat_list_lock);172172- hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);173173- spin_unlock_bh(&bat_priv->forw_bat_list_lock);174174-175175- /* start timer for this packet */176176- INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,177177- send_outstanding_bat_packet);178178- queue_delayed_work(bat_event_workqueue,179179- &forw_packet_aggr->delayed_work,180180- send_time - jiffies);181181-182182- return;183183-out:184184- hardif_free_ref(if_incoming);185185-}186186-187187-/* aggregate a new packet into the existing aggregation */188188-static void aggregate(struct forw_packet *forw_packet_aggr,189189- const unsigned char *packet_buff, int packet_len,190190- bool direct_link)191191-{192192- unsigned char *skb_buff;193193-194194- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);195195- memcpy(skb_buff, packet_buff, packet_len);196196- forw_packet_aggr->packet_len += packet_len;197197- forw_packet_aggr->num_packets++;198198-199199- /* save packet direct link flag status */200200- if (direct_link)201201- forw_packet_aggr->direct_link_flags |=202202- (1 << forw_packet_aggr->num_packets);203203-}204204-205205-void add_bat_packet_to_list(struct bat_priv *bat_priv,206206- unsigned char *packet_buff, int packet_len,207207- struct hard_iface *if_incoming, int own_packet,208208- unsigned long send_time)209209-{210210- /**211211- * _aggr -> pointer to the packet we want to aggregate with212212- * _pos -> pointer to the position in the queue213213- */214214- struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;215215- struct hlist_node *tmp_node;216216- struct batman_packet *batman_packet =217217- (struct batman_packet *)packet_buff;218218- bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;219219-220220- /* find position for the packet in the forward queue */221221- spin_lock_bh(&bat_priv->forw_bat_list_lock);222222- /* own packets are not to be aggregated */223223- if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {224224- hlist_for_each_entry(forw_packet_pos, tmp_node,225225- &bat_priv->forw_bat_list, list) {226226- if (can_aggregate_with(batman_packet,227227- bat_priv,228228- packet_len,229229- send_time,230230- direct_link,231231- if_incoming,232232- forw_packet_pos)) {233233- forw_packet_aggr = forw_packet_pos;234234- break;235235- }236236- }237237- }238238-239239- /* nothing to aggregate with - either aggregation disabled or no240240- * suitable aggregation packet found */241241- if (!forw_packet_aggr) {242242- /* the following section can run without the lock */243243- spin_unlock_bh(&bat_priv->forw_bat_list_lock);244244-245245- /**246246- * if we could not aggregate this packet with one of the others247247- * we hold it back for a while, so that it might be aggregated248248- * later on249249- */250250- if ((!own_packet) &&251251- (atomic_read(&bat_priv->aggregated_ogms)))252252- send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);253253-254254- new_aggregated_packet(packet_buff, packet_len,255255- send_time, direct_link,256256- if_incoming, own_packet);257257- } else {258258- aggregate(forw_packet_aggr,259259- packet_buff, packet_len,260260- direct_link);261261- spin_unlock_bh(&bat_priv->forw_bat_list_lock);262262- }263263-}264264-265265-/* unpack the aggregated packets and process them one by one */266266-void receive_aggr_bat_packet(const struct ethhdr *ethhdr,267267- unsigned char *packet_buff, int packet_len,268268- struct hard_iface *if_incoming)269269-{270270- struct batman_packet *batman_packet;271271- int buff_pos = 0;272272- unsigned char *tt_buff;273273-274274- batman_packet = (struct batman_packet *)packet_buff;275275-276276- do {277277- /* network to host order for our 32bit seqno and the278278- orig_interval */279279- batman_packet->seqno = ntohl(batman_packet->seqno);280280- batman_packet->tt_crc = ntohs(batman_packet->tt_crc);281281-282282- tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN;283283-284284- receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming);285285-286286- buff_pos += BAT_PACKET_LEN +287287- tt_len(batman_packet->tt_num_changes);288288-289289- batman_packet = (struct batman_packet *)290290- (packet_buff + buff_pos);291291- } while (aggregated_packet(buff_pos, packet_len,292292- batman_packet->tt_num_changes));293293-}
···1919 *2020 */21212222-#ifndef _NET_BATMAN_ADV_AGGREGATION_H_2323-#define _NET_BATMAN_ADV_AGGREGATION_H_2222+#ifndef _NET_BATMAN_ADV_OGM_H_2323+#define _NET_BATMAN_ADV_OGM_H_24242525#include "main.h"26262727-/* is there another aggregated packet here? */2828-static inline int aggregated_packet(int buff_pos, int packet_len,2929- int tt_num_changes)3030-{3131- int next_buff_pos = buff_pos + BAT_PACKET_LEN + tt_len(tt_num_changes);2727+void bat_ogm_init(struct hard_iface *hard_iface);2828+void bat_ogm_init_primary(struct hard_iface *hard_iface);2929+void bat_ogm_update_mac(struct hard_iface *hard_iface);3030+void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes);3131+void bat_ogm_emit(struct forw_packet *forw_packet);3232+void bat_ogm_receive(const struct ethhdr *ethhdr, unsigned char *packet_buff,3333+ int packet_len, struct hard_iface *if_incoming);32343333- return (next_buff_pos <= packet_len) &&3434- (next_buff_pos <= MAX_AGGREGATION_BYTES);3535-}3636-3737-void add_bat_packet_to_list(struct bat_priv *bat_priv,3838- unsigned char *packet_buff, int packet_len,3939- struct hard_iface *if_incoming, int own_packet,4040- unsigned long send_time);4141-void receive_aggr_bat_packet(const struct ethhdr *ethhdr,4242- unsigned char *packet_buff, int packet_len,4343- struct hard_iface *if_incoming);4444-4545-#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */3535+#endif /* _NET_BATMAN_ADV_OGM_H_ */
+1170
net/batman-adv/bat_iv_ogm.c
···11+/*22+ * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:33+ *44+ * Marek Lindner, Simon Wunderlich55+ *66+ * This program is free software; you can redistribute it and/or77+ * modify it under the terms of version 2 of the GNU General Public88+ * License as published by the Free Software Foundation.99+ *1010+ * This program is distributed in the hope that it will be useful, but1111+ * WITHOUT ANY WARRANTY; without even the implied warranty of1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1313+ * General Public License for more details.1414+ *1515+ * You should have received a copy of the GNU General Public License1616+ * along with this program; if not, write to the Free Software1717+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA1818+ * 02110-1301, USA1919+ *2020+ */2121+2222+#include "main.h"2323+#include "bat_ogm.h"2424+#include "translation-table.h"2525+#include "ring_buffer.h"2626+#include "originator.h"2727+#include "routing.h"2828+#include "gateway_common.h"2929+#include "gateway_client.h"3030+#include "hard-interface.h"3131+#include "send.h"3232+3333+void bat_ogm_init(struct hard_iface *hard_iface)3434+{3535+ struct batman_ogm_packet *batman_ogm_packet;3636+3737+ hard_iface->packet_len = BATMAN_OGM_LEN;3838+ hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);3939+4040+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;4141+ batman_ogm_packet->packet_type = BAT_OGM;4242+ batman_ogm_packet->version = COMPAT_VERSION;4343+ batman_ogm_packet->flags = NO_FLAGS;4444+ batman_ogm_packet->ttl = 2;4545+ batman_ogm_packet->tq = TQ_MAX_VALUE;4646+ batman_ogm_packet->tt_num_changes = 0;4747+ batman_ogm_packet->ttvn = 0;4848+}4949+5050+void bat_ogm_init_primary(struct hard_iface *hard_iface)5151+{5252+ struct batman_ogm_packet *batman_ogm_packet;5353+5454+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;5555+ batman_ogm_packet->flags = PRIMARIES_FIRST_HOP;5656+ batman_ogm_packet->ttl = TTL;5757+}5858+5959+void bat_ogm_update_mac(struct hard_iface *hard_iface)6060+{6161+ struct batman_ogm_packet *batman_ogm_packet;6262+6363+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;6464+ memcpy(batman_ogm_packet->orig,6565+ hard_iface->net_dev->dev_addr, ETH_ALEN);6666+ memcpy(batman_ogm_packet->prev_sender,6767+ hard_iface->net_dev->dev_addr, ETH_ALEN);6868+}6969+7070+/* when do we schedule our own ogm to be sent */7171+static unsigned long bat_ogm_emit_send_time(const struct bat_priv *bat_priv)7272+{7373+ return jiffies + msecs_to_jiffies(7474+ atomic_read(&bat_priv->orig_interval) -7575+ JITTER + (random32() % 2*JITTER));7676+}7777+7878+/* when do we schedule a ogm packet to be sent */7979+static unsigned long bat_ogm_fwd_send_time(void)8080+{8181+ return jiffies + msecs_to_jiffies(random32() % (JITTER/2));8282+}8383+8484+/* apply hop penalty for a normal link */8585+static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)8686+{8787+ int hop_penalty = atomic_read(&bat_priv->hop_penalty);8888+ return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);8989+}9090+9191+/* is there another aggregated packet here? */9292+static int bat_ogm_aggr_packet(int buff_pos, int packet_len,9393+ int tt_num_changes)9494+{9595+ int next_buff_pos = buff_pos + BATMAN_OGM_LEN + tt_len(tt_num_changes);9696+9797+ return (next_buff_pos <= packet_len) &&9898+ (next_buff_pos <= MAX_AGGREGATION_BYTES);9999+}100100+101101+/* send a batman ogm to a given interface */102102+static void bat_ogm_send_to_if(struct forw_packet *forw_packet,103103+ struct hard_iface *hard_iface)104104+{105105+ struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);106106+ char *fwd_str;107107+ uint8_t packet_num;108108+ int16_t buff_pos;109109+ struct batman_ogm_packet *batman_ogm_packet;110110+ struct sk_buff *skb;111111+112112+ if (hard_iface->if_status != IF_ACTIVE)113113+ return;114114+115115+ packet_num = 0;116116+ buff_pos = 0;117117+ batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;118118+119119+ /* adjust all flags and log packets */120120+ while (bat_ogm_aggr_packet(buff_pos, forw_packet->packet_len,121121+ batman_ogm_packet->tt_num_changes)) {122122+123123+ /* we might have aggregated direct link packets with an124124+ * ordinary base packet */125125+ if ((forw_packet->direct_link_flags & (1 << packet_num)) &&126126+ (forw_packet->if_incoming == hard_iface))127127+ batman_ogm_packet->flags |= DIRECTLINK;128128+ else129129+ batman_ogm_packet->flags &= ~DIRECTLINK;130130+131131+ fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?132132+ "Sending own" :133133+ "Forwarding"));134134+ bat_dbg(DBG_BATMAN, bat_priv,135135+ "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"136136+ " IDF %s, ttvn %d) on interface %s [%pM]\n",137137+ fwd_str, (packet_num > 0 ? "aggregated " : ""),138138+ batman_ogm_packet->orig,139139+ ntohl(batman_ogm_packet->seqno),140140+ batman_ogm_packet->tq, batman_ogm_packet->ttl,141141+ (batman_ogm_packet->flags & DIRECTLINK ?142142+ "on" : "off"),143143+ batman_ogm_packet->ttvn, hard_iface->net_dev->name,144144+ hard_iface->net_dev->dev_addr);145145+146146+ buff_pos += BATMAN_OGM_LEN +147147+ tt_len(batman_ogm_packet->tt_num_changes);148148+ packet_num++;149149+ batman_ogm_packet = (struct batman_ogm_packet *)150150+ (forw_packet->skb->data + buff_pos);151151+ }152152+153153+ /* create clone because function is called more than once */154154+ skb = skb_clone(forw_packet->skb, GFP_ATOMIC);155155+ if (skb)156156+ send_skb_packet(skb, hard_iface, broadcast_addr);157157+}158158+159159+/* send a batman ogm packet */160160+void bat_ogm_emit(struct forw_packet *forw_packet)161161+{162162+ struct hard_iface *hard_iface;163163+ struct net_device *soft_iface;164164+ struct bat_priv *bat_priv;165165+ struct hard_iface *primary_if = NULL;166166+ struct batman_ogm_packet *batman_ogm_packet;167167+ unsigned char directlink;168168+169169+ batman_ogm_packet = (struct batman_ogm_packet *)170170+ (forw_packet->skb->data);171171+ directlink = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);172172+173173+ if (!forw_packet->if_incoming) {174174+ pr_err("Error - can't forward packet: incoming iface not "175175+ "specified\n");176176+ goto out;177177+ }178178+179179+ soft_iface = forw_packet->if_incoming->soft_iface;180180+ bat_priv = netdev_priv(soft_iface);181181+182182+ if (forw_packet->if_incoming->if_status != IF_ACTIVE)183183+ goto out;184184+185185+ primary_if = primary_if_get_selected(bat_priv);186186+ if (!primary_if)187187+ goto out;188188+189189+ /* multihomed peer assumed */190190+ /* non-primary OGMs are only broadcasted on their interface */191191+ if ((directlink && (batman_ogm_packet->ttl == 1)) ||192192+ (forw_packet->own && (forw_packet->if_incoming != primary_if))) {193193+194194+ /* FIXME: what about aggregated packets ? */195195+ bat_dbg(DBG_BATMAN, bat_priv,196196+ "%s packet (originator %pM, seqno %d, TTL %d) "197197+ "on interface %s [%pM]\n",198198+ (forw_packet->own ? "Sending own" : "Forwarding"),199199+ batman_ogm_packet->orig,200200+ ntohl(batman_ogm_packet->seqno),201201+ batman_ogm_packet->ttl,202202+ forw_packet->if_incoming->net_dev->name,203203+ forw_packet->if_incoming->net_dev->dev_addr);204204+205205+ /* skb is only used once and than forw_packet is free'd */206206+ send_skb_packet(forw_packet->skb, forw_packet->if_incoming,207207+ broadcast_addr);208208+ forw_packet->skb = NULL;209209+210210+ goto out;211211+ }212212+213213+ /* broadcast on every interface */214214+ rcu_read_lock();215215+ list_for_each_entry_rcu(hard_iface, &hardif_list, list) {216216+ if (hard_iface->soft_iface != soft_iface)217217+ continue;218218+219219+ bat_ogm_send_to_if(forw_packet, hard_iface);220220+ }221221+ rcu_read_unlock();222222+223223+out:224224+ if (primary_if)225225+ hardif_free_ref(primary_if);226226+}227227+228228+/* return true if new_packet can be aggregated with forw_packet */229229+static bool bat_ogm_can_aggregate(const struct batman_ogm_packet230230+ *new_batman_ogm_packet,231231+ struct bat_priv *bat_priv,232232+ int packet_len, unsigned long send_time,233233+ bool directlink,234234+ const struct hard_iface *if_incoming,235235+ const struct forw_packet *forw_packet)236236+{237237+ struct batman_ogm_packet *batman_ogm_packet;238238+ int aggregated_bytes = forw_packet->packet_len + packet_len;239239+ struct hard_iface *primary_if = NULL;240240+ bool res = false;241241+242242+ batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;243243+244244+ /**245245+ * we can aggregate the current packet to this aggregated packet246246+ * if:247247+ *248248+ * - the send time is within our MAX_AGGREGATION_MS time249249+ * - the resulting packet wont be bigger than250250+ * MAX_AGGREGATION_BYTES251251+ */252252+253253+ if (time_before(send_time, forw_packet->send_time) &&254254+ time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),255255+ forw_packet->send_time) &&256256+ (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {257257+258258+ /**259259+ * check aggregation compatibility260260+ * -> direct link packets are broadcasted on261261+ * their interface only262262+ * -> aggregate packet if the current packet is263263+ * a "global" packet as well as the base264264+ * packet265265+ */266266+267267+ primary_if = primary_if_get_selected(bat_priv);268268+ if (!primary_if)269269+ goto out;270270+271271+ /* packets without direct link flag and high TTL272272+ * are flooded through the net */273273+ if ((!directlink) &&274274+ (!(batman_ogm_packet->flags & DIRECTLINK)) &&275275+ (batman_ogm_packet->ttl != 1) &&276276+277277+ /* own packets originating non-primary278278+ * interfaces leave only that interface */279279+ ((!forw_packet->own) ||280280+ (forw_packet->if_incoming == primary_if))) {281281+ res = true;282282+ goto out;283283+ }284284+285285+ /* if the incoming packet is sent via this one286286+ * interface only - we still can aggregate */287287+ if ((directlink) &&288288+ (new_batman_ogm_packet->ttl == 1) &&289289+ (forw_packet->if_incoming == if_incoming) &&290290+291291+ /* packets from direct neighbors or292292+ * own secondary interface packets293293+ * (= secondary interface packets in general) */294294+ (batman_ogm_packet->flags & DIRECTLINK ||295295+ (forw_packet->own &&296296+ forw_packet->if_incoming != primary_if))) {297297+ res = true;298298+ goto out;299299+ }300300+ }301301+302302+out:303303+ if (primary_if)304304+ hardif_free_ref(primary_if);305305+ return res;306306+}307307+308308+/* create a new aggregated packet and add this packet to it */309309+static void bat_ogm_aggregate_new(const unsigned char *packet_buff,310310+ int packet_len, unsigned long send_time,311311+ bool direct_link,312312+ struct hard_iface *if_incoming,313313+ int own_packet)314314+{315315+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);316316+ struct forw_packet *forw_packet_aggr;317317+ unsigned char *skb_buff;318318+319319+ if (!atomic_inc_not_zero(&if_incoming->refcount))320320+ return;321321+322322+ /* own packet should always be scheduled */323323+ if (!own_packet) {324324+ if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {325325+ bat_dbg(DBG_BATMAN, bat_priv,326326+ "batman packet queue full\n");327327+ goto out;328328+ }329329+ }330330+331331+ forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC);332332+ if (!forw_packet_aggr) {333333+ if (!own_packet)334334+ atomic_inc(&bat_priv->batman_queue_left);335335+ goto out;336336+ }337337+338338+ if ((atomic_read(&bat_priv->aggregated_ogms)) &&339339+ (packet_len < MAX_AGGREGATION_BYTES))340340+ forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +341341+ sizeof(struct ethhdr));342342+ else343343+ forw_packet_aggr->skb = dev_alloc_skb(packet_len +344344+ sizeof(struct ethhdr));345345+346346+ if (!forw_packet_aggr->skb) {347347+ if (!own_packet)348348+ atomic_inc(&bat_priv->batman_queue_left);349349+ kfree(forw_packet_aggr);350350+ goto out;351351+ }352352+ skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));353353+354354+ INIT_HLIST_NODE(&forw_packet_aggr->list);355355+356356+ skb_buff = skb_put(forw_packet_aggr->skb, packet_len);357357+ forw_packet_aggr->packet_len = packet_len;358358+ memcpy(skb_buff, packet_buff, packet_len);359359+360360+ forw_packet_aggr->own = own_packet;361361+ forw_packet_aggr->if_incoming = if_incoming;362362+ forw_packet_aggr->num_packets = 0;363363+ forw_packet_aggr->direct_link_flags = NO_FLAGS;364364+ forw_packet_aggr->send_time = send_time;365365+366366+ /* save packet direct link flag status */367367+ if (direct_link)368368+ forw_packet_aggr->direct_link_flags |= 1;369369+370370+ /* add new packet to packet list */371371+ spin_lock_bh(&bat_priv->forw_bat_list_lock);372372+ hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);373373+ spin_unlock_bh(&bat_priv->forw_bat_list_lock);374374+375375+ /* start timer for this packet */376376+ INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,377377+ send_outstanding_bat_ogm_packet);378378+ queue_delayed_work(bat_event_workqueue,379379+ &forw_packet_aggr->delayed_work,380380+ send_time - jiffies);381381+382382+ return;383383+out:384384+ hardif_free_ref(if_incoming);385385+}386386+387387+/* aggregate a new packet into the existing ogm packet */388388+static void bat_ogm_aggregate(struct forw_packet *forw_packet_aggr,389389+ const unsigned char *packet_buff,390390+ int packet_len, bool direct_link)391391+{392392+ unsigned char *skb_buff;393393+394394+ skb_buff = skb_put(forw_packet_aggr->skb, packet_len);395395+ memcpy(skb_buff, packet_buff, packet_len);396396+ forw_packet_aggr->packet_len += packet_len;397397+ forw_packet_aggr->num_packets++;398398+399399+ /* save packet direct link flag status */400400+ if (direct_link)401401+ forw_packet_aggr->direct_link_flags |=402402+ (1 << forw_packet_aggr->num_packets);403403+}404404+405405+static void bat_ogm_queue_add(struct bat_priv *bat_priv,406406+ unsigned char *packet_buff,407407+ int packet_len, struct hard_iface *if_incoming,408408+ int own_packet, unsigned long send_time)409409+{410410+ /**411411+ * _aggr -> pointer to the packet we want to aggregate with412412+ * _pos -> pointer to the position in the queue413413+ */414414+ struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;415415+ struct hlist_node *tmp_node;416416+ struct batman_ogm_packet *batman_ogm_packet;417417+ bool direct_link;418418+419419+ batman_ogm_packet = (struct batman_ogm_packet *)packet_buff;420420+ direct_link = batman_ogm_packet->flags & DIRECTLINK ? 1 : 0;421421+422422+ /* find position for the packet in the forward queue */423423+ spin_lock_bh(&bat_priv->forw_bat_list_lock);424424+ /* own packets are not to be aggregated */425425+ if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {426426+ hlist_for_each_entry(forw_packet_pos, tmp_node,427427+ &bat_priv->forw_bat_list, list) {428428+ if (bat_ogm_can_aggregate(batman_ogm_packet,429429+ bat_priv, packet_len,430430+ send_time, direct_link,431431+ if_incoming,432432+ forw_packet_pos)) {433433+ forw_packet_aggr = forw_packet_pos;434434+ break;435435+ }436436+ }437437+ }438438+439439+ /* nothing to aggregate with - either aggregation disabled or no440440+ * suitable aggregation packet found */441441+ if (!forw_packet_aggr) {442442+ /* the following section can run without the lock */443443+ spin_unlock_bh(&bat_priv->forw_bat_list_lock);444444+445445+ /**446446+ * if we could not aggregate this packet with one of the others447447+ * we hold it back for a while, so that it might be aggregated448448+ * later on449449+ */450450+ if ((!own_packet) &&451451+ (atomic_read(&bat_priv->aggregated_ogms)))452452+ send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);453453+454454+ bat_ogm_aggregate_new(packet_buff, packet_len,455455+ send_time, direct_link,456456+ if_incoming, own_packet);457457+ } else {458458+ bat_ogm_aggregate(forw_packet_aggr, packet_buff, packet_len,459459+ direct_link);460460+ spin_unlock_bh(&bat_priv->forw_bat_list_lock);461461+ }462462+}463463+464464+static void bat_ogm_forward(struct orig_node *orig_node,465465+ const struct ethhdr *ethhdr,466466+ struct batman_ogm_packet *batman_ogm_packet,467467+ int directlink, struct hard_iface *if_incoming)468468+{469469+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);470470+ struct neigh_node *router;471471+ uint8_t in_tq, in_ttl, tq_avg = 0;472472+ uint8_t tt_num_changes;473473+474474+ if (batman_ogm_packet->ttl <= 1) {475475+ bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");476476+ return;477477+ }478478+479479+ router = orig_node_get_router(orig_node);480480+481481+ in_tq = batman_ogm_packet->tq;482482+ in_ttl = batman_ogm_packet->ttl;483483+ tt_num_changes = batman_ogm_packet->tt_num_changes;484484+485485+ batman_ogm_packet->ttl--;486486+ memcpy(batman_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);487487+488488+ /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast489489+ * of our best tq value */490490+ if (router && router->tq_avg != 0) {491491+492492+ /* rebroadcast ogm of best ranking neighbor as is */493493+ if (!compare_eth(router->addr, ethhdr->h_source)) {494494+ batman_ogm_packet->tq = router->tq_avg;495495+496496+ if (router->last_ttl)497497+ batman_ogm_packet->ttl = router->last_ttl - 1;498498+ }499499+500500+ tq_avg = router->tq_avg;501501+ }502502+503503+ if (router)504504+ neigh_node_free_ref(router);505505+506506+ /* apply hop penalty */507507+ batman_ogm_packet->tq = hop_penalty(batman_ogm_packet->tq, bat_priv);508508+509509+ bat_dbg(DBG_BATMAN, bat_priv,510510+ "Forwarding packet: tq_orig: %i, tq_avg: %i, "511511+ "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",512512+ in_tq, tq_avg, batman_ogm_packet->tq, in_ttl - 1,513513+ batman_ogm_packet->ttl);514514+515515+ batman_ogm_packet->seqno = htonl(batman_ogm_packet->seqno);516516+ batman_ogm_packet->tt_crc = htons(batman_ogm_packet->tt_crc);517517+518518+ /* switch of primaries first hop flag when forwarding */519519+ batman_ogm_packet->flags &= ~PRIMARIES_FIRST_HOP;520520+ if (directlink)521521+ batman_ogm_packet->flags |= DIRECTLINK;522522+ else523523+ batman_ogm_packet->flags &= ~DIRECTLINK;524524+525525+ bat_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet,526526+ BATMAN_OGM_LEN + tt_len(tt_num_changes),527527+ if_incoming, 0, bat_ogm_fwd_send_time());528528+}529529+530530+void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes)531531+{532532+ struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);533533+ struct batman_ogm_packet *batman_ogm_packet;534534+ struct hard_iface *primary_if;535535+ int vis_server;536536+537537+ vis_server = atomic_read(&bat_priv->vis_mode);538538+ primary_if = primary_if_get_selected(bat_priv);539539+540540+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;541541+542542+ /* change sequence number to network order */543543+ batman_ogm_packet->seqno =544544+ htonl((uint32_t)atomic_read(&hard_iface->seqno));545545+546546+ batman_ogm_packet->ttvn = atomic_read(&bat_priv->ttvn);547547+ batman_ogm_packet->tt_crc = htons((uint16_t)548548+ atomic_read(&bat_priv->tt_crc));549549+ if (tt_num_changes >= 0)550550+ batman_ogm_packet->tt_num_changes = tt_num_changes;551551+552552+ if (vis_server == VIS_TYPE_SERVER_SYNC)553553+ batman_ogm_packet->flags |= VIS_SERVER;554554+ else555555+ batman_ogm_packet->flags &= ~VIS_SERVER;556556+557557+ if ((hard_iface == primary_if) &&558558+ (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))559559+ batman_ogm_packet->gw_flags =560560+ (uint8_t)atomic_read(&bat_priv->gw_bandwidth);561561+ else562562+ batman_ogm_packet->gw_flags = NO_FLAGS;563563+564564+ atomic_inc(&hard_iface->seqno);565565+566566+ slide_own_bcast_window(hard_iface);567567+ bat_ogm_queue_add(bat_priv, hard_iface->packet_buff,568568+ hard_iface->packet_len, hard_iface, 1,569569+ bat_ogm_emit_send_time(bat_priv));570570+571571+ if (primary_if)572572+ hardif_free_ref(primary_if);573573+}574574+575575+static void bat_ogm_orig_update(struct bat_priv *bat_priv,576576+ struct orig_node *orig_node,577577+ const struct ethhdr *ethhdr,578578+ const struct batman_ogm_packet579579+ *batman_ogm_packet,580580+ struct hard_iface *if_incoming,581581+ const unsigned char *tt_buff, int is_duplicate)582582+{583583+ struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;584584+ struct neigh_node *router = NULL;585585+ struct orig_node *orig_node_tmp;586586+ struct hlist_node *node;587587+ uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;588588+589589+ bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "590590+ "Searching and updating originator entry of received packet\n");591591+592592+ rcu_read_lock();593593+ hlist_for_each_entry_rcu(tmp_neigh_node, node,594594+ &orig_node->neigh_list, list) {595595+ if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&596596+ (tmp_neigh_node->if_incoming == if_incoming) &&597597+ atomic_inc_not_zero(&tmp_neigh_node->refcount)) {598598+ if (neigh_node)599599+ neigh_node_free_ref(neigh_node);600600+ neigh_node = tmp_neigh_node;601601+ continue;602602+ }603603+604604+ if (is_duplicate)605605+ continue;606606+607607+ spin_lock_bh(&tmp_neigh_node->tq_lock);608608+ ring_buffer_set(tmp_neigh_node->tq_recv,609609+ &tmp_neigh_node->tq_index, 0);610610+ tmp_neigh_node->tq_avg =611611+ ring_buffer_avg(tmp_neigh_node->tq_recv);612612+ spin_unlock_bh(&tmp_neigh_node->tq_lock);613613+ }614614+615615+ if (!neigh_node) {616616+ struct orig_node *orig_tmp;617617+618618+ orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);619619+ if (!orig_tmp)620620+ goto unlock;621621+622622+ neigh_node = create_neighbor(orig_node, orig_tmp,623623+ ethhdr->h_source, if_incoming);624624+625625+ orig_node_free_ref(orig_tmp);626626+ if (!neigh_node)627627+ goto unlock;628628+ } else629629+ bat_dbg(DBG_BATMAN, bat_priv,630630+ "Updating existing last-hop neighbor of originator\n");631631+632632+ rcu_read_unlock();633633+634634+ orig_node->flags = batman_ogm_packet->flags;635635+ neigh_node->last_valid = jiffies;636636+637637+ spin_lock_bh(&neigh_node->tq_lock);638638+ ring_buffer_set(neigh_node->tq_recv,639639+ &neigh_node->tq_index,640640+ batman_ogm_packet->tq);641641+ neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);642642+ spin_unlock_bh(&neigh_node->tq_lock);643643+644644+ if (!is_duplicate) {645645+ orig_node->last_ttl = batman_ogm_packet->ttl;646646+ neigh_node->last_ttl = batman_ogm_packet->ttl;647647+ }648648+649649+ bonding_candidate_add(orig_node, neigh_node);650650+651651+ /* if this neighbor already is our next hop there is nothing652652+ * to change */653653+ router = orig_node_get_router(orig_node);654654+ if (router == neigh_node)655655+ goto update_tt;656656+657657+ /* if this neighbor does not offer a better TQ we won't consider it */658658+ if (router && (router->tq_avg > neigh_node->tq_avg))659659+ goto update_tt;660660+661661+ /* if the TQ is the same and the link not more symmetric we662662+ * won't consider it either */663663+ if (router && (neigh_node->tq_avg == router->tq_avg)) {664664+ orig_node_tmp = router->orig_node;665665+ spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);666666+ bcast_own_sum_orig =667667+ orig_node_tmp->bcast_own_sum[if_incoming->if_num];668668+ spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);669669+670670+ orig_node_tmp = neigh_node->orig_node;671671+ spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);672672+ bcast_own_sum_neigh =673673+ orig_node_tmp->bcast_own_sum[if_incoming->if_num];674674+ spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);675675+676676+ if (bcast_own_sum_orig >= bcast_own_sum_neigh)677677+ goto update_tt;678678+ }679679+680680+ update_route(bat_priv, orig_node, neigh_node);681681+682682+update_tt:683683+ /* I have to check for transtable changes only if the OGM has been684684+ * sent through a primary interface */685685+ if (((batman_ogm_packet->orig != ethhdr->h_source) &&686686+ (batman_ogm_packet->ttl > 2)) ||687687+ (batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))688688+ tt_update_orig(bat_priv, orig_node, tt_buff,689689+ batman_ogm_packet->tt_num_changes,690690+ batman_ogm_packet->ttvn,691691+ batman_ogm_packet->tt_crc);692692+693693+ if (orig_node->gw_flags != batman_ogm_packet->gw_flags)694694+ gw_node_update(bat_priv, orig_node,695695+ batman_ogm_packet->gw_flags);696696+697697+ orig_node->gw_flags = batman_ogm_packet->gw_flags;698698+699699+ /* restart gateway selection if fast or late switching was enabled */700700+ if ((orig_node->gw_flags) &&701701+ (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&702702+ (atomic_read(&bat_priv->gw_sel_class) > 2))703703+ gw_check_election(bat_priv, orig_node);704704+705705+ goto out;706706+707707+unlock:708708+ rcu_read_unlock();709709+out:710710+ if (neigh_node)711711+ neigh_node_free_ref(neigh_node);712712+ if (router)713713+ neigh_node_free_ref(router);714714+}715715+716716+static int bat_ogm_calc_tq(struct orig_node *orig_node,717717+ struct orig_node *orig_neigh_node,718718+ struct batman_ogm_packet *batman_ogm_packet,719719+ struct hard_iface *if_incoming)720720+{721721+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);722722+ struct neigh_node *neigh_node = NULL, *tmp_neigh_node;723723+ struct hlist_node *node;724724+ uint8_t total_count;725725+ uint8_t orig_eq_count, neigh_rq_count, tq_own;726726+ int tq_asym_penalty, ret = 0;727727+728728+ /* find corresponding one hop neighbor */729729+ rcu_read_lock();730730+ hlist_for_each_entry_rcu(tmp_neigh_node, node,731731+ &orig_neigh_node->neigh_list, list) {732732+733733+ if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig))734734+ continue;735735+736736+ if (tmp_neigh_node->if_incoming != if_incoming)737737+ continue;738738+739739+ if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))740740+ continue;741741+742742+ neigh_node = tmp_neigh_node;743743+ break;744744+ }745745+ rcu_read_unlock();746746+747747+ if (!neigh_node)748748+ neigh_node = create_neighbor(orig_neigh_node,749749+ orig_neigh_node,750750+ orig_neigh_node->orig,751751+ if_incoming);752752+753753+ if (!neigh_node)754754+ goto out;755755+756756+ /* if orig_node is direct neighbor update neigh_node last_valid */757757+ if (orig_node == orig_neigh_node)758758+ neigh_node->last_valid = jiffies;759759+760760+ orig_node->last_valid = jiffies;761761+762762+ /* find packet count of corresponding one hop neighbor */763763+ spin_lock_bh(&orig_node->ogm_cnt_lock);764764+ orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];765765+ neigh_rq_count = neigh_node->real_packet_count;766766+ spin_unlock_bh(&orig_node->ogm_cnt_lock);767767+768768+ /* pay attention to not get a value bigger than 100 % */769769+ total_count = (orig_eq_count > neigh_rq_count ?770770+ neigh_rq_count : orig_eq_count);771771+772772+ /* if we have too few packets (too less data) we set tq_own to zero */773773+ /* if we receive too few packets it is not considered bidirectional */774774+ if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||775775+ (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))776776+ tq_own = 0;777777+ else778778+ /* neigh_node->real_packet_count is never zero as we779779+ * only purge old information when getting new780780+ * information */781781+ tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count;782782+783783+ /*784784+ * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does785785+ * affect the nearly-symmetric links only a little, but786786+ * punishes asymmetric links more. This will give a value787787+ * between 0 and TQ_MAX_VALUE788788+ */789789+ tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *790790+ (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *791791+ (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *792792+ (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count)) /793793+ (TQ_LOCAL_WINDOW_SIZE *794794+ TQ_LOCAL_WINDOW_SIZE *795795+ TQ_LOCAL_WINDOW_SIZE);796796+797797+ batman_ogm_packet->tq = ((batman_ogm_packet->tq * tq_own798798+ * tq_asym_penalty) /799799+ (TQ_MAX_VALUE * TQ_MAX_VALUE));800800+801801+ bat_dbg(DBG_BATMAN, bat_priv,802802+ "bidirectional: "803803+ "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "804804+ "real recv = %2i, local tq: %3i, asym_penalty: %3i, "805805+ "total tq: %3i\n",806806+ orig_node->orig, orig_neigh_node->orig, total_count,807807+ neigh_rq_count, tq_own, tq_asym_penalty, batman_ogm_packet->tq);808808+809809+ /* if link has the minimum required transmission quality810810+ * consider it bidirectional */811811+ if (batman_ogm_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)812812+ ret = 1;813813+814814+out:815815+ if (neigh_node)816816+ neigh_node_free_ref(neigh_node);817817+ return ret;818818+}819819+820820+/* processes a batman packet for all interfaces, adjusts the sequence number and821821+ * finds out whether it is a duplicate.822822+ * returns:823823+ * 1 the packet is a duplicate824824+ * 0 the packet has not yet been received825825+ * -1 the packet is old and has been received while the seqno window826826+ * was protected. Caller should drop it.827827+ */828828+static int bat_ogm_update_seqnos(const struct ethhdr *ethhdr,829829+ const struct batman_ogm_packet830830+ *batman_ogm_packet,831831+ const struct hard_iface *if_incoming)832832+{833833+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);834834+ struct orig_node *orig_node;835835+ struct neigh_node *tmp_neigh_node;836836+ struct hlist_node *node;837837+ int is_duplicate = 0;838838+ int32_t seq_diff;839839+ int need_update = 0;840840+ int set_mark, ret = -1;841841+842842+ orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);843843+ if (!orig_node)844844+ return 0;845845+846846+ spin_lock_bh(&orig_node->ogm_cnt_lock);847847+ seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;848848+849849+ /* signalize caller that the packet is to be dropped. */850850+ if (window_protected(bat_priv, seq_diff,851851+ &orig_node->batman_seqno_reset))852852+ goto out;853853+854854+ rcu_read_lock();855855+ hlist_for_each_entry_rcu(tmp_neigh_node, node,856856+ &orig_node->neigh_list, list) {857857+858858+ is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,859859+ orig_node->last_real_seqno,860860+ batman_ogm_packet->seqno);861861+862862+ if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&863863+ (tmp_neigh_node->if_incoming == if_incoming))864864+ set_mark = 1;865865+ else866866+ set_mark = 0;867867+868868+ /* if the window moved, set the update flag. */869869+ need_update |= bit_get_packet(bat_priv,870870+ tmp_neigh_node->real_bits,871871+ seq_diff, set_mark);872872+873873+ tmp_neigh_node->real_packet_count =874874+ bit_packet_count(tmp_neigh_node->real_bits);875875+ }876876+ rcu_read_unlock();877877+878878+ if (need_update) {879879+ bat_dbg(DBG_BATMAN, bat_priv,880880+ "updating last_seqno: old %d, new %d\n",881881+ orig_node->last_real_seqno, batman_ogm_packet->seqno);882882+ orig_node->last_real_seqno = batman_ogm_packet->seqno;883883+ }884884+885885+ ret = is_duplicate;886886+887887+out:888888+ spin_unlock_bh(&orig_node->ogm_cnt_lock);889889+ orig_node_free_ref(orig_node);890890+ return ret;891891+}892892+893893+static void bat_ogm_process(const struct ethhdr *ethhdr,894894+ struct batman_ogm_packet *batman_ogm_packet,895895+ const unsigned char *tt_buff,896896+ struct hard_iface *if_incoming)897897+{898898+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);899899+ struct hard_iface *hard_iface;900900+ struct orig_node *orig_neigh_node, *orig_node;901901+ struct neigh_node *router = NULL, *router_router = NULL;902902+ struct neigh_node *orig_neigh_router = NULL;903903+ int has_directlink_flag;904904+ int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;905905+ int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;906906+ int is_duplicate;907907+ uint32_t if_incoming_seqno;908908+909909+ /* Silently drop when the batman packet is actually not a910910+ * correct packet.911911+ *912912+ * This might happen if a packet is padded (e.g. Ethernet has a913913+ * minimum frame length of 64 byte) and the aggregation interprets914914+ * it as an additional length.915915+ *916916+ * TODO: A more sane solution would be to have a bit in the917917+ * batman_ogm_packet to detect whether the packet is the last918918+ * packet in an aggregation. Here we expect that the padding919919+ * is always zero (or not 0x01)920920+ */921921+ if (batman_ogm_packet->packet_type != BAT_OGM)922922+ return;923923+924924+ /* could be changed by schedule_own_packet() */925925+ if_incoming_seqno = atomic_read(&if_incoming->seqno);926926+927927+ has_directlink_flag = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);928928+929929+ is_single_hop_neigh = (compare_eth(ethhdr->h_source,930930+ batman_ogm_packet->orig) ? 1 : 0);931931+932932+ bat_dbg(DBG_BATMAN, bat_priv,933933+ "Received BATMAN packet via NB: %pM, IF: %s [%pM] "934934+ "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "935935+ "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",936936+ ethhdr->h_source, if_incoming->net_dev->name,937937+ if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,938938+ batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,939939+ batman_ogm_packet->ttvn, batman_ogm_packet->tt_crc,940940+ batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq,941941+ batman_ogm_packet->ttl, batman_ogm_packet->version,942942+ has_directlink_flag);943943+944944+ rcu_read_lock();945945+ list_for_each_entry_rcu(hard_iface, &hardif_list, list) {946946+ if (hard_iface->if_status != IF_ACTIVE)947947+ continue;948948+949949+ if (hard_iface->soft_iface != if_incoming->soft_iface)950950+ continue;951951+952952+ if (compare_eth(ethhdr->h_source,953953+ hard_iface->net_dev->dev_addr))954954+ is_my_addr = 1;955955+956956+ if (compare_eth(batman_ogm_packet->orig,957957+ hard_iface->net_dev->dev_addr))958958+ is_my_orig = 1;959959+960960+ if (compare_eth(batman_ogm_packet->prev_sender,961961+ hard_iface->net_dev->dev_addr))962962+ is_my_oldorig = 1;963963+964964+ if (is_broadcast_ether_addr(ethhdr->h_source))965965+ is_broadcast = 1;966966+ }967967+ rcu_read_unlock();968968+969969+ if (batman_ogm_packet->version != COMPAT_VERSION) {970970+ bat_dbg(DBG_BATMAN, bat_priv,971971+ "Drop packet: incompatible batman version (%i)\n",972972+ batman_ogm_packet->version);973973+ return;974974+ }975975+976976+ if (is_my_addr) {977977+ bat_dbg(DBG_BATMAN, bat_priv,978978+ "Drop packet: received my own broadcast (sender: %pM"979979+ ")\n",980980+ ethhdr->h_source);981981+ return;982982+ }983983+984984+ if (is_broadcast) {985985+ bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "986986+ "ignoring all packets with broadcast source addr (sender: %pM"987987+ ")\n", ethhdr->h_source);988988+ return;989989+ }990990+991991+ if (is_my_orig) {992992+ unsigned long *word;993993+ int offset;994994+995995+ orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);996996+ if (!orig_neigh_node)997997+ return;998998+999999+ /* neighbor has to indicate direct link and it has to10001000+ * come via the corresponding interface */10011001+ /* save packet seqno for bidirectional check */10021002+ if (has_directlink_flag &&10031003+ compare_eth(if_incoming->net_dev->dev_addr,10041004+ batman_ogm_packet->orig)) {10051005+ offset = if_incoming->if_num * NUM_WORDS;10061006+10071007+ spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);10081008+ word = &(orig_neigh_node->bcast_own[offset]);10091009+ bit_mark(word,10101010+ if_incoming_seqno -10111011+ batman_ogm_packet->seqno - 2);10121012+ orig_neigh_node->bcast_own_sum[if_incoming->if_num] =10131013+ bit_packet_count(word);10141014+ spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);10151015+ }10161016+10171017+ bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "10181018+ "originator packet from myself (via neighbor)\n");10191019+ orig_node_free_ref(orig_neigh_node);10201020+ return;10211021+ }10221022+10231023+ if (is_my_oldorig) {10241024+ bat_dbg(DBG_BATMAN, bat_priv,10251025+ "Drop packet: ignoring all rebroadcast echos (sender: "10261026+ "%pM)\n", ethhdr->h_source);10271027+ return;10281028+ }10291029+10301030+ orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);10311031+ if (!orig_node)10321032+ return;10331033+10341034+ is_duplicate = bat_ogm_update_seqnos(ethhdr, batman_ogm_packet,10351035+ if_incoming);10361036+10371037+ if (is_duplicate == -1) {10381038+ bat_dbg(DBG_BATMAN, bat_priv,10391039+ "Drop packet: packet within seqno protection time "10401040+ "(sender: %pM)\n", ethhdr->h_source);10411041+ goto out;10421042+ }10431043+10441044+ if (batman_ogm_packet->tq == 0) {10451045+ bat_dbg(DBG_BATMAN, bat_priv,10461046+ "Drop packet: originator packet with tq equal 0\n");10471047+ goto out;10481048+ }10491049+10501050+ router = orig_node_get_router(orig_node);10511051+ if (router)10521052+ router_router = orig_node_get_router(router->orig_node);10531053+10541054+ /* avoid temporary routing loops */10551055+ if (router && router_router &&10561056+ (compare_eth(router->addr, batman_ogm_packet->prev_sender)) &&10571057+ !(compare_eth(batman_ogm_packet->orig,10581058+ batman_ogm_packet->prev_sender)) &&10591059+ (compare_eth(router->addr, router_router->addr))) {10601060+ bat_dbg(DBG_BATMAN, bat_priv,10611061+ "Drop packet: ignoring all rebroadcast packets that "10621062+ "may make me loop (sender: %pM)\n", ethhdr->h_source);10631063+ goto out;10641064+ }10651065+10661066+ /* if sender is a direct neighbor the sender mac equals10671067+ * originator mac */10681068+ orig_neigh_node = (is_single_hop_neigh ?10691069+ orig_node :10701070+ get_orig_node(bat_priv, ethhdr->h_source));10711071+ if (!orig_neigh_node)10721072+ goto out;10731073+10741074+ orig_neigh_router = orig_node_get_router(orig_neigh_node);10751075+10761076+ /* drop packet if sender is not a direct neighbor and if we10771077+ * don't route towards it */10781078+ if (!is_single_hop_neigh && (!orig_neigh_router)) {10791079+ bat_dbg(DBG_BATMAN, bat_priv,10801080+ "Drop packet: OGM via unknown neighbor!\n");10811081+ goto out_neigh;10821082+ }10831083+10841084+ is_bidirectional = bat_ogm_calc_tq(orig_node, orig_neigh_node,10851085+ batman_ogm_packet, if_incoming);10861086+10871087+ bonding_save_primary(orig_node, orig_neigh_node, batman_ogm_packet);10881088+10891089+ /* update ranking if it is not a duplicate or has the same10901090+ * seqno and similar ttl as the non-duplicate */10911091+ if (is_bidirectional &&10921092+ (!is_duplicate ||10931093+ ((orig_node->last_real_seqno == batman_ogm_packet->seqno) &&10941094+ (orig_node->last_ttl - 3 <= batman_ogm_packet->ttl))))10951095+ bat_ogm_orig_update(bat_priv, orig_node, ethhdr,10961096+ batman_ogm_packet, if_incoming,10971097+ tt_buff, is_duplicate);10981098+10991099+ /* is single hop (direct) neighbor */11001100+ if (is_single_hop_neigh) {11011101+11021102+ /* mark direct link on incoming interface */11031103+ bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet,11041104+ 1, if_incoming);11051105+11061106+ bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "11071107+ "rebroadcast neighbor packet with direct link flag\n");11081108+ goto out_neigh;11091109+ }11101110+11111111+ /* multihop originator */11121112+ if (!is_bidirectional) {11131113+ bat_dbg(DBG_BATMAN, bat_priv,11141114+ "Drop packet: not received via bidirectional link\n");11151115+ goto out_neigh;11161116+ }11171117+11181118+ if (is_duplicate) {11191119+ bat_dbg(DBG_BATMAN, bat_priv,11201120+ "Drop packet: duplicate packet received\n");11211121+ goto out_neigh;11221122+ }11231123+11241124+ bat_dbg(DBG_BATMAN, bat_priv,11251125+ "Forwarding packet: rebroadcast originator packet\n");11261126+ bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet, 0, if_incoming);11271127+11281128+out_neigh:11291129+ if ((orig_neigh_node) && (!is_single_hop_neigh))11301130+ orig_node_free_ref(orig_neigh_node);11311131+out:11321132+ if (router)11331133+ neigh_node_free_ref(router);11341134+ if (router_router)11351135+ neigh_node_free_ref(router_router);11361136+ if (orig_neigh_router)11371137+ neigh_node_free_ref(orig_neigh_router);11381138+11391139+ orig_node_free_ref(orig_node);11401140+}11411141+11421142+void bat_ogm_receive(const struct ethhdr *ethhdr, unsigned char *packet_buff,11431143+ int packet_len, struct hard_iface *if_incoming)11441144+{11451145+ struct batman_ogm_packet *batman_ogm_packet;11461146+ int buff_pos = 0;11471147+ unsigned char *tt_buff;11481148+11491149+ batman_ogm_packet = (struct batman_ogm_packet *)packet_buff;11501150+11511151+ /* unpack the aggregated packets and process them one by one */11521152+ do {11531153+ /* network to host order for our 32bit seqno and the11541154+ orig_interval */11551155+ batman_ogm_packet->seqno = ntohl(batman_ogm_packet->seqno);11561156+ batman_ogm_packet->tt_crc = ntohs(batman_ogm_packet->tt_crc);11571157+11581158+ tt_buff = packet_buff + buff_pos + BATMAN_OGM_LEN;11591159+11601160+ bat_ogm_process(ethhdr, batman_ogm_packet,11611161+ tt_buff, if_incoming);11621162+11631163+ buff_pos += BATMAN_OGM_LEN +11641164+ tt_len(batman_ogm_packet->tt_num_changes);11651165+11661166+ batman_ogm_packet = (struct batman_ogm_packet *)11671167+ (packet_buff + buff_pos);11681168+ } while (bat_ogm_aggr_packet(buff_pos, packet_len,11691169+ batman_ogm_packet->tt_num_changes));11701170+}
+15-39
net/batman-adv/hard-interface.c
···2828#include "bat_sysfs.h"2929#include "originator.h"3030#include "hash.h"3131+#include "bat_ogm.h"31323233#include <linux/if_arp.h>3334···132131 struct hard_iface *new_hard_iface)133132{134133 struct hard_iface *curr_hard_iface;135135- struct batman_packet *batman_packet;136134137135 ASSERT_RTNL();138136···147147 if (!new_hard_iface)148148 return;149149150150- batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff);151151- batman_packet->flags = PRIMARIES_FIRST_HOP;152152- batman_packet->ttl = TTL;153153-150150+ bat_ogm_init_primary(new_hard_iface);154151 primary_if_update_addr(bat_priv);155152}156153···157160 return true;158161159162 return false;160160-}161161-162162-static void update_mac_addresses(struct hard_iface *hard_iface)163163-{164164- memcpy(((struct batman_packet *)(hard_iface->packet_buff))->orig,165165- hard_iface->net_dev->dev_addr, ETH_ALEN);166166- memcpy(((struct batman_packet *)(hard_iface->packet_buff))->prev_sender,167167- hard_iface->net_dev->dev_addr, ETH_ALEN);168163}169164170165static void check_known_mac_addr(const struct net_device *net_dev)···233244234245 bat_priv = netdev_priv(hard_iface->soft_iface);235246236236- update_mac_addresses(hard_iface);247247+ bat_ogm_update_mac(hard_iface);237248 hard_iface->if_status = IF_TO_BE_ACTIVATED;238249239250 /**···272283 const char *iface_name)273284{274285 struct bat_priv *bat_priv;275275- struct batman_packet *batman_packet;276286 struct net_device *soft_iface;277287 int ret;278288···306318307319 hard_iface->soft_iface = soft_iface;308320 bat_priv = netdev_priv(hard_iface->soft_iface);309309- hard_iface->packet_len = BAT_PACKET_LEN;310310- hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);321321+322322+ bat_ogm_init(hard_iface);311323312324 if (!hard_iface->packet_buff) {313325 bat_err(hard_iface->soft_iface, "Can't add interface packet "···315327 ret = -ENOMEM;316328 goto err;317329 }318318-319319- batman_packet = (struct batman_packet *)(hard_iface->packet_buff);320320- batman_packet->packet_type = BAT_PACKET;321321- batman_packet->version = COMPAT_VERSION;322322- batman_packet->flags = NO_FLAGS;323323- batman_packet->ttl = 2;324324- batman_packet->tq = TQ_MAX_VALUE;325325- batman_packet->tt_num_changes = 0;326326- batman_packet->ttvn = 0;327330328331 hard_iface->if_num = bat_priv->num_ifaces;329332 bat_priv->num_ifaces++;···360381 hard_iface->net_dev->name);361382362383 /* begin scheduling originator messages on that interface */363363- schedule_own_packet(hard_iface);384384+ schedule_bat_ogm(hard_iface);364385365386out:366387 return 0;···434455 dev_hold(net_dev);435456436457 hard_iface = kmalloc(sizeof(*hard_iface), GFP_ATOMIC);437437- if (!hard_iface) {438438- pr_err("Can't add interface (%s): out of memory\n",439439- net_dev->name);458458+ if (!hard_iface)440459 goto release_dev;441441- }442460443461 ret = sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);444462 if (ret)···527551 goto hardif_put;528552529553 check_known_mac_addr(hard_iface->net_dev);530530- update_mac_addresses(hard_iface);554554+ bat_ogm_update_mac(hard_iface);531555532556 bat_priv = netdev_priv(hard_iface->soft_iface);533557 primary_if = primary_if_get_selected(bat_priv);···556580 struct net_device *orig_dev)557581{558582 struct bat_priv *bat_priv;559559- struct batman_packet *batman_packet;583583+ struct batman_ogm_packet *batman_ogm_packet;560584 struct hard_iface *hard_iface;561585 int ret;562586···588612 if (hard_iface->if_status != IF_ACTIVE)589613 goto err_free;590614591591- batman_packet = (struct batman_packet *)skb->data;615615+ batman_ogm_packet = (struct batman_ogm_packet *)skb->data;592616593593- if (batman_packet->version != COMPAT_VERSION) {617617+ if (batman_ogm_packet->version != COMPAT_VERSION) {594618 bat_dbg(DBG_BATMAN, bat_priv,595619 "Drop packet: incompatible batman version (%i)\n",596596- batman_packet->version);620620+ batman_ogm_packet->version);597621 goto err_free;598622 }599623600624 /* all receive handlers return whether they received or reused601625 * the supplied skb. if not, we have to free the skb. */602626603603- switch (batman_packet->packet_type) {627627+ switch (batman_ogm_packet->packet_type) {604628 /* batman originator packet */605605- case BAT_PACKET:606606- ret = recv_bat_packet(skb, hard_iface);629629+ case BAT_OGM:630630+ ret = recv_bat_ogm_packet(skb, hard_iface);607631 break;608632609633 /* batman icmp packet */
-2
net/batman-adv/main.c
···117117 goto end;118118119119err:120120- pr_err("Unable to allocate memory for mesh information structures: "121121- "out of mem ?\n");122120 mesh_free(soft_iface);123121 return -1;124122