diff options
Diffstat (limited to 'net/tipc/discover.c')
| -rw-r--r-- | net/tipc/discover.c | 281 |
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 | */ |
| 57 | struct tipc_link_req { | 58 | struct 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 | */ |
| 72 | static struct sk_buff *tipc_disc_init_msg(u32 type, struct tipc_bearer *b_ptr) | 74 | static 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 | */ |
| 114 | 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) |
| 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 | */ | ||
| 390 | void 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 | } | ||
