diff options
-rw-r--r-- | net/tipc/discover.c | 72 |
1 files changed, 58 insertions, 14 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 7ae1b4c33aeb..f5f9bf7a0436 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
@@ -122,7 +122,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
122 | { | 122 | { |
123 | struct tipc_node *n_ptr; | 123 | struct tipc_node *n_ptr; |
124 | struct tipc_link *link; | 124 | struct tipc_link *link; |
125 | struct tipc_media_addr media_addr, *addr; | 125 | struct tipc_media_addr media_addr; |
126 | struct sk_buff *rbuf; | 126 | struct sk_buff *rbuf; |
127 | struct tipc_msg *msg = buf_msg(buf); | 127 | struct tipc_msg *msg = buf_msg(buf); |
128 | u32 dest = msg_dest_domain(msg); | 128 | u32 dest = msg_dest_domain(msg); |
@@ -130,13 +130,14 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
130 | u32 net_id = msg_bc_netid(msg); | 130 | u32 net_id = msg_bc_netid(msg); |
131 | u32 type = msg_type(msg); | 131 | u32 type = msg_type(msg); |
132 | u32 signature = msg_node_sig(msg); | 132 | u32 signature = msg_node_sig(msg); |
133 | int addr_mismatch; | ||
133 | int link_fully_up; | 134 | int link_fully_up; |
134 | 135 | ||
135 | media_addr.broadcast = 1; | 136 | media_addr.broadcast = 1; |
136 | b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); | 137 | b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); |
137 | buf_discard(buf); | 138 | buf_discard(buf); |
138 | 139 | ||
139 | /* Validate discovery message from requesting node */ | 140 | /* Ensure message from node is valid and communication is permitted */ |
140 | if (net_id != tipc_net_id) | 141 | if (net_id != tipc_net_id) |
141 | return; | 142 | return; |
142 | if (media_addr.broadcast) | 143 | if (media_addr.broadcast) |
@@ -164,15 +165,50 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
164 | } | 165 | } |
165 | tipc_node_lock(n_ptr); | 166 | tipc_node_lock(n_ptr); |
166 | 167 | ||
168 | /* Prepare to validate requesting node's signature and media address */ | ||
167 | link = n_ptr->links[b_ptr->identity]; | 169 | link = n_ptr->links[b_ptr->identity]; |
170 | addr_mismatch = (link != NULL) && | ||
171 | memcmp(&link->media_addr, &media_addr, sizeof(media_addr)); | ||
168 | 172 | ||
169 | /* Create a link endpoint for this bearer, if necessary */ | 173 | /* |
170 | if (!link) { | 174 | * Ensure discovery message's signature is correct |
171 | link = tipc_link_create(n_ptr, b_ptr, &media_addr); | 175 | * |
172 | if (!link) { | 176 | * If signature is incorrect and there is no working link to the node, |
177 | * accept the new signature but invalidate all existing links to the | ||
178 | * node so they won't re-activate without a new discovery message. | ||
179 | * | ||
180 | * If signature is incorrect and the requested link to the node is | ||
181 | * working, accept the new signature. (This is an instance of delayed | ||
182 | * rediscovery, where a link endpoint was able to re-establish contact | ||
183 | * with its peer endpoint on a node that rebooted before receiving a | ||
184 | * discovery message from that node.) | ||
185 | * | ||
186 | * If signature is incorrect and there is a working link to the node | ||
187 | * that is not the requested link, reject the request (must be from | ||
188 | * a duplicate node). | ||
189 | */ | ||
190 | if (signature != n_ptr->signature) { | ||
191 | if (n_ptr->working_links == 0) { | ||
192 | struct tipc_link *curr_link; | ||
193 | int i; | ||
194 | |||
195 | for (i = 0; i < MAX_BEARERS; i++) { | ||
196 | curr_link = n_ptr->links[i]; | ||
197 | if (curr_link) { | ||
198 | memset(&curr_link->media_addr, 0, | ||
199 | sizeof(media_addr)); | ||
200 | tipc_link_reset(curr_link); | ||
201 | } | ||
202 | } | ||
203 | addr_mismatch = (link != NULL); | ||
204 | } else if (tipc_link_is_up(link) && !addr_mismatch) { | ||
205 | /* delayed rediscovery */ | ||
206 | } else { | ||
207 | disc_dupl_alert(b_ptr, orig, &media_addr); | ||
173 | tipc_node_unlock(n_ptr); | 208 | tipc_node_unlock(n_ptr); |
174 | return; | 209 | return; |
175 | } | 210 | } |
211 | n_ptr->signature = signature; | ||
176 | } | 212 | } |
177 | 213 | ||
178 | /* | 214 | /* |
@@ -185,21 +221,29 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
185 | * the new media address and reset the link to ensure it starts up | 221 | * the new media address and reset the link to ensure it starts up |
186 | * cleanly. | 222 | * cleanly. |
187 | */ | 223 | */ |
188 | addr = &link->media_addr; | 224 | |
189 | if (memcmp(addr, &media_addr, sizeof(*addr))) { | 225 | if (addr_mismatch) { |
190 | if (tipc_link_is_up(link) || (!link->started)) { | 226 | if (tipc_link_is_up(link)) { |
191 | disc_dupl_alert(b_ptr, orig, &media_addr); | 227 | disc_dupl_alert(b_ptr, orig, &media_addr); |
192 | tipc_node_unlock(n_ptr); | 228 | tipc_node_unlock(n_ptr); |
193 | return; | 229 | return; |
230 | } else { | ||
231 | memcpy(&link->media_addr, &media_addr, | ||
232 | sizeof(media_addr)); | ||
233 | tipc_link_reset(link); | ||
234 | } | ||
235 | } | ||
236 | |||
237 | /* Create a link endpoint for this bearer, if necessary */ | ||
238 | if (!link) { | ||
239 | link = tipc_link_create(n_ptr, b_ptr, &media_addr); | ||
240 | if (!link) { | ||
241 | tipc_node_unlock(n_ptr); | ||
242 | return; | ||
194 | } | 243 | } |
195 | warn("Resetting link <%s>, peer interface address changed\n", | ||
196 | link->name); | ||
197 | memcpy(addr, &media_addr, sizeof(*addr)); | ||
198 | tipc_link_reset(link); | ||
199 | } | 244 | } |
200 | 245 | ||
201 | /* Accept discovery message & send response, if necessary */ | 246 | /* Accept discovery message & send response, if necessary */ |
202 | n_ptr->signature = signature; | ||
203 | link_fully_up = link_working_working(link); | 247 | link_fully_up = link_working_working(link); |
204 | 248 | ||
205 | if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { | 249 | if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { |