diff options
Diffstat (limited to 'net/bridge/br_stp_if.c')
-rw-r--r-- | net/bridge/br_stp_if.c | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index a285897a2fb4..3e246b37020e 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c | |||
@@ -87,7 +87,6 @@ void br_stp_disable_bridge(struct net_bridge *br) | |||
87 | void br_stp_enable_port(struct net_bridge_port *p) | 87 | void br_stp_enable_port(struct net_bridge_port *p) |
88 | { | 88 | { |
89 | br_init_port(p); | 89 | br_init_port(p); |
90 | br_ifinfo_notify(RTM_NEWLINK, p); | ||
91 | br_port_state_selection(p->br); | 90 | br_port_state_selection(p->br); |
92 | } | 91 | } |
93 | 92 | ||
@@ -101,8 +100,6 @@ void br_stp_disable_port(struct net_bridge_port *p) | |||
101 | printk(KERN_INFO "%s: port %i(%s) entering %s state\n", | 100 | printk(KERN_INFO "%s: port %i(%s) entering %s state\n", |
102 | br->dev->name, p->port_no, p->dev->name, "disabled"); | 101 | br->dev->name, p->port_no, p->dev->name, "disabled"); |
103 | 102 | ||
104 | br_ifinfo_notify(RTM_DELLINK, p); | ||
105 | |||
106 | wasroot = br_is_root_bridge(br); | 103 | wasroot = br_is_root_bridge(br); |
107 | br_become_designated_port(p); | 104 | br_become_designated_port(p); |
108 | p->state = BR_STATE_DISABLED; | 105 | p->state = BR_STATE_DISABLED; |
@@ -123,6 +120,62 @@ void br_stp_disable_port(struct net_bridge_port *p) | |||
123 | br_become_root_bridge(br); | 120 | br_become_root_bridge(br); |
124 | } | 121 | } |
125 | 122 | ||
123 | static void br_stp_start(struct net_bridge *br) | ||
124 | { | ||
125 | int r; | ||
126 | char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL }; | ||
127 | char *envp[] = { NULL }; | ||
128 | |||
129 | r = call_usermodehelper(BR_STP_PROG, argv, envp, 1); | ||
130 | if (r == 0) { | ||
131 | br->stp_enabled = BR_USER_STP; | ||
132 | printk(KERN_INFO "%s: userspace STP started\n", br->dev->name); | ||
133 | } else { | ||
134 | br->stp_enabled = BR_KERNEL_STP; | ||
135 | printk(KERN_INFO "%s: starting userspace STP failed, " | ||
136 | "staring kernel STP\n", br->dev->name); | ||
137 | |||
138 | /* To start timers on any ports left in blocking */ | ||
139 | spin_lock_bh(&br->lock); | ||
140 | br_port_state_selection(br); | ||
141 | spin_unlock_bh(&br->lock); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void br_stp_stop(struct net_bridge *br) | ||
146 | { | ||
147 | int r; | ||
148 | char *argv[] = { BR_STP_PROG, br->dev->name, "stop", NULL }; | ||
149 | char *envp[] = { NULL }; | ||
150 | |||
151 | if (br->stp_enabled == BR_USER_STP) { | ||
152 | r = call_usermodehelper(BR_STP_PROG, argv, envp, 1); | ||
153 | printk(KERN_INFO "%s: userspace STP stopped, return code %d\n", | ||
154 | br->dev->name, r); | ||
155 | |||
156 | |||
157 | /* To start timers on any ports left in blocking */ | ||
158 | spin_lock_bh(&br->lock); | ||
159 | br_port_state_selection(br); | ||
160 | spin_unlock_bh(&br->lock); | ||
161 | } | ||
162 | |||
163 | br->stp_enabled = BR_NO_STP; | ||
164 | } | ||
165 | |||
166 | void br_stp_set_enabled(struct net_bridge *br, unsigned long val) | ||
167 | { | ||
168 | ASSERT_RTNL(); | ||
169 | |||
170 | if (val) { | ||
171 | if (br->stp_enabled == BR_NO_STP) | ||
172 | br_stp_start(br); | ||
173 | } else { | ||
174 | if (br->stp_enabled != BR_NO_STP) | ||
175 | br_stp_stop(br); | ||
176 | } | ||
177 | } | ||
178 | |||
126 | /* called under bridge lock */ | 179 | /* called under bridge lock */ |
127 | void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) | 180 | void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) |
128 | { | 181 | { |