wlcore/wl12xx: spi: fix oops on firmware load
[pandora-kernel.git] / net / tipc / link.c
index f89570c..ae98a72 100644 (file)
@@ -332,15 +332,16 @@ struct link *tipc_link_create(struct tipc_node *n_ptr,
 
        l_ptr->addr = peer;
        if_name = strchr(b_ptr->name, ':') + 1;
-       sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:",
+       sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown",
                tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
                tipc_node(tipc_own_addr),
                if_name,
                tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
-               /* note: peer i/f is appended to link name by reset/activate */
+               /* note: peer i/f name is updated by reset/activate message */
        memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
        l_ptr->owner = n_ptr;
        l_ptr->checkpoint = 1;
+       l_ptr->peer_session = INVALID_SESSION;
        l_ptr->b_ptr = b_ptr;
        link_set_supervision_props(l_ptr, b_ptr->media->tolerance);
        l_ptr->state = RESET_UNKNOWN;
@@ -536,9 +537,6 @@ void tipc_link_stop(struct link *l_ptr)
        l_ptr->proto_msg_queue = NULL;
 }
 
-/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
-#define link_send_event(fcn, l_ptr, up) do { } while (0)
-
 void tipc_link_reset(struct link *l_ptr)
 {
        struct sk_buff *buf;
@@ -596,10 +594,6 @@ void tipc_link_reset(struct link *l_ptr)
        l_ptr->fsm_msg_cnt = 0;
        l_ptr->stale_count = 0;
        link_reset_statistics(l_ptr);
-
-       link_send_event(tipc_cfg_link_event, l_ptr, 0);
-       if (!in_own_cluster(l_ptr->addr))
-               link_send_event(tipc_disc_link_event, l_ptr, 0);
 }
 
 
@@ -608,9 +602,6 @@ static void link_activate(struct link *l_ptr)
        l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
        tipc_node_link_up(l_ptr->owner, l_ptr);
        tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
-       link_send_event(tipc_cfg_link_event, l_ptr, 1);
-       if (!in_own_cluster(l_ptr->addr))
-               link_send_event(tipc_disc_link_event, l_ptr, 1);
 }
 
 /**
@@ -984,6 +975,51 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
        return res;
 }
 
+/*
+ * tipc_link_send_names - send name table entries to new neighbor
+ *
+ * Send routine for bulk delivery of name table messages when contact
+ * with a new neighbor occurs. No link congestion checking is performed
+ * because name table messages *must* be delivered. The messages must be
+ * small enough not to require fragmentation.
+ * Called without any locks held.
+ */
+
+void tipc_link_send_names(struct list_head *message_list, u32 dest)
+{
+       struct tipc_node *n_ptr;
+       struct link *l_ptr;
+       struct sk_buff *buf;
+       struct sk_buff *temp_buf;
+
+       if (list_empty(message_list))
+               return;
+
+       read_lock_bh(&tipc_net_lock);
+       n_ptr = tipc_node_find(dest);
+       if (n_ptr) {
+               tipc_node_lock(n_ptr);
+               l_ptr = n_ptr->active_links[0];
+               if (l_ptr) {
+                       /* convert circular list to linear list */
+                       ((struct sk_buff *)message_list->prev)->next = NULL;
+                       link_add_chain_to_outqueue(l_ptr,
+                               (struct sk_buff *)message_list->next, 0);
+                       tipc_link_push_queue(l_ptr);
+                       INIT_LIST_HEAD(message_list);
+               }
+               tipc_node_unlock(n_ptr);
+       }
+       read_unlock_bh(&tipc_net_lock);
+
+       /* discard the messages if they couldn't be sent */
+
+       list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) {
+               list_del((struct list_head *)buf);
+               buf_discard(buf);
+       }
+}
+
 /*
  * link_send_buf_fast: Entry for data messages where the
  * destination link is known and the header is complete,
@@ -1031,9 +1067,6 @@ int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
        u32 selector = msg_origport(buf_msg(buf)) & 1;
        u32 dummy;
 
-       if (destnode == tipc_own_addr)
-               return tipc_port_recv_msg(buf);
-
        read_lock_bh(&tipc_net_lock);
        n_ptr = tipc_node_find(destnode);
        if (likely(n_ptr)) {
@@ -1658,19 +1691,12 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
                        continue;
                }
 
+               /* Discard unicast link messages destined for another node */
+
                if (unlikely(!msg_short(msg) &&
                             (msg_destnode(msg) != tipc_own_addr)))
                        goto cont;
 
-               /* Discard non-routeable messages destined for another node */
-
-               if (unlikely(!msg_isdata(msg) &&
-                            (msg_destnode(msg) != tipc_own_addr))) {
-                       if ((msg_user(msg) != CONN_MANAGER) &&
-                           (msg_user(msg) != MSG_FRAGMENTER))
-                               goto cont;
-               }
-
                /* Locate neighboring node that sent message */
 
                n_ptr = tipc_node_find(msg_prevnode(msg));
@@ -1678,17 +1704,24 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
                        goto cont;
                tipc_node_lock(n_ptr);
 
-               /* Don't talk to neighbor during cleanup after last session */
+               /* Locate unicast link endpoint that should handle message */
 
-               if (n_ptr->cleanup_required) {
+               l_ptr = n_ptr->links[b_ptr->identity];
+               if (unlikely(!l_ptr)) {
                        tipc_node_unlock(n_ptr);
                        goto cont;
                }
 
-               /* Locate unicast link endpoint that should handle message */
+               /* Verify that communication with node is currently allowed */
 
-               l_ptr = n_ptr->links[b_ptr->identity];
-               if (unlikely(!l_ptr)) {
+               if ((n_ptr->block_setup & WAIT_PEER_DOWN) &&
+                       msg_user(msg) == LINK_PROTOCOL &&
+                       (msg_type(msg) == RESET_MSG ||
+                                       msg_type(msg) == ACTIVATE_MSG) &&
+                       !msg_redundant_link(msg))
+                       n_ptr->block_setup &= ~WAIT_PEER_DOWN;
+
+               if (n_ptr->block_setup) {
                        tipc_node_unlock(n_ptr);
                        goto cont;
                }
@@ -1923,6 +1956,12 @@ void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
 
        if (link_blocked(l_ptr))
                return;
+
+       /* Abort non-RESET send if communication with node is prohibited */
+
+       if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG))
+               return;
+
        msg_set_type(msg, msg_typ);
        msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
        msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in));
@@ -2051,9 +2090,19 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
        case RESET_MSG:
                if (!link_working_unknown(l_ptr) &&
                    (l_ptr->peer_session != INVALID_SESSION)) {
-                       if (msg_session(msg) == l_ptr->peer_session)
-                               break; /* duplicate: ignore */
+                       if (less_eq(msg_session(msg), l_ptr->peer_session))
+                               break; /* duplicate or old reset: ignore */
+               }
+
+               if (!msg_redundant_link(msg) && (link_working_working(l_ptr) ||
+                               link_working_unknown(l_ptr))) {
+                       /*
+                        * peer has lost contact -- don't allow peer's links
+                        * to reactivate before we recognize loss & clean up
+                        */
+                       l_ptr->owner->block_setup = WAIT_NODE_DOWN;
                }
+
                /* fall thru' */
        case ACTIVATE_MSG:
                /* Update link settings according other endpoint's values */