return l->state & (LINK_RESET | LINK_FAILINGOVER | LINK_ESTABLISHING);
}
+bool tipc_link_is_establishing(struct tipc_link *l)
+{
+ return l->state == LINK_ESTABLISHING;
+}
+
bool tipc_link_is_synching(struct tipc_link *l)
{
return l->state == LINK_SYNCHING;
switch (evt) {
case LINK_ESTABLISH_EVT:
l->state = LINK_ESTABLISHED;
- rc |= TIPC_LINK_UP_EVT;
break;
case LINK_FAILOVER_BEGIN_EVT:
l->state = LINK_FAILINGOVER;
break;
- case LINK_PEER_RESET_EVT:
case LINK_RESET_EVT:
+ l->state = LINK_RESET;
+ break;
case LINK_FAILURE_EVT:
+ case LINK_PEER_RESET_EVT:
case LINK_SYNCH_BEGIN_EVT:
case LINK_FAILOVER_END_EVT:
break;
return tipc_link_proto_rcv(l, skb, xmitq);
if (unlikely(!link_is_up(l))) {
- rc = tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
- if (!link_is_up(l))
- goto drop;
+ if (l->state == LINK_ESTABLISHING)
+ rc = TIPC_LINK_UP_EVT;
+ goto drop;
}
/* Don't send probe at next timeout expiration */
u16 peers_tol = msg_link_tolerance(hdr);
u16 peers_prio = msg_linkprio(hdr);
u16 rcv_nxt = l->rcv_nxt;
+ int mtyp = msg_type(hdr);
char *if_name;
int rc = 0;
if (link_own_addr(l) > msg_prevnode(hdr))
l->net_plane = msg_net_plane(hdr);
- switch (msg_type(hdr)) {
+ switch (mtyp) {
case RESET_MSG:
/* Ignore duplicate RESET with old session number */
if (in_range(peers_prio, l->priority + 1, TIPC_MAX_LINK_PRI))
l->priority = peers_prio;
- if (msg_type(hdr) == RESET_MSG) {
- rc |= tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT);
- } else if (!link_is_up(l)) {
- tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT);
- rc |= tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
- }
+ /* ACTIVATE_MSG serves as PEER_RESET if link is already down */
+ if ((mtyp == RESET_MSG) || !link_is_up(l))
+ rc = tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT);
+
+ /* ACTIVATE_MSG takes up link if it was already locally reset */
+ if ((mtyp == ACTIVATE_MSG) && (l->state == LINK_ESTABLISHING))
+ rc = TIPC_LINK_UP_EVT;
+
l->peer_session = msg_session(hdr);
l->peer_bearer_id = msg_bearer_id(hdr);
if (l->mtu > msg_max_pkt(hdr))
l->stats.recv_states++;
if (msg_probe(hdr))
l->stats.recv_probes++;
- rc = tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
- if (!link_is_up(l))
+
+ if (!link_is_up(l)) {
+ if (l->state == LINK_ESTABLISHING)
+ rc = TIPC_LINK_UP_EVT;
break;
+ }
/* Send NACK if peer has sent pkts we haven't received yet */
if (more(peers_snd_nxt, rcv_nxt) && !tipc_link_is_synching(l))
struct tipc_link *ol = node_active_link(n, 0);
struct tipc_link *nl = n->links[bearer_id].link;
- if (!nl || !tipc_link_is_up(nl))
+ if (!nl)
+ return;
+
+ tipc_link_fsm_evt(nl, LINK_ESTABLISH_EVT);
+ if (!tipc_link_is_up(nl))
return;
n->working_links++;
static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete)
{
struct tipc_link_entry *le = &n->links[bearer_id];
+ struct tipc_link *l = le->link;
struct tipc_media_addr *maddr;
struct sk_buff_head xmitq;
+ if (!l)
+ return;
+
__skb_queue_head_init(&xmitq);
tipc_node_lock(n);
- __tipc_node_link_down(n, &bearer_id, &xmitq, &maddr);
- if (delete && le->link) {
- kfree(le->link);
- le->link = NULL;
- n->link_cnt--;
+ if (!tipc_link_is_establishing(l)) {
+ __tipc_node_link_down(n, &bearer_id, &xmitq, &maddr);
+ if (delete) {
+ kfree(l);
+ le->link = NULL;
+ n->link_cnt--;
+ }
+ } else {
+ /* Defuse pending tipc_node_link_up() */
+ tipc_link_fsm_evt(l, LINK_RESET_EVT);
}
tipc_node_unlock(n);
memcpy(&le->maddr, maddr, sizeof(*maddr));
exit:
tipc_node_unlock(n);
- if (reset)
+ if (reset && !tipc_link_is_reset(l))
tipc_node_link_down(n, b->identity, false);
tipc_node_put(n);
}
break;
case SELF_ESTABL_CONTACT_EVT:
case PEER_LOST_CONTACT_EVT:
- break;
case NODE_SYNCH_END_EVT:
- case NODE_SYNCH_BEGIN_EVT:
case NODE_FAILOVER_BEGIN_EVT:
+ break;
+ case NODE_SYNCH_BEGIN_EVT:
case NODE_FAILOVER_END_EVT:
default:
goto illegal_evt;