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; }