aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/discover.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/discover.c')
-rw-r--r--net/tipc/discover.c219
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 */
113void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr) 113void 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/**