コード例 #1
0
ファイル: bridge_loop_avoidance.c プロジェクト: SimonPe/linux
/* periodic work to do:
 *  * purge structures when they are too old
 *  * send announcements
 */
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_node *node;
	struct hlist_head *head;
	struct batadv_backbone_gw *backbone_gw;
	struct batadv_hashtable *hash;
	struct batadv_hard_iface *primary_if;
	int i;

	delayed_work = container_of(work, struct delayed_work, work);
	priv_bla = container_of(delayed_work, struct batadv_priv_bla, work);
	bat_priv = container_of(priv_bla, struct batadv_priv, bla);
	primary_if = batadv_primary_if_get_selected(bat_priv);
	if (!primary_if)
		goto out;

	batadv_bla_purge_claims(bat_priv, primary_if, 0);
	batadv_bla_purge_backbone_gw(bat_priv, 0);

	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
		goto out;

	hash = bat_priv->bla.backbone_hash;
	if (!hash)
		goto out;

	for (i = 0; i < hash->size; i++) {
		head = &hash->table[i];

		rcu_read_lock();
		hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
			if (!batadv_compare_eth(backbone_gw->orig,
						primary_if->net_dev->dev_addr))
				continue;

			backbone_gw->lasttime = jiffies;

			batadv_bla_send_announce(bat_priv, backbone_gw);
		}
		rcu_read_unlock();
	}
out:
	if (primary_if)
		batadv_hardif_free_ref(primary_if);

	batadv_bla_start_timer(bat_priv);
}
コード例 #2
0
ファイル: bridge_loop_avoidance.c プロジェクト: Dyoed/ath
/**
 * batadv_bla_update_orig_address
 * @bat_priv: the bat priv with all the soft interface information
 * @primary_if: the new selected primary_if
 * @oldif: the old primary interface, may be NULL
 *
 * Update the backbone gateways when the own orig address changes.
 */
void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
				    struct batadv_hard_iface *primary_if,
				    struct batadv_hard_iface *oldif)
{
	struct batadv_bla_backbone_gw *backbone_gw;
	struct hlist_head *head;
	struct batadv_hashtable *hash;
	__be16 group;
	int i;

	/* reset bridge loop avoidance group id */
	group = htons(crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN));
	bat_priv->bla.claim_dest.group = group;

	/* purge everything when bridge loop avoidance is turned off */
	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
		oldif = NULL;

	if (!oldif) {
		batadv_bla_purge_claims(bat_priv, NULL, 1);
		batadv_bla_purge_backbone_gw(bat_priv, 1);
		return;
	}

	hash = bat_priv->bla.backbone_hash;
	if (!hash)
		return;

	for (i = 0; i < hash->size; i++) {
		head = &hash->table[i];

		rcu_read_lock();
		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
			/* own orig still holds the old value. */
			if (!batadv_compare_eth(backbone_gw->orig,
						oldif->net_dev->dev_addr))
				continue;

			ether_addr_copy(backbone_gw->orig,
					primary_if->net_dev->dev_addr);
			/* send an announce frame so others will ask for our
			 * claims and update their tables.
			 */
			batadv_bla_send_announce(bat_priv, backbone_gw);
		}
		rcu_read_unlock();
	}
}
コード例 #3
0
ファイル: bridge_loop_avoidance.c プロジェクト: SimonPe/linux
/* @bat_priv: the bat priv with all the soft interface information
 * @vid: the vid where the request came on
 *
 * Repeat all of our own claims, and finally send an ANNOUNCE frame
 * to allow the requester another check if the CRC is correct now.
 */
static void batadv_bla_answer_request(struct batadv_priv *bat_priv,
				      struct batadv_hard_iface *primary_if,
				      short vid)
{
	struct hlist_node *node;
	struct hlist_head *head;
	struct batadv_hashtable *hash;
	struct batadv_claim *claim;
	struct batadv_backbone_gw *backbone_gw;
	int i;

	batadv_dbg(BATADV_DBG_BLA, bat_priv,
		   "bla_answer_request(): received a claim request, send all of our own claims again\n");

	backbone_gw = batadv_backbone_hash_find(bat_priv,
						primary_if->net_dev->dev_addr,
						vid);
	if (!backbone_gw)
		return;

	hash = bat_priv->bla.claim_hash;
	for (i = 0; i < hash->size; i++) {
		head = &hash->table[i];

		rcu_read_lock();
		hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
			/* only own claims are interesting */
			if (claim->backbone_gw != backbone_gw)
				continue;

			batadv_bla_send_claim(bat_priv, claim->addr, claim->vid,
					      BATADV_CLAIM_TYPE_CLAIM);
		}
		rcu_read_unlock();
	}

	/* finally, send an announcement frame */
	batadv_bla_send_announce(bat_priv, backbone_gw);
	batadv_backbone_gw_free_ref(backbone_gw);
}
コード例 #4
0
ファイル: bridge_loop_avoidance.c プロジェクト: Dyoed/ath
/**
 * batadv_bla_get_backbone_gw
 * @bat_priv: the bat priv with all the soft interface information
 * @orig: the mac address of the originator
 * @vid: the VLAN ID
 * @own_backbone: set if the requested backbone is local
 *
 * searches for the backbone gw or creates a new one if it could not
 * be found.
 */
static struct batadv_bla_backbone_gw *
batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig,
			   unsigned short vid, bool own_backbone)
{
	struct batadv_bla_backbone_gw *entry;
	struct batadv_orig_node *orig_node;
	int hash_added;

	entry = batadv_backbone_hash_find(bat_priv, orig, vid);

	if (entry)
		return entry;

	batadv_dbg(BATADV_DBG_BLA, bat_priv,
		   "bla_get_backbone_gw(): not found (%pM, %d), creating new entry\n",
		   orig, BATADV_PRINT_VID(vid));

	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
	if (!entry)
		return NULL;

	entry->vid = vid;
	entry->lasttime = jiffies;
	entry->crc = BATADV_BLA_CRC_INIT;
	entry->bat_priv = bat_priv;
	atomic_set(&entry->request_sent, 0);
	atomic_set(&entry->wait_periods, 0);
	ether_addr_copy(entry->orig, orig);

	/* one for the hash, one for returning */
	atomic_set(&entry->refcount, 2);

	hash_added = batadv_hash_add(bat_priv->bla.backbone_hash,
				     batadv_compare_backbone_gw,
				     batadv_choose_backbone_gw, entry,
				     &entry->hash_entry);

	if (unlikely(hash_added != 0)) {
		/* hash failed, free the structure */
		kfree(entry);
		return NULL;
	}

	/* this is a gateway now, remove any TT entry on this VLAN */
	orig_node = batadv_orig_hash_find(bat_priv, orig);
	if (orig_node) {
		batadv_tt_global_del_orig(bat_priv, orig_node, vid,
					  "became a backbone gateway");
		batadv_orig_node_free_ref(orig_node);
	}

	if (own_backbone) {
		batadv_bla_send_announce(bat_priv, entry);

		/* this will be decreased in the worker thread */
		atomic_inc(&entry->request_sent);
		atomic_set(&entry->wait_periods, BATADV_BLA_WAIT_PERIODS);
		atomic_inc(&bat_priv->bla.num_requests);
	}

	return entry;
}
コード例 #5
0
ファイル: bridge_loop_avoidance.c プロジェクト: Dyoed/ath
/* periodic work to do:
 *  * purge structures when they are too old
 *  * send announcements
 */
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;
	int i;

	delayed_work = container_of(work, struct delayed_work, work);
	priv_bla = container_of(delayed_work, struct batadv_priv_bla, work);
	bat_priv = container_of(priv_bla, struct batadv_priv, bla);
	primary_if = batadv_primary_if_get_selected(bat_priv);
	if (!primary_if)
		goto out;

	batadv_bla_purge_claims(bat_priv, primary_if, 0);
	batadv_bla_purge_backbone_gw(bat_priv, 0);

	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
		goto out;

	hash = bat_priv->bla.backbone_hash;
	if (!hash)
		goto out;

	for (i = 0; i < hash->size; i++) {
		head = &hash->table[i];

		rcu_read_lock();
		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
			if (!batadv_compare_eth(backbone_gw->orig,
						primary_if->net_dev->dev_addr))
				continue;

			backbone_gw->lasttime = jiffies;

			batadv_bla_send_announce(bat_priv, backbone_gw);

			/* request_sent is only set after creation to avoid
			 * problems when we are not yet known as backbone gw
			 * in the backbone.
			 *
			 * We can reset this now after we waited some periods
			 * to give bridge forward delays and bla group forming
			 * some grace time.
			 */

			if (atomic_read(&backbone_gw->request_sent) == 0)
				continue;

			if (!atomic_dec_and_test(&backbone_gw->wait_periods))
				continue;

			atomic_dec(&backbone_gw->bat_priv->bla.num_requests);
			atomic_set(&backbone_gw->request_sent, 0);
		}
		rcu_read_unlock();
	}
out:
	if (primary_if)
		batadv_hardif_free_ref(primary_if);

	queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
			   msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
}