int interface_tx(struct sk_buff *skb, struct net_device *dev)
{
	struct unicast_packet *unicast_packet;
	struct bcast_packet *bcast_packet;
	struct orig_node *orig_node;
	struct neigh_node *router;
	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
	struct bat_priv *priv = netdev_priv(dev);
	struct batman_if *batman_if;
	struct bat_priv *bat_priv;
	uint8_t dstaddr[6];
	int data_len = skb->len;
	unsigned long flags;

	if (atomic_read(&module_state) != MODULE_ACTIVE)
		goto dropped;

	/* FIXME: each batman_if will be attached to a softif */
	bat_priv = netdev_priv(soft_device);

	dev->trans_start = jiffies;
	/* TODO: check this for locks */
	hna_local_add(ethhdr->h_source);

	/* ethernet packet should be broadcasted */
	if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {

		if (my_skb_push(skb, sizeof(struct bcast_packet)) < 0)
			goto dropped;

		bcast_packet = (struct bcast_packet *)skb->data;
		bcast_packet->version = COMPAT_VERSION;
		bcast_packet->ttl = TTL;

		/* batman packet type: broadcast */
		bcast_packet->packet_type = BAT_BCAST;

		/* hw address of first interface is the orig mac because only
		 * this mac is known throughout the mesh */
		memcpy(bcast_packet->orig, main_if_addr, ETH_ALEN);

		/* set broadcast sequence number */
		bcast_packet->seqno = htonl(bcast_seqno);

		/* broadcast packet. on success, increase seqno. */
		if (add_bcast_packet_to_list(skb) == NETDEV_TX_OK)
			bcast_seqno++;

		/* a copy is stored in the bcast list, therefore removing
		 * the original skb. */
		kfree_skb(skb);

	/* unicast packet */
	} else {
		spin_lock_irqsave(&orig_hash_lock, flags);
		/* get routing information */
		orig_node = ((struct orig_node *)hash_find(orig_hash,
							   ethhdr->h_dest));

		/* check for hna host */
		if (!orig_node)
			orig_node = transtable_search(ethhdr->h_dest);

		router = find_router(orig_node, NULL);

		if (!router)
			goto unlock;

		/* don't lock while sending the packets ... we therefore
		 * copy the required data before sending */

		batman_if = router->if_incoming;
		memcpy(dstaddr, router->addr, ETH_ALEN);

		spin_unlock_irqrestore(&orig_hash_lock, flags);

		if (batman_if->if_status != IF_ACTIVE)
			goto dropped;

		if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
			goto dropped;

		unicast_packet = (struct unicast_packet *)skb->data;

		unicast_packet->version = COMPAT_VERSION;
		/* batman packet type: unicast */
		unicast_packet->packet_type = BAT_UNICAST;
		/* set unicast ttl */
		unicast_packet->ttl = TTL;
		/* copy the destination for faster routing */
		memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);

		send_skb_packet(skb, batman_if, dstaddr);
	}

	priv->stats.tx_packets++;
	priv->stats.tx_bytes += data_len;
	goto end;

unlock:
	spin_unlock_irqrestore(&orig_hash_lock, flags);
dropped:
	priv->stats.tx_dropped++;
	kfree_skb(skb);
end:
	return NETDEV_TX_OK;
}
static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
{
	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
	struct bat_priv *bat_priv = netdev_priv(soft_iface);
	struct hard_iface *primary_if = NULL;
	struct bcast_packet *bcast_packet;
	struct vlan_ethhdr *vhdr;
	static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00,
						   0x00};
	unsigned int header_len = 0;
	int data_len = skb->len, ret;
	short vid __maybe_unused = -1;
	bool do_bcast = false;

	if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
		goto dropped;

	soft_iface->trans_start = jiffies;

	switch (ntohs(ethhdr->h_proto)) {
	case ETH_P_8021Q:
		vhdr = (struct vlan_ethhdr *)skb->data;
		vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;

		if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN)
			break;

		/* fall through */
	case ETH_P_BATMAN:
		goto dropped;
	}

	if (bla_tx(bat_priv, skb, vid))
		goto dropped;

	/* Register the client MAC in the transtable */
	tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);

	/* don't accept stp packets. STP does not help in meshes.
	 * better use the bridge loop avoidance ...
	 */
	if (compare_eth(ethhdr->h_dest, stp_addr))
		goto dropped;

	if (is_multicast_ether_addr(ethhdr->h_dest)) {
		do_bcast = true;

		switch (atomic_read(&bat_priv->gw_mode)) {
		case GW_MODE_SERVER:
			/* gateway servers should not send dhcp
			 * requests into the mesh */
			ret = gw_is_dhcp_target(skb, &header_len);
			if (ret)
				goto dropped;
			break;
		case GW_MODE_CLIENT:
			/* gateway clients should send dhcp requests
			 * via unicast to their gateway */
			ret = gw_is_dhcp_target(skb, &header_len);
			if (ret)
				do_bcast = false;
			break;
		case GW_MODE_OFF:
		default:
			break;
		}
	}

	/* ethernet packet should be broadcasted */
	if (do_bcast) {
		primary_if = primary_if_get_selected(bat_priv);
		if (!primary_if)
			goto dropped;

		if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
			goto dropped;

		bcast_packet = (struct bcast_packet *)skb->data;
		bcast_packet->header.version = COMPAT_VERSION;
		bcast_packet->header.ttl = TTL;

		/* batman packet type: broadcast */
		bcast_packet->header.packet_type = BAT_BCAST;

		/* hw address of first interface is the orig mac because only
		 * this mac is known throughout the mesh */
		memcpy(bcast_packet->orig,
		       primary_if->net_dev->dev_addr, ETH_ALEN);

		/* set broadcast sequence number */
		bcast_packet->seqno =
			htonl(atomic_inc_return(&bat_priv->bcast_seqno));

		add_bcast_packet_to_list(bat_priv, skb, 1);

		/* a copy is stored in the bcast list, therefore removing
		 * the original skb. */
		kfree_skb(skb);

	/* unicast packet */
	} else {
		if (atomic_read(&bat_priv->gw_mode) != GW_MODE_OFF) {
			ret = gw_out_of_range(bat_priv, skb, ethhdr);
			if (ret)
				goto dropped;
		}

		ret = unicast_send_skb(skb, bat_priv);
		if (ret != 0)
			goto dropped_freed;
	}

	bat_priv->stats.tx_packets++;
	bat_priv->stats.tx_bytes += data_len;
	goto end;

dropped:
	kfree_skb(skb);
dropped_freed:
	bat_priv->stats.tx_dropped++;
end:
	if (primary_if)
		hardif_free_ref(primary_if);
	return NETDEV_TX_OK;
}