1 /* 2 * net/tipc/discover.c 3 * 4 * Copyright (c) 2003-2006, Ericsson AB 5 * Copyright (c) 2005-2006, Wind River Systems 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the names of the copyright holders nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * Alternatively, this software may be distributed under the terms of the 21 * GNU General Public License ("GPL") version 2 as published by the Free 22 * Software Foundation. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include "core.h" 38 #include "dbg.h" 39 #include "link.h" 40 #include "zone.h" 41 #include "discover.h" 42 #include "port.h" 43 #include "name_table.h" 44 45 #define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */ 46 #define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */ 47 #define TIPC_LINK_REQ_SLOW 600000 /* normal delay if bearer has links */ 48 49 /* 50 * TODO: Most of the inter-cluster setup stuff should be 51 * rewritten, and be made conformant with specification. 52 */ 53 54 55 /** 56 * struct link_req - information about an ongoing link setup request 57 * @bearer: bearer issuing requests 58 * @dest: destination address for request messages 59 * @buf: request message to be (repeatedly) sent 60 * @timer: timer governing period between requests 61 * @timer_intv: current interval between requests (in ms) 62 */ 63 struct link_req { 64 struct bearer *bearer; 65 struct tipc_media_addr dest; 66 struct sk_buff *buf; 67 struct timer_list timer; 68 unsigned int timer_intv; 69 }; 70 71 /** 72 * tipc_disc_init_msg - initialize a link setup message 73 * @type: message type (request or response) 74 * @req_links: number of links associated with message 75 * @dest_domain: network domain of node(s) which should respond to message 76 * @b_ptr: ptr to bearer issuing message 77 */ 78 79 static struct sk_buff *tipc_disc_init_msg(u32 type, 80 u32 req_links, 81 u32 dest_domain, 82 struct bearer *b_ptr) 83 { 84 struct sk_buff *buf = tipc_buf_acquire(DSC_H_SIZE); 85 struct tipc_msg *msg; 86 87 if (buf) { 88 msg = buf_msg(buf); 89 tipc_msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain); 90 msg_set_non_seq(msg, 1); 91 msg_set_req_links(msg, req_links); 92 msg_set_dest_domain(msg, dest_domain); 93 msg_set_bc_netid(msg, tipc_net_id); 94 msg_set_media_addr(msg, &b_ptr->publ.addr); 95 } 96 return buf; 97 } 98 99 /** 100 * disc_dupl_alert - issue node address duplication alert 101 * @b_ptr: pointer to bearer detecting duplication 102 * @node_addr: duplicated node address 103 * @media_addr: media address advertised by duplicated node 104 */ 105 106 static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr, 107 struct tipc_media_addr *media_addr) 108 { 109 char node_addr_str[16]; 110 char media_addr_str[64]; 111 struct print_buf pb; 112 113 tipc_addr_string_fill(node_addr_str, node_addr); 114 tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str)); 115 tipc_media_addr_printf(&pb, media_addr); 116 tipc_printbuf_validate(&pb); 117 warn("Duplicate %s using %s seen on <%s>\n", 118 node_addr_str, media_addr_str, b_ptr->publ.name); 119 } 120 121 /** 122 * tipc_disc_recv_msg - handle incoming link setup message (request or response) 123 * @buf: buffer containing message 124 * @b_ptr: bearer that message arrived on 125 */ 126 127 void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) 128 { 129 struct link *link; 130 struct tipc_media_addr media_addr; 131 struct tipc_msg *msg = buf_msg(buf); 132 u32 dest = msg_dest_domain(msg); 133 u32 orig = msg_prevnode(msg); 134 u32 net_id = msg_bc_netid(msg); 135 u32 type = msg_type(msg); 136 137 msg_get_media_addr(msg,&media_addr); 138 msg_dbg(msg, "RECV:"); 139 buf_discard(buf); 140 141 if (net_id != tipc_net_id) 142 return; 143 if (!tipc_addr_domain_valid(dest)) 144 return; 145 if (!tipc_addr_node_valid(orig)) 146 return; 147 if (orig == tipc_own_addr) { 148 if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr))) 149 disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); 150 return; 151 } 152 if (!tipc_in_scope(dest, tipc_own_addr)) 153 return; 154 if (is_slave(tipc_own_addr) && is_slave(orig)) 155 return; 156 if (is_slave(orig) && !in_own_cluster(orig)) 157 return; 158 if (in_own_cluster(orig)) { 159 /* Always accept link here */ 160 struct sk_buff *rbuf; 161 struct tipc_media_addr *addr; 162 struct tipc_node *n_ptr = tipc_node_find(orig); 163 int link_fully_up; 164 165 dbg(" in own cluster\n"); 166 if (n_ptr == NULL) { 167 n_ptr = tipc_node_create(orig); 168 if (!n_ptr) 169 return; 170 } 171 spin_lock_bh(&n_ptr->lock); 172 173 /* Don't talk to neighbor during cleanup after last session */ 174 175 if (n_ptr->cleanup_required) { 176 spin_unlock_bh(&n_ptr->lock); 177 return; 178 } 179 180 link = n_ptr->links[b_ptr->identity]; 181 if (!link) { 182 dbg("creating link\n"); 183 link = tipc_link_create(b_ptr, orig, &media_addr); 184 if (!link) { 185 spin_unlock_bh(&n_ptr->lock); 186 return; 187 } 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 spin_unlock_bh(&n_ptr->lock); 194 return; 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 link_fully_up = link_working_working(link); 202 spin_unlock_bh(&n_ptr->lock); 203 if ((type == DSC_RESP_MSG) || link_fully_up) 204 return; 205 rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr); 206 if (rbuf != NULL) { 207 msg_dbg(buf_msg(rbuf),"SEND:"); 208 b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr); 209 buf_discard(rbuf); 210 } 211 } 212 } 213 214 /** 215 * tipc_disc_stop_link_req - stop sending periodic link setup requests 216 * @req: ptr to link request structure 217 */ 218 219 void tipc_disc_stop_link_req(struct link_req *req) 220 { 221 if (!req) 222 return; 223 224 k_cancel_timer(&req->timer); 225 k_term_timer(&req->timer); 226 buf_discard(req->buf); 227 kfree(req); 228 } 229 230 /** 231 * tipc_disc_update_link_req - update frequency of periodic link setup requests 232 * @req: ptr to link request structure 233 */ 234 235 void tipc_disc_update_link_req(struct link_req *req) 236 { 237 if (!req) 238 return; 239 240 if (req->timer_intv == TIPC_LINK_REQ_SLOW) { 241 if (!req->bearer->nodes.count) { 242 req->timer_intv = TIPC_LINK_REQ_FAST; 243 k_start_timer(&req->timer, req->timer_intv); 244 } 245 } else if (req->timer_intv == TIPC_LINK_REQ_FAST) { 246 if (req->bearer->nodes.count) { 247 req->timer_intv = TIPC_LINK_REQ_SLOW; 248 k_start_timer(&req->timer, req->timer_intv); 249 } 250 } else { 251 /* leave timer "as is" if haven't yet reached a "normal" rate */ 252 } 253 } 254 255 /** 256 * disc_timeout - send a periodic link setup request 257 * @req: ptr to link request structure 258 * 259 * Called whenever a link setup request timer associated with a bearer expires. 260 */ 261 262 static void disc_timeout(struct link_req *req) 263 { 264 spin_lock_bh(&req->bearer->publ.lock); 265 266 req->bearer->media->send_msg(req->buf, &req->bearer->publ, &req->dest); 267 268 if ((req->timer_intv == TIPC_LINK_REQ_SLOW) || 269 (req->timer_intv == TIPC_LINK_REQ_FAST)) { 270 /* leave timer interval "as is" if already at a "normal" rate */ 271 } else { 272 req->timer_intv *= 2; 273 if (req->timer_intv > TIPC_LINK_REQ_FAST) 274 req->timer_intv = TIPC_LINK_REQ_FAST; 275 if ((req->timer_intv == TIPC_LINK_REQ_FAST) && 276 (req->bearer->nodes.count)) 277 req->timer_intv = TIPC_LINK_REQ_SLOW; 278 } 279 k_start_timer(&req->timer, req->timer_intv); 280 281 spin_unlock_bh(&req->bearer->publ.lock); 282 } 283 284 /** 285 * tipc_disc_init_link_req - start sending periodic link setup requests 286 * @b_ptr: ptr to bearer issuing requests 287 * @dest: destination address for request messages 288 * @dest_domain: network domain of node(s) which should respond to message 289 * @req_links: max number of desired links 290 * 291 * Returns pointer to link request structure, or NULL if unable to create. 292 */ 293 294 struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr, 295 const struct tipc_media_addr *dest, 296 u32 dest_domain, 297 u32 req_links) 298 { 299 struct link_req *req; 300 301 req = kmalloc(sizeof(*req), GFP_ATOMIC); 302 if (!req) 303 return NULL; 304 305 req->buf = tipc_disc_init_msg(DSC_REQ_MSG, req_links, dest_domain, b_ptr); 306 if (!req->buf) { 307 kfree(req); 308 return NULL; 309 } 310 311 memcpy(&req->dest, dest, sizeof(*dest)); 312 req->bearer = b_ptr; 313 req->timer_intv = TIPC_LINK_REQ_INIT; 314 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); 315 k_start_timer(&req->timer, req->timer_intv); 316 return req; 317 } 318 319