1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright (c) 2020, Nikolay Aleksandrov <nikolay@cumulusnetworks.com> 3 #include <linux/kernel.h> 4 #include <linux/netdevice.h> 5 #include <linux/rtnetlink.h> 6 #include <linux/slab.h> 7 8 #include "br_private.h" 9 10 /* check if the options between two vlans are equal */ 11 bool br_vlan_opts_eq(const struct net_bridge_vlan *v1, 12 const struct net_bridge_vlan *v2) 13 { 14 return true; 15 } 16 17 bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v) 18 { 19 return true; 20 } 21 22 size_t br_vlan_opts_nl_size(void) 23 { 24 return 0; 25 } 26 27 static int br_vlan_process_one_opts(const struct net_bridge *br, 28 const struct net_bridge_port *p, 29 struct net_bridge_vlan_group *vg, 30 struct net_bridge_vlan *v, 31 struct nlattr **tb, 32 bool *changed, 33 struct netlink_ext_ack *extack) 34 { 35 *changed = false; 36 return 0; 37 } 38 39 int br_vlan_process_options(const struct net_bridge *br, 40 const struct net_bridge_port *p, 41 struct net_bridge_vlan *range_start, 42 struct net_bridge_vlan *range_end, 43 struct nlattr **tb, 44 struct netlink_ext_ack *extack) 45 { 46 struct net_bridge_vlan *v, *curr_start = NULL, *curr_end = NULL; 47 struct net_bridge_vlan_group *vg; 48 int vid, err = 0; 49 u16 pvid; 50 51 if (p) 52 vg = nbp_vlan_group(p); 53 else 54 vg = br_vlan_group(br); 55 56 if (!range_start || !br_vlan_should_use(range_start)) { 57 NL_SET_ERR_MSG_MOD(extack, "Vlan range start doesn't exist, can't process options"); 58 return -ENOENT; 59 } 60 if (!range_end || !br_vlan_should_use(range_end)) { 61 NL_SET_ERR_MSG_MOD(extack, "Vlan range end doesn't exist, can't process options"); 62 return -ENOENT; 63 } 64 65 pvid = br_get_pvid(vg); 66 for (vid = range_start->vid; vid <= range_end->vid; vid++) { 67 bool changed = false; 68 69 v = br_vlan_find(vg, vid); 70 if (!v || !br_vlan_should_use(v)) { 71 NL_SET_ERR_MSG_MOD(extack, "Vlan in range doesn't exist, can't process options"); 72 err = -ENOENT; 73 break; 74 } 75 76 err = br_vlan_process_one_opts(br, p, vg, v, tb, &changed, 77 extack); 78 if (err) 79 break; 80 81 if (changed) { 82 /* vlan options changed, check for range */ 83 if (!curr_start) { 84 curr_start = v; 85 curr_end = v; 86 continue; 87 } 88 89 if (v->vid == pvid || 90 !br_vlan_can_enter_range(v, curr_end)) { 91 br_vlan_notify(br, p, curr_start->vid, 92 curr_end->vid, RTM_NEWVLAN); 93 curr_start = v; 94 } 95 curr_end = v; 96 } else { 97 /* nothing changed and nothing to notify yet */ 98 if (!curr_start) 99 continue; 100 101 br_vlan_notify(br, p, curr_start->vid, curr_end->vid, 102 RTM_NEWVLAN); 103 curr_start = NULL; 104 curr_end = NULL; 105 } 106 } 107 if (curr_start) 108 br_vlan_notify(br, p, curr_start->vid, curr_end->vid, 109 RTM_NEWVLAN); 110 111 return err; 112 } 113