diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/discover.c | 219 |
1 files changed, 111 insertions, 108 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index b15cbedfea13..aa722a42ef8b 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * net/tipc/discover.c | 2 | * net/tipc/discover.c |
3 | * | 3 | * |
4 | * Copyright (c) 2003-2006, Ericsson AB | 4 | * Copyright (c) 2003-2006, 2014, Ericsson AB |
5 | * Copyright (c) 2005-2006, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2005-2006, 2010-2011, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
@@ -106,147 +106,150 @@ static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr, | |||
106 | } | 106 | } |
107 | 107 | ||
108 | /** | 108 | /** |
109 | * tipc_disc_rcv - handle incoming link setup message (request or response) | 109 | * tipc_disc_rcv - handle incoming discovery message (request or response) |
110 | * @buf: buffer containing message | 110 | * @buf: buffer containing message |
111 | * @b_ptr: bearer that message arrived on | 111 | * @bearer: bearer that message arrived on |
112 | */ | 112 | */ |
113 | void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr) | 113 | void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer) |
114 | { | 114 | { |
115 | struct tipc_node *n_ptr; | 115 | struct tipc_node *node; |
116 | struct tipc_link *link; | 116 | struct tipc_link *link; |
117 | struct tipc_media_addr media_addr; | 117 | struct tipc_media_addr maddr; |
118 | struct sk_buff *rbuf; | 118 | struct sk_buff *rbuf; |
119 | struct tipc_msg *msg = buf_msg(buf); | 119 | struct tipc_msg *msg = buf_msg(buf); |
120 | u32 dest = msg_dest_domain(msg); | 120 | u32 ddom = msg_dest_domain(msg); |
121 | u32 orig = msg_prevnode(msg); | 121 | u32 onode = msg_prevnode(msg); |
122 | u32 net_id = msg_bc_netid(msg); | 122 | u32 net_id = msg_bc_netid(msg); |
123 | u32 type = msg_type(msg); | 123 | u32 mtyp = msg_type(msg); |
124 | u32 signature = msg_node_sig(msg); | 124 | u32 signature = msg_node_sig(msg); |
125 | int addr_mismatch; | 125 | bool addr_match = false; |
126 | int link_fully_up; | 126 | bool sign_match = false; |
127 | 127 | bool link_up = false; | |
128 | media_addr.broadcast = 1; | 128 | bool accept_addr = false; |
129 | b_ptr->media->msg2addr(b_ptr, &media_addr, msg_media_addr(msg)); | 129 | bool accept_sign = false; |
130 | bool respond = false; | ||
131 | |||
132 | bearer->media->msg2addr(bearer, &maddr, msg_media_addr(msg)); | ||
130 | kfree_skb(buf); | 133 | kfree_skb(buf); |
131 | 134 | ||
132 | /* Ensure message from node is valid and communication is permitted */ | 135 | /* Ensure message from node is valid and communication is permitted */ |
133 | if (net_id != tipc_net_id) | 136 | if (net_id != tipc_net_id) |
134 | return; | 137 | return; |
135 | if (media_addr.broadcast) | 138 | if (maddr.broadcast) |
136 | return; | 139 | return; |
137 | if (!tipc_addr_domain_valid(dest)) | 140 | if (!tipc_addr_domain_valid(ddom)) |
138 | return; | 141 | return; |
139 | if (!tipc_addr_node_valid(orig)) | 142 | if (!tipc_addr_node_valid(onode)) |
140 | return; | 143 | return; |
141 | if (orig == tipc_own_addr) { | 144 | |
142 | if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr))) | 145 | if (in_own_node(onode)) { |
143 | disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); | 146 | if (memcmp(&maddr, &bearer->addr, sizeof(maddr))) |
147 | disc_dupl_alert(bearer, tipc_own_addr, &maddr); | ||
144 | return; | 148 | return; |
145 | } | 149 | } |
146 | if (!tipc_in_scope(dest, tipc_own_addr)) | 150 | if (!tipc_in_scope(ddom, tipc_own_addr)) |
147 | return; | 151 | return; |
148 | if (!tipc_in_scope(b_ptr->domain, orig)) | 152 | if (!tipc_in_scope(bearer->domain, onode)) |
149 | return; | 153 | return; |
150 | 154 | ||
151 | /* Locate structure corresponding to requesting node */ | 155 | /* Locate, or if necessary, create, node: */ |
152 | n_ptr = tipc_node_find(orig); | 156 | node = tipc_node_find(onode); |
153 | if (!n_ptr) { | 157 | if (!node) |
154 | n_ptr = tipc_node_create(orig); | 158 | node = tipc_node_create(onode); |
155 | if (!n_ptr) | 159 | if (!node) |
156 | return; | 160 | return; |
157 | } | ||
158 | tipc_node_lock(n_ptr); | ||
159 | 161 | ||
160 | /* Prepare to validate requesting node's signature and media address */ | 162 | tipc_node_lock(node); |
161 | link = n_ptr->links[b_ptr->identity]; | 163 | link = node->links[bearer->identity]; |
162 | addr_mismatch = (link != NULL) && | ||
163 | memcmp(&link->media_addr, &media_addr, sizeof(media_addr)); | ||
164 | 164 | ||
165 | /* | 165 | /* Prepare to validate requesting node's signature and media address */ |
166 | * Ensure discovery message's signature is correct | 166 | sign_match = (signature == node->signature); |
167 | * | 167 | addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr)); |
168 | * If signature is incorrect and there is no working link to the node, | 168 | link_up = link && tipc_link_is_up(link); |
169 | * accept the new signature but invalidate all existing links to the | 169 | |
170 | * node so they won't re-activate without a new discovery message. | 170 | |
171 | * | 171 | /* These three flags give us eight permutations: */ |
172 | * If signature is incorrect and the requested link to the node is | 172 | |
173 | * working, accept the new signature. (This is an instance of delayed | 173 | if (sign_match && addr_match && link_up) { |
174 | * rediscovery, where a link endpoint was able to re-establish contact | 174 | /* All is fine. Do nothing. */ |
175 | * with its peer endpoint on a node that rebooted before receiving a | 175 | } else if (sign_match && addr_match && !link_up) { |
176 | * discovery message from that node.) | 176 | /* Respond. The link will come up in due time */ |
177 | * | 177 | respond = true; |
178 | * If signature is incorrect and there is a working link to the node | 178 | } else if (sign_match && !addr_match && link_up) { |
179 | * that is not the requested link, reject the request (must be from | 179 | /* Peer has changed i/f address without rebooting. |
180 | * a duplicate node). | 180 | * If so, the link will reset soon, and the next |
181 | */ | 181 | * discovery will be accepted. So we can ignore it. |
182 | if (signature != n_ptr->signature) { | 182 | * It may also be an cloned or malicious peer having |
183 | if (n_ptr->working_links == 0) { | 183 | * chosen the same node address and signature as an |
184 | struct tipc_link *curr_link; | 184 | * existing one. |
185 | int i; | 185 | * Ignore requests until the link goes down, if ever. |
186 | 186 | */ | |
187 | for (i = 0; i < MAX_BEARERS; i++) { | 187 | disc_dupl_alert(bearer, onode, &maddr); |
188 | curr_link = n_ptr->links[i]; | 188 | } else if (sign_match && !addr_match && !link_up) { |
189 | if (curr_link) { | 189 | /* Peer link has changed i/f address without rebooting. |
190 | memset(&curr_link->media_addr, 0, | 190 | * It may also be a cloned or malicious peer; we can't |
191 | sizeof(media_addr)); | 191 | * distinguish between the two. |
192 | tipc_link_reset(curr_link); | 192 | * The signature is correct, so we must accept. |
193 | } | 193 | */ |
194 | } | 194 | accept_addr = true; |
195 | addr_mismatch = (link != NULL); | 195 | respond = true; |
196 | } else if (tipc_link_is_up(link) && !addr_mismatch) { | 196 | } else if (!sign_match && addr_match && link_up) { |
197 | /* delayed rediscovery */ | 197 | /* Peer node rebooted. Two possibilities: |
198 | } else { | 198 | * - Delayed re-discovery; this link endpoint has already |
199 | disc_dupl_alert(b_ptr, orig, &media_addr); | 199 | * reset and re-established contact with the peer, before |
200 | tipc_node_unlock(n_ptr); | 200 | * receiving a discovery message from that node. |
201 | return; | 201 | * (The peer happened to receive one from this node first). |
202 | } | 202 | * - The peer came back so fast that our side has not |
203 | n_ptr->signature = signature; | 203 | * discovered it yet. Probing from this side will soon |
204 | * reset the link, since there can be no working link | ||
205 | * endpoint at the peer end, and the link will re-establish. | ||
206 | * Accept the signature, since it comes from a known peer. | ||
207 | */ | ||
208 | accept_sign = true; | ||
209 | } else if (!sign_match && addr_match && !link_up) { | ||
210 | /* The peer node has rebooted. | ||
211 | * Accept signature, since it is a known peer. | ||
212 | */ | ||
213 | accept_sign = true; | ||
214 | respond = true; | ||
215 | } else if (!sign_match && !addr_match && link_up) { | ||
216 | /* Peer rebooted with new address, or a new/duplicate peer. | ||
217 | * Ignore until the link goes down, if ever. | ||
218 | */ | ||
219 | disc_dupl_alert(bearer, onode, &maddr); | ||
220 | } else if (!sign_match && !addr_match && !link_up) { | ||
221 | /* Peer rebooted with new address, or it is a new peer. | ||
222 | * Accept signature and address. | ||
223 | */ | ||
224 | accept_sign = true; | ||
225 | accept_addr = true; | ||
226 | respond = true; | ||
204 | } | 227 | } |
205 | 228 | ||
206 | /* | 229 | if (accept_sign) |
207 | * Ensure requesting node's media address is correct | 230 | node->signature = signature; |
208 | * | ||
209 | * If media address doesn't match and the link is working, reject the | ||
210 | * request (must be from a duplicate node). | ||
211 | * | ||
212 | * If media address doesn't match and the link is not working, accept | ||
213 | * the new media address and reset the link to ensure it starts up | ||
214 | * cleanly. | ||
215 | */ | ||
216 | if (addr_mismatch) { | ||
217 | if (tipc_link_is_up(link)) { | ||
218 | disc_dupl_alert(b_ptr, orig, &media_addr); | ||
219 | tipc_node_unlock(n_ptr); | ||
220 | return; | ||
221 | } else { | ||
222 | memcpy(&link->media_addr, &media_addr, | ||
223 | sizeof(media_addr)); | ||
224 | tipc_link_reset(link); | ||
225 | } | ||
226 | } | ||
227 | 231 | ||
228 | /* Create a link endpoint for this bearer, if necessary */ | 232 | if (accept_addr) { |
229 | if (!link) { | 233 | if (!link) |
230 | link = tipc_link_create(n_ptr, b_ptr, &media_addr); | 234 | link = tipc_link_create(node, bearer, &maddr); |
231 | if (!link) { | 235 | if (link) { |
232 | tipc_node_unlock(n_ptr); | 236 | memcpy(&link->media_addr, &maddr, sizeof(maddr)); |
233 | return; | 237 | tipc_link_reset(link); |
238 | } else { | ||
239 | respond = false; | ||
234 | } | 240 | } |
235 | } | 241 | } |
236 | 242 | ||
237 | /* Accept discovery message & send response, if necessary */ | 243 | /* Send response, if necessary */ |
238 | link_fully_up = link_working_working(link); | 244 | if (respond && (mtyp == DSC_REQ_MSG)) { |
239 | |||
240 | if ((type == DSC_REQ_MSG) && !link_fully_up) { | ||
241 | rbuf = tipc_buf_acquire(INT_H_SIZE); | 245 | rbuf = tipc_buf_acquire(INT_H_SIZE); |
242 | if (rbuf) { | 246 | if (rbuf) { |
243 | tipc_disc_init_msg(rbuf, DSC_RESP_MSG, b_ptr); | 247 | tipc_disc_init_msg(rbuf, DSC_RESP_MSG, bearer); |
244 | tipc_bearer_send(b_ptr->identity, rbuf, &media_addr); | 248 | tipc_bearer_send(bearer->identity, rbuf, &maddr); |
245 | kfree_skb(rbuf); | 249 | kfree_skb(rbuf); |
246 | } | 250 | } |
247 | } | 251 | } |
248 | 252 | tipc_node_unlock(node); | |
249 | tipc_node_unlock(n_ptr); | ||
250 | } | 253 | } |
251 | 254 | ||
252 | /** | 255 | /** |