diff options
-rw-r--r-- | net/tipc/discover.c | 103 |
1 files changed, 59 insertions, 44 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 09ce2318b89e..2345268ca64b 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
@@ -119,17 +119,21 @@ static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr, | |||
119 | 119 | ||
120 | void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | 120 | void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) |
121 | { | 121 | { |
122 | struct tipc_node *n_ptr; | ||
122 | struct link *link; | 123 | struct link *link; |
123 | struct tipc_media_addr media_addr; | 124 | struct tipc_media_addr media_addr, *addr; |
125 | struct sk_buff *rbuf; | ||
124 | struct tipc_msg *msg = buf_msg(buf); | 126 | struct tipc_msg *msg = buf_msg(buf); |
125 | u32 dest = msg_dest_domain(msg); | 127 | u32 dest = msg_dest_domain(msg); |
126 | u32 orig = msg_prevnode(msg); | 128 | u32 orig = msg_prevnode(msg); |
127 | u32 net_id = msg_bc_netid(msg); | 129 | u32 net_id = msg_bc_netid(msg); |
128 | u32 type = msg_type(msg); | 130 | u32 type = msg_type(msg); |
131 | int link_fully_up; | ||
129 | 132 | ||
130 | msg_get_media_addr(msg, &media_addr); | 133 | msg_get_media_addr(msg, &media_addr); |
131 | buf_discard(buf); | 134 | buf_discard(buf); |
132 | 135 | ||
136 | /* Validate discovery message from requesting node */ | ||
133 | if (net_id != tipc_net_id) | 137 | if (net_id != tipc_net_id) |
134 | return; | 138 | return; |
135 | if (!tipc_addr_domain_valid(dest)) | 139 | if (!tipc_addr_domain_valid(dest)) |
@@ -143,56 +147,67 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
143 | } | 147 | } |
144 | if (!tipc_in_scope(dest, tipc_own_addr)) | 148 | if (!tipc_in_scope(dest, tipc_own_addr)) |
145 | return; | 149 | return; |
146 | if (in_own_cluster(orig)) { | 150 | if (!in_own_cluster(orig)) |
147 | /* Always accept link here */ | 151 | return; |
148 | struct sk_buff *rbuf; | ||
149 | struct tipc_media_addr *addr; | ||
150 | struct tipc_node *n_ptr = tipc_node_find(orig); | ||
151 | int link_fully_up; | ||
152 | |||
153 | if (n_ptr == NULL) { | ||
154 | n_ptr = tipc_node_create(orig); | ||
155 | if (!n_ptr) | ||
156 | return; | ||
157 | } | ||
158 | spin_lock_bh(&n_ptr->lock); | ||
159 | |||
160 | /* Don't talk to neighbor during cleanup after last session */ | ||
161 | 152 | ||
162 | if (n_ptr->cleanup_required) { | 153 | /* Locate structure corresponding to requesting node */ |
163 | spin_unlock_bh(&n_ptr->lock); | 154 | n_ptr = tipc_node_find(orig); |
155 | if (!n_ptr) { | ||
156 | n_ptr = tipc_node_create(orig); | ||
157 | if (!n_ptr) | ||
164 | return; | 158 | return; |
165 | } | 159 | } |
160 | tipc_node_lock(n_ptr); | ||
161 | |||
162 | /* Don't talk to neighbor during cleanup after last session */ | ||
163 | if (n_ptr->cleanup_required) { | ||
164 | tipc_node_unlock(n_ptr); | ||
165 | return; | ||
166 | } | ||
166 | 167 | ||
167 | link = n_ptr->links[b_ptr->identity]; | 168 | link = n_ptr->links[b_ptr->identity]; |
169 | |||
170 | /* Create a link endpoint for this bearer, if necessary */ | ||
171 | if (!link) { | ||
172 | link = tipc_link_create(b_ptr, orig, &media_addr); | ||
168 | if (!link) { | 173 | if (!link) { |
169 | link = tipc_link_create(b_ptr, orig, &media_addr); | 174 | tipc_node_unlock(n_ptr); |
170 | if (!link) { | 175 | return; |
171 | spin_unlock_bh(&n_ptr->lock); | ||
172 | return; | ||
173 | } | ||
174 | } | ||
175 | addr = &link->media_addr; | ||
176 | if (memcmp(addr, &media_addr, sizeof(*addr))) { | ||
177 | if (tipc_link_is_up(link) || (!link->started)) { | ||
178 | disc_dupl_alert(b_ptr, orig, &media_addr); | ||
179 | spin_unlock_bh(&n_ptr->lock); | ||
180 | return; | ||
181 | } | ||
182 | warn("Resetting link <%s>, peer interface address changed\n", | ||
183 | link->name); | ||
184 | memcpy(addr, &media_addr, sizeof(*addr)); | ||
185 | tipc_link_reset(link); | ||
186 | } | 176 | } |
187 | link_fully_up = link_working_working(link); | 177 | } |
188 | spin_unlock_bh(&n_ptr->lock); | 178 | |
189 | if ((type == DSC_RESP_MSG) || link_fully_up) | 179 | /* |
180 | * Ensure requesting node's media address is correct | ||
181 | * | ||
182 | * If media address doesn't match and the link is working, reject the | ||
183 | * request (must be from a duplicate node). | ||
184 | * | ||
185 | * If media address doesn't match and the link is not working, accept | ||
186 | * the new media address and reset the link to ensure it starts up | ||
187 | * cleanly. | ||
188 | */ | ||
189 | addr = &link->media_addr; | ||
190 | if (memcmp(addr, &media_addr, sizeof(*addr))) { | ||
191 | if (tipc_link_is_up(link) || (!link->started)) { | ||
192 | disc_dupl_alert(b_ptr, orig, &media_addr); | ||
193 | tipc_node_unlock(n_ptr); | ||
190 | return; | 194 | return; |
191 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); | ||
192 | if (rbuf != NULL) { | ||
193 | b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); | ||
194 | buf_discard(rbuf); | ||
195 | } | 195 | } |
196 | warn("Resetting link <%s>, peer interface address changed\n", | ||
197 | link->name); | ||
198 | memcpy(addr, &media_addr, sizeof(*addr)); | ||
199 | tipc_link_reset(link); | ||
200 | } | ||
201 | |||
202 | /* Accept discovery message & send response, if necessary */ | ||
203 | link_fully_up = link_working_working(link); | ||
204 | tipc_node_unlock(n_ptr); | ||
205 | if ((type == DSC_RESP_MSG) || link_fully_up) | ||
206 | return; | ||
207 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); | ||
208 | if (rbuf != NULL) { | ||
209 | b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); | ||
210 | buf_discard(rbuf); | ||
196 | } | 211 | } |
197 | } | 212 | } |
198 | 213 | ||