diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/discover.c | 103 |
1 files changed, 59 insertions, 44 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 09ce2318b89e..2345268ca64b 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
| @@ -119,17 +119,21 @@ static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr, | |||
| 119 | 119 | ||
| 120 | void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | 120 | void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) |
| 121 | { | 121 | { |
| 122 | struct tipc_node *n_ptr; | ||
| 122 | struct link *link; | 123 | struct link *link; |
| 123 | struct tipc_media_addr media_addr; | 124 | struct tipc_media_addr media_addr, *addr; |
| 125 | struct sk_buff *rbuf; | ||
| 124 | struct tipc_msg *msg = buf_msg(buf); | 126 | struct tipc_msg *msg = buf_msg(buf); |
| 125 | u32 dest = msg_dest_domain(msg); | 127 | u32 dest = msg_dest_domain(msg); |
| 126 | u32 orig = msg_prevnode(msg); | 128 | u32 orig = msg_prevnode(msg); |
| 127 | u32 net_id = msg_bc_netid(msg); | 129 | u32 net_id = msg_bc_netid(msg); |
| 128 | u32 type = msg_type(msg); | 130 | u32 type = msg_type(msg); |
| 131 | int link_fully_up; | ||
| 129 | 132 | ||
| 130 | msg_get_media_addr(msg, &media_addr); | 133 | msg_get_media_addr(msg, &media_addr); |
| 131 | buf_discard(buf); | 134 | buf_discard(buf); |
| 132 | 135 | ||
| 136 | /* Validate discovery message from requesting node */ | ||
| 133 | if (net_id != tipc_net_id) | 137 | if (net_id != tipc_net_id) |
| 134 | return; | 138 | return; |
| 135 | if (!tipc_addr_domain_valid(dest)) | 139 | if (!tipc_addr_domain_valid(dest)) |
| @@ -143,56 +147,67 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
| 143 | } | 147 | } |
| 144 | if (!tipc_in_scope(dest, tipc_own_addr)) | 148 | if (!tipc_in_scope(dest, tipc_own_addr)) |
| 145 | return; | 149 | return; |
| 146 | if (in_own_cluster(orig)) { | 150 | if (!in_own_cluster(orig)) |
| 147 | /* Always accept link here */ | 151 | return; |
| 148 | struct sk_buff *rbuf; | ||
| 149 | struct tipc_media_addr *addr; | ||
| 150 | struct tipc_node *n_ptr = tipc_node_find(orig); | ||
| 151 | int link_fully_up; | ||
| 152 | |||
| 153 | if (n_ptr == NULL) { | ||
| 154 | n_ptr = tipc_node_create(orig); | ||
| 155 | if (!n_ptr) | ||
| 156 | return; | ||
| 157 | } | ||
| 158 | spin_lock_bh(&n_ptr->lock); | ||
| 159 | |||
| 160 | /* Don't talk to neighbor during cleanup after last session */ | ||
| 161 | 152 | ||
| 162 | if (n_ptr->cleanup_required) { | 153 | /* Locate structure corresponding to requesting node */ |
| 163 | spin_unlock_bh(&n_ptr->lock); | 154 | n_ptr = tipc_node_find(orig); |
| 155 | if (!n_ptr) { | ||
| 156 | n_ptr = tipc_node_create(orig); | ||
| 157 | if (!n_ptr) | ||
| 164 | return; | 158 | return; |
| 165 | } | 159 | } |
| 160 | tipc_node_lock(n_ptr); | ||
| 161 | |||
| 162 | /* Don't talk to neighbor during cleanup after last session */ | ||
| 163 | if (n_ptr->cleanup_required) { | ||
| 164 | tipc_node_unlock(n_ptr); | ||
| 165 | return; | ||
| 166 | } | ||
| 166 | 167 | ||
| 167 | link = n_ptr->links[b_ptr->identity]; | 168 | link = n_ptr->links[b_ptr->identity]; |
| 169 | |||
| 170 | /* Create a link endpoint for this bearer, if necessary */ | ||
| 171 | if (!link) { | ||
| 172 | link = tipc_link_create(b_ptr, orig, &media_addr); | ||
| 168 | if (!link) { | 173 | if (!link) { |
| 169 | link = tipc_link_create(b_ptr, orig, &media_addr); | 174 | tipc_node_unlock(n_ptr); |
| 170 | if (!link) { | 175 | return; |
| 171 | spin_unlock_bh(&n_ptr->lock); | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | addr = &link->media_addr; | ||
| 176 | if (memcmp(addr, &media_addr, sizeof(*addr))) { | ||
| 177 | if (tipc_link_is_up(link) || (!link->started)) { | ||
| 178 | disc_dupl_alert(b_ptr, orig, &media_addr); | ||
| 179 | spin_unlock_bh(&n_ptr->lock); | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | warn("Resetting link <%s>, peer interface address changed\n", | ||
| 183 | link->name); | ||
| 184 | memcpy(addr, &media_addr, sizeof(*addr)); | ||
| 185 | tipc_link_reset(link); | ||
| 186 | } | 176 | } |
| 187 | link_fully_up = link_working_working(link); | 177 | } |
| 188 | spin_unlock_bh(&n_ptr->lock); | 178 | |
| 189 | if ((type == DSC_RESP_MSG) || link_fully_up) | 179 | /* |
| 180 | * Ensure requesting node's media address is correct | ||
| 181 | * | ||
| 182 | * If media address doesn't match and the link is working, reject the | ||
| 183 | * request (must be from a duplicate node). | ||
| 184 | * | ||
| 185 | * If media address doesn't match and the link is not working, accept | ||
| 186 | * the new media address and reset the link to ensure it starts up | ||
| 187 | * cleanly. | ||
| 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 | tipc_node_unlock(n_ptr); | ||
| 190 | return; | 194 | return; |
| 191 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); | ||
| 192 | if (rbuf != NULL) { | ||
| 193 | b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); | ||
| 194 | buf_discard(rbuf); | ||
| 195 | } | 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 | |||
| 202 | /* Accept discovery message & send response, if necessary */ | ||
| 203 | link_fully_up = link_working_working(link); | ||
| 204 | tipc_node_unlock(n_ptr); | ||
| 205 | if ((type == DSC_RESP_MSG) || link_fully_up) | ||
| 206 | return; | ||
| 207 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); | ||
| 208 | if (rbuf != NULL) { | ||
| 209 | b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); | ||
| 210 | buf_discard(rbuf); | ||
| 196 | } | 211 | } |
| 197 | } | 212 | } |
| 198 | 213 | ||
