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.c281
1 files changed, 153 insertions, 128 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 542fe3413dc4..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 *
@@ -46,8 +46,9 @@
46 46
47/** 47/**
48 * struct tipc_link_req - information about an ongoing link setup request 48 * struct tipc_link_req - information about an ongoing link setup request
49 * @bearer: bearer issuing requests 49 * @bearer_id: identity of bearer issuing requests
50 * @dest: destination address for request messages 50 * @dest: destination address for request messages
51 * @domain: network domain to which links can be established
51 * @num_nodes: number of nodes currently discovered (i.e. with an active link) 52 * @num_nodes: number of nodes currently discovered (i.e. with an active link)
52 * @lock: spinlock for controlling access to requests 53 * @lock: spinlock for controlling access to requests
53 * @buf: request message to be (repeatedly) sent 54 * @buf: request message to be (repeatedly) sent
@@ -55,8 +56,9 @@
55 * @timer_intv: current interval between requests (in ms) 56 * @timer_intv: current interval between requests (in ms)
56 */ 57 */
57struct tipc_link_req { 58struct tipc_link_req {
58 struct tipc_bearer *bearer; 59 u32 bearer_id;
59 struct tipc_media_addr dest; 60 struct tipc_media_addr dest;
61 u32 domain;
60 int num_nodes; 62 int num_nodes;
61 spinlock_t lock; 63 spinlock_t lock;
62 struct sk_buff *buf; 64 struct sk_buff *buf;
@@ -69,22 +71,19 @@ struct tipc_link_req {
69 * @type: message type (request or response) 71 * @type: message type (request or response)
70 * @b_ptr: ptr to bearer issuing message 72 * @b_ptr: ptr to bearer issuing message
71 */ 73 */
72static struct sk_buff *tipc_disc_init_msg(u32 type, struct tipc_bearer *b_ptr) 74static void tipc_disc_init_msg(struct sk_buff *buf, u32 type,
75 struct tipc_bearer *b_ptr)
73{ 76{
74 struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE);
75 struct tipc_msg *msg; 77 struct tipc_msg *msg;
76 u32 dest_domain = b_ptr->domain; 78 u32 dest_domain = b_ptr->domain;
77 79
78 if (buf) { 80 msg = buf_msg(buf);
79 msg = buf_msg(buf); 81 tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
80 tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain); 82 msg_set_non_seq(msg, 1);
81 msg_set_non_seq(msg, 1); 83 msg_set_node_sig(msg, tipc_random);
82 msg_set_node_sig(msg, tipc_random); 84 msg_set_dest_domain(msg, dest_domain);
83 msg_set_dest_domain(msg, dest_domain); 85 msg_set_bc_netid(msg, tipc_net_id);
84 msg_set_bc_netid(msg, tipc_net_id); 86 b_ptr->media->addr2msg(msg_media_addr(msg), &b_ptr->addr);
85 b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
86 }
87 return buf;
88} 87}
89 88
90/** 89/**
@@ -107,146 +106,150 @@ static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr,
107} 106}
108 107
109/** 108/**
110 * tipc_disc_rcv - handle incoming link setup message (request or response) 109 * tipc_disc_rcv - handle incoming discovery message (request or response)
111 * @buf: buffer containing message 110 * @buf: buffer containing message
112 * @b_ptr: bearer that message arrived on 111 * @bearer: bearer that message arrived on
113 */ 112 */
114void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr) 113void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer)
115{ 114{
116 struct tipc_node *n_ptr; 115 struct tipc_node *node;
117 struct tipc_link *link; 116 struct tipc_link *link;
118 struct tipc_media_addr media_addr; 117 struct tipc_media_addr maddr;
119 struct sk_buff *rbuf; 118 struct sk_buff *rbuf;
120 struct tipc_msg *msg = buf_msg(buf); 119 struct tipc_msg *msg = buf_msg(buf);
121 u32 dest = msg_dest_domain(msg); 120 u32 ddom = msg_dest_domain(msg);
122 u32 orig = msg_prevnode(msg); 121 u32 onode = msg_prevnode(msg);
123 u32 net_id = msg_bc_netid(msg); 122 u32 net_id = msg_bc_netid(msg);
124 u32 type = msg_type(msg); 123 u32 mtyp = msg_type(msg);
125 u32 signature = msg_node_sig(msg); 124 u32 signature = msg_node_sig(msg);
126 int addr_mismatch; 125 bool addr_match = false;
127 int link_fully_up; 126 bool sign_match = false;
128 127 bool link_up = false;
129 media_addr.broadcast = 1; 128 bool accept_addr = false;
130 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));
131 kfree_skb(buf); 133 kfree_skb(buf);
132 134
133 /* Ensure message from node is valid and communication is permitted */ 135 /* Ensure message from node is valid and communication is permitted */
134 if (net_id != tipc_net_id) 136 if (net_id != tipc_net_id)
135 return; 137 return;
136 if (media_addr.broadcast) 138 if (maddr.broadcast)
137 return; 139 return;
138 if (!tipc_addr_domain_valid(dest)) 140 if (!tipc_addr_domain_valid(ddom))
139 return; 141 return;
140 if (!tipc_addr_node_valid(orig)) 142 if (!tipc_addr_node_valid(onode))
141 return; 143 return;
142 if (orig == tipc_own_addr) { 144
143 if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr))) 145 if (in_own_node(onode)) {
144 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);
145 return; 148 return;
146 } 149 }
147 if (!tipc_in_scope(dest, tipc_own_addr)) 150 if (!tipc_in_scope(ddom, tipc_own_addr))
148 return; 151 return;
149 if (!tipc_in_scope(b_ptr->domain, orig)) 152 if (!tipc_in_scope(bearer->domain, onode))
150 return; 153 return;
151 154
152 /* Locate structure corresponding to requesting node */ 155 /* Locate, or if necessary, create, node: */
153 n_ptr = tipc_node_find(orig); 156 node = tipc_node_find(onode);
154 if (!n_ptr) { 157 if (!node)
155 n_ptr = tipc_node_create(orig); 158 node = tipc_node_create(onode);
156 if (!n_ptr) 159 if (!node)
157 return; 160 return;
158 }
159 tipc_node_lock(n_ptr);
160 161
161 /* Prepare to validate requesting node's signature and media address */ 162 tipc_node_lock(node);
162 link = n_ptr->links[b_ptr->identity]; 163 link = node->links[bearer->identity];
163 addr_mismatch = (link != NULL) &&
164 memcmp(&link->media_addr, &media_addr, sizeof(media_addr));
165 164
166 /* 165 /* Prepare to validate requesting node's signature and media address */
167 * Ensure discovery message's signature is correct 166 sign_match = (signature == node->signature);
168 * 167 addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr));
169 * If signature is incorrect and there is no working link to the node, 168 link_up = link && tipc_link_is_up(link);
170 * accept the new signature but invalidate all existing links to the 169
171 * node so they won't re-activate without a new discovery message. 170
172 * 171 /* These three flags give us eight permutations: */
173 * If signature is incorrect and the requested link to the node is 172
174 * working, accept the new signature. (This is an instance of delayed 173 if (sign_match && addr_match && link_up) {
175 * rediscovery, where a link endpoint was able to re-establish contact 174 /* All is fine. Do nothing. */
176 * with its peer endpoint on a node that rebooted before receiving a 175 } else if (sign_match && addr_match && !link_up) {
177 * discovery message from that node.) 176 /* Respond. The link will come up in due time */
178 * 177 respond = true;
179 * If signature is incorrect and there is a working link to the node 178 } else if (sign_match && !addr_match && link_up) {
180 * that is not the requested link, reject the request (must be from 179 /* Peer has changed i/f address without rebooting.
181 * a duplicate node). 180 * If so, the link will reset soon, and the next
182 */ 181 * discovery will be accepted. So we can ignore it.
183 if (signature != n_ptr->signature) { 182 * It may also be an cloned or malicious peer having
184 if (n_ptr->working_links == 0) { 183 * chosen the same node address and signature as an
185 struct tipc_link *curr_link; 184 * existing one.
186 int i; 185 * Ignore requests until the link goes down, if ever.
187 186 */
188 for (i = 0; i < MAX_BEARERS; i++) { 187 disc_dupl_alert(bearer, onode, &maddr);
189 curr_link = n_ptr->links[i]; 188 } else if (sign_match && !addr_match && !link_up) {
190 if (curr_link) { 189 /* Peer link has changed i/f address without rebooting.
191 memset(&curr_link->media_addr, 0, 190 * It may also be a cloned or malicious peer; we can't
192 sizeof(media_addr)); 191 * distinguish between the two.
193 tipc_link_reset(curr_link); 192 * The signature is correct, so we must accept.
194 } 193 */
195 } 194 accept_addr = true;
196 addr_mismatch = (link != NULL); 195 respond = true;
197 } else if (tipc_link_is_up(link) && !addr_mismatch) { 196 } else if (!sign_match && addr_match && link_up) {
198 /* delayed rediscovery */ 197 /* Peer node rebooted. Two possibilities:
199 } else { 198 * - Delayed re-discovery; this link endpoint has already
200 disc_dupl_alert(b_ptr, orig, &media_addr); 199 * reset and re-established contact with the peer, before
201 tipc_node_unlock(n_ptr); 200 * receiving a discovery message from that node.
202 return; 201 * (The peer happened to receive one from this node first).
203 } 202 * - The peer came back so fast that our side has not
204 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;
205 } 227 }
206 228
207 /* 229 if (accept_sign)
208 * Ensure requesting node's media address is correct 230 node->signature = signature;
209 *
210 * If media address doesn't match and the link is working, reject the
211 * request (must be from a duplicate node).
212 *
213 * If media address doesn't match and the link is not working, accept
214 * the new media address and reset the link to ensure it starts up
215 * cleanly.
216 */
217 if (addr_mismatch) {
218 if (tipc_link_is_up(link)) {
219 disc_dupl_alert(b_ptr, orig, &media_addr);
220 tipc_node_unlock(n_ptr);
221 return;
222 } else {
223 memcpy(&link->media_addr, &media_addr,
224 sizeof(media_addr));
225 tipc_link_reset(link);
226 }
227 }
228 231
229 /* Create a link endpoint for this bearer, if necessary */ 232 if (accept_addr) {
230 if (!link) { 233 if (!link)
231 link = tipc_link_create(n_ptr, b_ptr, &media_addr); 234 link = tipc_link_create(node, bearer, &maddr);
232 if (!link) { 235 if (link) {
233 tipc_node_unlock(n_ptr); 236 memcpy(&link->media_addr, &maddr, sizeof(maddr));
234 return; 237 tipc_link_reset(link);
238 } else {
239 respond = false;
235 } 240 }
236 } 241 }
237 242
238 /* Accept discovery message & send response, if necessary */ 243 /* Send response, if necessary */
239 link_fully_up = link_working_working(link); 244 if (respond && (mtyp == DSC_REQ_MSG)) {
240 245 rbuf = tipc_buf_acquire(INT_H_SIZE);
241 if ((type == DSC_REQ_MSG) && !link_fully_up) {
242 rbuf = tipc_disc_init_msg(DSC_RESP_MSG, b_ptr);
243 if (rbuf) { 246 if (rbuf) {
244 tipc_bearer_send(b_ptr, rbuf, &media_addr); 247 tipc_disc_init_msg(rbuf, DSC_RESP_MSG, bearer);
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/**
@@ -303,7 +306,7 @@ static void disc_timeout(struct tipc_link_req *req)
303 spin_lock_bh(&req->lock); 306 spin_lock_bh(&req->lock);
304 307
305 /* Stop searching if only desired node has been found */ 308 /* Stop searching if only desired node has been found */
306 if (tipc_node(req->bearer->domain) && req->num_nodes) { 309 if (tipc_node(req->domain) && req->num_nodes) {
307 req->timer_intv = TIPC_LINK_REQ_INACTIVE; 310 req->timer_intv = TIPC_LINK_REQ_INACTIVE;
308 goto exit; 311 goto exit;
309 } 312 }
@@ -315,7 +318,7 @@ static void disc_timeout(struct tipc_link_req *req)
315 * hold at fast polling rate if don't have any associated nodes, 318 * hold at fast polling rate if don't have any associated nodes,
316 * otherwise hold at slow polling rate 319 * otherwise hold at slow polling rate
317 */ 320 */
318 tipc_bearer_send(req->bearer, req->buf, &req->dest); 321 tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
319 322
320 323
321 req->timer_intv *= 2; 324 req->timer_intv *= 2;
@@ -347,21 +350,23 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
347 if (!req) 350 if (!req)
348 return -ENOMEM; 351 return -ENOMEM;
349 352
350 req->buf = tipc_disc_init_msg(DSC_REQ_MSG, b_ptr); 353 req->buf = tipc_buf_acquire(INT_H_SIZE);
351 if (!req->buf) { 354 if (!req->buf) {
352 kfree(req); 355 kfree(req);
353 return -ENOMSG; 356 return -ENOMEM;
354 } 357 }
355 358
359 tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
356 memcpy(&req->dest, dest, sizeof(*dest)); 360 memcpy(&req->dest, dest, sizeof(*dest));
357 req->bearer = b_ptr; 361 req->bearer_id = b_ptr->identity;
362 req->domain = b_ptr->domain;
358 req->num_nodes = 0; 363 req->num_nodes = 0;
359 req->timer_intv = TIPC_LINK_REQ_INIT; 364 req->timer_intv = TIPC_LINK_REQ_INIT;
360 spin_lock_init(&req->lock); 365 spin_lock_init(&req->lock);
361 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); 366 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
362 k_start_timer(&req->timer, req->timer_intv); 367 k_start_timer(&req->timer, req->timer_intv);
363 b_ptr->link_req = req; 368 b_ptr->link_req = req;
364 tipc_bearer_send(req->bearer, req->buf, &req->dest); 369 tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
365 return 0; 370 return 0;
366} 371}
367 372
@@ -376,3 +381,23 @@ void tipc_disc_delete(struct tipc_link_req *req)
376 kfree_skb(req->buf); 381 kfree_skb(req->buf);
377 kfree(req); 382 kfree(req);
378} 383}
384
385/**
386 * tipc_disc_reset - reset object to send periodic link setup requests
387 * @b_ptr: ptr to bearer issuing requests
388 * @dest_domain: network domain to which links can be established
389 */
390void tipc_disc_reset(struct tipc_bearer *b_ptr)
391{
392 struct tipc_link_req *req = b_ptr->link_req;
393
394 spin_lock_bh(&req->lock);
395 tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
396 req->bearer_id = b_ptr->identity;
397 req->domain = b_ptr->domain;
398 req->num_nodes = 0;
399 req->timer_intv = TIPC_LINK_REQ_INIT;
400 k_start_timer(&req->timer, req->timer_intv);
401 tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
402 spin_unlock_bh(&req->lock);
403}