batman-adv: Clean up untagged vlan when destroying via rtnl-link
[cascardo/linux.git] / net / batman-adv / soft-interface.c
index 8a136b6..287a387 100644 (file)
@@ -186,7 +186,6 @@ static int batadv_interface_tx(struct sk_buff *skb,
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
        struct batadv_hard_iface *primary_if = NULL;
        struct batadv_bcast_packet *bcast_packet;
-       __be16 ethertype = htons(ETH_P_BATMAN);
        static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00,
                                              0x00, 0x00};
        static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
@@ -208,7 +207,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
        if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
                goto dropped;
 
-       soft_iface->trans_start = jiffies;
+       netif_trans_update(soft_iface);
        vid = batadv_get_vid(skb, 0);
        ethhdr = eth_hdr(skb);
 
@@ -216,7 +215,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
        case ETH_P_8021Q:
                vhdr = vlan_eth_hdr(skb);
 
-               if (vhdr->h_vlan_encapsulated_proto != ethertype) {
+               /* drop batman-in-batman packets to prevent loops */
+               if (vhdr->h_vlan_encapsulated_proto != htons(ETH_P_BATMAN)) {
                        network_offset += VLAN_HLEN;
                        break;
                }
@@ -381,13 +381,29 @@ end:
        return NETDEV_TX_OK;
 }
 
+/**
+ * batadv_interface_rx - receive ethernet frame on local batman-adv interface
+ * @soft_iface: local interface which will receive the ethernet frame
+ * @skb: ethernet frame for @soft_iface
+ * @hdr_size: size of already parsed batman-adv header
+ * @orig_node: originator from which the batman-adv packet was sent
+ *
+ * Sends a ethernet frame to the receive path of the local @soft_iface.
+ * skb->data has still point to the batman-adv header with the size @hdr_size.
+ * The caller has to have parsed this header already and made sure that at least
+ * @hdr_size bytes are still available for pull in @skb.
+ *
+ * The packet may still get dropped. This can happen when the encapsulated
+ * ethernet frame is invalid or contains again an batman-adv packet. Also
+ * unicast packets will be dropped directly when it was sent between two
+ * isolated clients.
+ */
 void batadv_interface_rx(struct net_device *soft_iface,
-                        struct sk_buff *skb, struct batadv_hard_iface *recv_if,
-                        int hdr_size, struct batadv_orig_node *orig_node)
+                        struct sk_buff *skb, int hdr_size,
+                        struct batadv_orig_node *orig_node)
 {
        struct batadv_bcast_packet *batadv_bcast_packet;
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
-       __be16 ethertype = htons(ETH_P_BATMAN);
        struct vlan_ethhdr *vhdr;
        struct ethhdr *ethhdr;
        unsigned short vid;
@@ -396,10 +412,6 @@ void batadv_interface_rx(struct net_device *soft_iface,
        batadv_bcast_packet = (struct batadv_bcast_packet *)skb->data;
        is_bcast = (batadv_bcast_packet->packet_type == BATADV_BCAST);
 
-       /* check if enough space is available for pulling, and pull */
-       if (!pskb_may_pull(skb, hdr_size))
-               goto dropped;
-
        skb_pull_rcsum(skb, hdr_size);
        skb_reset_mac_header(skb);
 
@@ -421,7 +433,8 @@ void batadv_interface_rx(struct net_device *soft_iface,
 
                vhdr = (struct vlan_ethhdr *)skb->data;
 
-               if (vhdr->h_vlan_encapsulated_proto != ethertype)
+               /* drop batman-in-batman packets to prevent loops */
+               if (vhdr->h_vlan_encapsulated_proto != htons(ETH_P_BATMAN))
                        break;
 
                /* fall through */
@@ -543,7 +556,7 @@ struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
 }
 
 /**
- * batadv_create_vlan - allocate the needed resources for a new vlan
+ * batadv_softif_create_vlan - allocate the needed resources for a new vlan
  * @bat_priv: the bat priv with all the soft interface information
  * @vid: the VLAN identifier
  *
@@ -872,13 +885,14 @@ static int batadv_softif_slave_add(struct net_device *dev,
                                   struct net_device *slave_dev)
 {
        struct batadv_hard_iface *hard_iface;
+       struct net *net = dev_net(dev);
        int ret = -EINVAL;
 
        hard_iface = batadv_hardif_get_by_netdev(slave_dev);
        if (!hard_iface || hard_iface->soft_iface)
                goto out;
 
-       ret = batadv_hardif_enable_interface(hard_iface, dev->name);
+       ret = batadv_hardif_enable_interface(hard_iface, net, dev->name);
 
 out:
        if (hard_iface)
@@ -959,7 +973,7 @@ static void batadv_softif_init_early(struct net_device *dev)
 
        dev->netdev_ops = &batadv_netdev_ops;
        dev->destructor = batadv_softif_free;
-       dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+       dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL;
        dev->priv_flags |= IFF_NO_QUEUE;
 
        /* can't call min_mtu, because the needed variables
@@ -975,7 +989,7 @@ static void batadv_softif_init_early(struct net_device *dev)
        memset(priv, 0, sizeof(*priv));
 }
 
-struct net_device *batadv_softif_create(const char *name)
+struct net_device *batadv_softif_create(struct net *net, const char *name)
 {
        struct net_device *soft_iface;
        int ret;
@@ -985,6 +999,8 @@ struct net_device *batadv_softif_create(const char *name)
        if (!soft_iface)
                return NULL;
 
+       dev_net_set(soft_iface, net);
+
        soft_iface->rtnl_link_ops = &batadv_link_ops;
 
        ret = register_netdevice(soft_iface);
@@ -1017,7 +1033,9 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface)
 static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
                                          struct list_head *head)
 {
+       struct batadv_priv *bat_priv = netdev_priv(soft_iface);
        struct batadv_hard_iface *hard_iface;
+       struct batadv_softif_vlan *vlan;
 
        list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
                if (hard_iface->soft_iface == soft_iface)
@@ -1025,16 +1043,23 @@ static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
                                                        BATADV_IF_CLEANUP_KEEP);
        }
 
+       /* destroy the "untagged" VLAN */
+       vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
+       if (vlan) {
+               batadv_softif_destroy_vlan(bat_priv, vlan);
+               batadv_softif_vlan_put(vlan);
+       }
+
        batadv_sysfs_del_meshif(soft_iface);
        unregister_netdevice_queue(soft_iface, head);
 }
 
-int batadv_softif_is_valid(const struct net_device *net_dev)
+bool batadv_softif_is_valid(const struct net_device *net_dev)
 {
        if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx)
-               return 1;
+               return true;
 
-       return 0;
+       return false;
 }
 
 struct rtnl_link_ops batadv_link_ops __read_mostly = {