aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2014-05-14 05:39:14 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-14 15:19:48 -0400
commitc82910e2a8d6fc9dd321a1f30dd4e89fb779cfe1 (patch)
tree5f6d454d653fe9c7189481f28972595498e5c888 /net/tipc
parent38504c28a201a80d12a6a0f821fecb331cb1f223 (diff)
tipc: clean up neigbor discovery message reception
The function tipc_disc_rcv(), which is handling received neighbor discovery messages, is perceived as messy, and it is hard to verify its correctness by code inspection. The fact that the task it is set to resolve is fairly complex does not make the situation better. In this commit we try to take a more systematic approach to the problem. We define a decision machine which takes three state flags as input, and produces three action flags as output. We then walk through all permutations of the state flags, and for each of them we describe verbally what is going on, plus that we set zero or more of the action flags. The action flags indicate what should be done once the decision machine has finished its job, while the last part of the function deals with performing those actions. Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-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/**