return 0;
 }
 
+/* send a notification if v_curr can't enter the range and start a new one */
+static void __vlan_tunnel_handle_range(const struct net_bridge_port *p,
+                                      struct net_bridge_vlan **v_start,
+                                      struct net_bridge_vlan **v_end,
+                                      int v_curr, bool curr_change)
+{
+       struct net_bridge_vlan_group *vg;
+       struct net_bridge_vlan *v;
+
+       vg = nbp_vlan_group(p);
+       if (!vg)
+               return;
+
+       v = br_vlan_find(vg, v_curr);
+
+       if (!*v_start)
+               goto out_init;
+
+       if (v && curr_change && br_vlan_can_enter_range(v, *v_end)) {
+               *v_end = v;
+               return;
+       }
+
+       br_vlan_notify(p->br, p, (*v_start)->vid, (*v_end)->vid, RTM_NEWVLAN);
+out_init:
+       /* we start a range only if there are any changes to notify about */
+       *v_start = curr_change ? v : NULL;
+       *v_end = *v_start;
+}
+
 int br_process_vlan_tunnel_info(const struct net_bridge *br,
                                const struct net_bridge_port *p, int cmd,
                                struct vtunnel_info *tinfo_curr,
                        return -EINVAL;
                memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
        } else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
+               struct net_bridge_vlan *v_start = NULL, *v_end = NULL;
                int t, v;
 
                if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
                        return -EINVAL;
                t = tinfo_last->tunid;
                for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
-                       err = br_vlan_tunnel_info(p, cmd, v, t, changed);
+                       bool curr_change = false;
+
+                       err = br_vlan_tunnel_info(p, cmd, v, t, &curr_change);
                        if (err)
-                               return err;
+                               break;
                        t++;
+
+                       if (curr_change)
+                               *changed = curr_change;
+                        __vlan_tunnel_handle_range(p, &v_start, &v_end, v,
+                                                   curr_change);
                }
+               if (v_start && v_end)
+                       br_vlan_notify(br, p, v_start->vid, v_end->vid,
+                                      RTM_NEWVLAN);
+               if (err)
+                       return err;
+
                memset(tinfo_last, 0, sizeof(struct vtunnel_info));
                memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
        } else {
                                          tinfo_curr->tunid, changed);
                if (err)
                        return err;
+               br_vlan_notify(br, p, tinfo_curr->vid, 0, RTM_NEWVLAN);
                memset(tinfo_last, 0, sizeof(struct vtunnel_info));
                memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
        }