@@ -357,8 +357,16 @@ static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
return gw_bandwidth_set(net_dev, buff, count);
}
+void update_mcast_tracker(struct net_device *net_dev)
+{
+ struct bat_priv *bat_priv = netdev_priv(net_dev);
+
+ if (!atomic_read(&bat_priv->mcast_tracker_interval))
+ mcast_tracker_reset(bat_priv);
+}
+
static ssize_t show_mcast_mode(struct kobject *kobj, struct attribute *attr,
- char *buff)
+ char *buff)
{
struct device *dev = to_dev(kobj->parent);
struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
@@ -509,7 +517,8 @@ BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
-BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
+BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX,
+ update_mcast_tracker);
BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL);
BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
post_gw_deselect);
@@ -32,6 +32,7 @@
#include "gateway_client.h"
#include "types.h"
#include "vis.h"
+#include "multicast.h"
#include "hash.h"
struct list_head if_list;
@@ -108,6 +109,9 @@ int mesh_init(struct net_device *soft_iface)
if (vis_init(bat_priv) < 1)
goto err;
+ if (mcast_init(bat_priv) < 1)
+ goto err;
+
atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
goto end;
@@ -138,6 +142,7 @@ void mesh_free(struct net_device *soft_iface)
hna_global_free(bat_priv);
softif_neigh_purge(bat_priv);
+ mcast_free(bat_priv);
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
}
@@ -22,6 +22,48 @@
#include "main.h"
#include "multicast.h"
+/* how long to wait until sending a multicast tracker packet */
+static int tracker_send_delay(struct bat_priv *bat_priv)
+{
+ int tracker_interval = atomic_read(&bat_priv->mcast_tracker_interval);
+
+ /* auto mode, set to 1/2 ogm interval */
+ if (!tracker_interval)
+ tracker_interval = atomic_read(&bat_priv->orig_interval) / 2;
+
+ /* multicast tracker packets get half as much jitter as ogms as they're
+ * limited down to JITTER and not JITTER*2 */
+ return msecs_to_jiffies(tracker_interval -
+ JITTER/2 + (random32() % JITTER));
+}
+
+static void start_mcast_tracker(struct bat_priv *bat_priv)
+{
+ /* adding some jitter */
+ unsigned long tracker_interval = tracker_send_delay(bat_priv);
+ queue_delayed_work(bat_event_workqueue, &bat_priv->mcast_tracker_work,
+ tracker_interval);
+}
+
+static void stop_mcast_tracker(struct bat_priv *bat_priv)
+{
+ cancel_delayed_work_sync(&bat_priv->mcast_tracker_work);
+}
+
+void mcast_tracker_reset(struct bat_priv *bat_priv)
+{
+ stop_mcast_tracker(bat_priv);
+ start_mcast_tracker(bat_priv);
+}
+
+static void mcast_tracker_timer(struct work_struct *work)
+{
+ struct bat_priv *bat_priv = container_of(work, struct bat_priv,
+ mcast_tracker_work.work);
+
+ start_mcast_tracker(bat_priv);
+}
+
int mcast_tracker_interval_set(struct net_device *net_dev, char *buff,
size_t count)
{
@@ -68,6 +110,8 @@ ok:
atomic_set(&bat_priv->mcast_tracker_interval, new_tracker_interval);
+ mcast_tracker_reset(bat_priv);
+
return count;
}
@@ -119,3 +163,16 @@ ok:
return count;
}
+
+int mcast_init(struct bat_priv *bat_priv)
+{
+ INIT_DELAYED_WORK(&bat_priv->mcast_tracker_work, mcast_tracker_timer);
+ start_mcast_tracker(bat_priv);
+
+ return 1;
+}
+
+void mcast_free(struct bat_priv *bat_priv)
+{
+ stop_mcast_tracker(bat_priv);
+}
@@ -26,5 +26,8 @@ int mcast_tracker_interval_set(struct net_device *net_dev, char *buff,
size_t count);
int mcast_tracker_timeout_set(struct net_device *net_dev, char *buff,
size_t count);
+void mcast_tracker_reset(struct bat_priv *bat_priv);
+int mcast_init(struct bat_priv *bat_priv);
+void mcast_free(struct bat_priv *bat_priv);
#endif /* _NET_BATMAN_ADV_MULTICAST_H_ */
@@ -173,6 +173,7 @@ struct bat_priv {
struct delayed_work hna_work;
struct delayed_work orig_work;
struct delayed_work vis_work;
+ struct delayed_work mcast_tracker_work;
struct gw_node *curr_gw;
struct vis_info *my_vis_info;
};