fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / tipc / link.c
index 511872a..1bb983c 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/link.c: TIPC link code
  * 
  * Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -132,7 +132,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
  * allow the output from multiple links to be intermixed.  For this reason
  * routines of the form "dbg_link_XXX()" have been created that will capture
  * debug info into a link's personal print buffer, which can then be dumped
- * into the TIPC system log (LOG) upon request.
+ * into the TIPC system log (TIPC_LOG) upon request.
  *
  * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
  * of the print buffer used by each link.  If LINK_LOG_BUF_SIZE is set to 0,
@@ -141,7 +141,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
  * when there is only a single link in the system being debugged.
  *
  * Notes:
- * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
+ * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE
  * - "l_ptr" must be valid when using dbg_link_XXX() macros  
  */
 
@@ -157,15 +157,15 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
        } \
 } while (0)
 
-static inline void dbg_print_link(struct link *l_ptr, const char *str)
+static void dbg_print_link(struct link *l_ptr, const char *str)
 {
-       if (DBG_OUTPUT)
+       if (DBG_OUTPUT != TIPC_NULL)
                link_print(l_ptr, DBG_OUTPUT, str);
 }
 
-static inline void dbg_print_buf_chain(struct sk_buff *root_buf)
+static void dbg_print_buf_chain(struct sk_buff *root_buf)
 {
-       if (DBG_OUTPUT) {
+       if (DBG_OUTPUT != TIPC_NULL) {
                struct sk_buff *buf = root_buf;
 
                while (buf) {
@@ -176,50 +176,50 @@ static inline void dbg_print_buf_chain(struct sk_buff *root_buf)
 }
 
 /*
- *  Simple inlined link routines
+ *  Simple link routines
  */
 
-static inline unsigned int align(unsigned int i)
+static unsigned int align(unsigned int i)
 {
        return (i + 3) & ~3u;
 }
 
-static inline int link_working_working(struct link *l_ptr)
+static int link_working_working(struct link *l_ptr)
 {
        return (l_ptr->state == WORKING_WORKING);
 }
 
-static inline int link_working_unknown(struct link *l_ptr)
+static int link_working_unknown(struct link *l_ptr)
 {
        return (l_ptr->state == WORKING_UNKNOWN);
 }
 
-static inline int link_reset_unknown(struct link *l_ptr)
+static int link_reset_unknown(struct link *l_ptr)
 {
        return (l_ptr->state == RESET_UNKNOWN);
 }
 
-static inline int link_reset_reset(struct link *l_ptr)
+static int link_reset_reset(struct link *l_ptr)
 {
        return (l_ptr->state == RESET_RESET);
 }
 
-static inline int link_blocked(struct link *l_ptr)
+static int link_blocked(struct link *l_ptr)
 {
        return (l_ptr->exp_msg_count || l_ptr->blocked);
 }
 
-static inline int link_congested(struct link *l_ptr)
+static int link_congested(struct link *l_ptr)
 {
        return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
 }
 
-static inline u32 link_max_pkt(struct link *l_ptr)
+static u32 link_max_pkt(struct link *l_ptr)
 {
        return l_ptr->max_pkt;
 }
 
-static inline void link_init_max_pkt(struct link *l_ptr)
+static void link_init_max_pkt(struct link *l_ptr)
 {
        u32 max_pkt;
        
@@ -236,20 +236,20 @@ static inline void link_init_max_pkt(struct link *l_ptr)
         l_ptr->max_pkt_probes = 0;
 }
 
-static inline u32 link_next_sent(struct link *l_ptr)
+static u32 link_next_sent(struct link *l_ptr)
 {
        if (l_ptr->next_out)
                return msg_seqno(buf_msg(l_ptr->next_out));
        return mod(l_ptr->next_out_no);
 }
 
-static inline u32 link_last_sent(struct link *l_ptr)
+static u32 link_last_sent(struct link *l_ptr)
 {
        return mod(link_next_sent(l_ptr) - 1);
 }
 
 /*
- *  Simple non-inlined link routines (i.e. referenced outside this file)
+ *  Simple non-static link routines (i.e. referenced outside this file)
  */
 
 int tipc_link_is_up(struct link *l_ptr)
@@ -396,7 +396,7 @@ static void link_timeout(struct link *l_ptr)
        tipc_node_unlock(l_ptr->owner);
 }
 
-static inline void link_set_timer(struct link *l_ptr, u32 time)
+static void link_set_timer(struct link *l_ptr, u32 time)
 {
        k_start_timer(&l_ptr->timer, time);
 }
@@ -417,12 +417,11 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
        struct tipc_msg *msg;
        char *if_name;
 
-       l_ptr = (struct link *)kmalloc(sizeof(*l_ptr), GFP_ATOMIC);
+       l_ptr = kzalloc(sizeof(*l_ptr), GFP_ATOMIC);
        if (!l_ptr) {
-               warn("Memory squeeze; Failed to create link\n");
+               warn("Link creation failed, no memory\n");
                return NULL;
        }
-       memset(l_ptr, 0, sizeof(*l_ptr));
 
        l_ptr->addr = peer;
        if_name = strchr(b_ptr->publ.name, ':') + 1;
@@ -469,7 +468,7 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
 
                if (!pb) {
                        kfree(l_ptr);
-                       warn("Memory squeeze; Failed to create link\n");
+                       warn("Link creation failed, no memory for print buffer\n");
                        return NULL;
                }
                tipc_printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
@@ -573,8 +572,7 @@ void tipc_link_wakeup_ports(struct link *l_ptr, int all)
                if (win <= 0)
                        break;
                list_del_init(&p_ptr->wait_list);
-               p_ptr->congested_link = 0;
-               assert(p_ptr->wakeup);
+               p_ptr->congested_link = NULL;
                spin_lock_bh(p_ptr->publ.lock);
                p_ptr->publ.congested = 0;
                p_ptr->wakeup(&p_ptr->publ);
@@ -691,6 +689,7 @@ void tipc_link_reset(struct link *l_ptr)
        struct sk_buff *buf;
        u32 prev_state = l_ptr->state;
        u32 checkpoint = l_ptr->next_in_no;
+       int was_active_link = tipc_link_is_active(l_ptr);
        
        msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
 
@@ -712,7 +711,7 @@ void tipc_link_reset(struct link *l_ptr)
        tipc_printf(TIPC_CONS, "\nReset link <%s>\n", l_ptr->name);
        dbg_link_dump();
 #endif
-       if (tipc_node_has_active_links(l_ptr->owner) &&
+       if (was_active_link && tipc_node_has_active_links(l_ptr->owner) &&
            l_ptr->owner->permit_changeover) {
                l_ptr->reset_checkpoint = checkpoint;
                l_ptr->exp_msg_count = START_CHANGEOVER;
@@ -755,7 +754,7 @@ void tipc_link_reset(struct link *l_ptr)
 
 static void link_activate(struct link *l_ptr)
 {
-       l_ptr->next_in_no = 1;
+       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);
@@ -820,6 +819,8 @@ static void link_state_event(struct link *l_ptr, unsigned event)
                        break;
                case RESET_MSG:
                        dbg_link("RES -> RR\n");
+                       info("Resetting link <%s>, requested by peer\n", 
+                            l_ptr->name);
                        tipc_link_reset(l_ptr);
                        l_ptr->state = RESET_RESET;
                        l_ptr->fsm_msg_cnt = 0;
@@ -844,6 +845,8 @@ static void link_state_event(struct link *l_ptr, unsigned event)
                        break;
                case RESET_MSG:
                        dbg_link("RES -> RR\n");
+                       info("Resetting link <%s>, requested by peer "
+                            "while probing\n", l_ptr->name);
                        tipc_link_reset(l_ptr);
                        l_ptr->state = RESET_RESET;
                        l_ptr->fsm_msg_cnt = 0;
@@ -875,6 +878,8 @@ static void link_state_event(struct link *l_ptr, unsigned event)
                        } else {        /* Link has failed */
                                dbg_link("-> RU (%u probes unanswered)\n",
                                         l_ptr->fsm_msg_cnt);
+                               warn("Resetting link <%s>, peer not responding\n",
+                                    l_ptr->name);
                                tipc_link_reset(l_ptr);
                                l_ptr->state = RESET_UNKNOWN;
                                l_ptr->fsm_msg_cnt = 0;
@@ -982,17 +987,20 @@ static int link_bundle_buf(struct link *l_ptr,
        struct tipc_msg *bundler_msg = buf_msg(bundler);
        struct tipc_msg *msg = buf_msg(buf);
        u32 size = msg_size(msg);
-       u32 to_pos = align(msg_size(bundler_msg));
-       u32 rest = link_max_pkt(l_ptr) - to_pos;
+       u32 bundle_size = msg_size(bundler_msg);
+       u32 to_pos = align(bundle_size);
+       u32 pad = to_pos - bundle_size;
 
        if (msg_user(bundler_msg) != MSG_BUNDLER)
                return 0;
        if (msg_type(bundler_msg) != OPEN_MSG)
                return 0;
-       if (rest < align(size))
+       if (skb_tailroom(bundler) < (pad + size))
+               return 0;
+       if (link_max_pkt(l_ptr) < (to_pos + size))
                return 0;
 
-       skb_put(bundler, (to_pos - msg_size(bundler_msg)) + size);
+       skb_put(bundler, pad + size);
        memcpy(bundler->data + to_pos, buf->data, size);
        msg_set_size(bundler_msg, to_pos + size);
        msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
@@ -1004,9 +1012,9 @@ static int link_bundle_buf(struct link *l_ptr,
        return 1;
 }
 
-static inline void link_add_to_outqueue(struct link *l_ptr, 
-                                       struct sk_buff *buf, 
-                                       struct tipc_msg *msg)
+static void link_add_to_outqueue(struct link *l_ptr,
+                                struct sk_buff *buf,
+                                struct tipc_msg *msg)
 {
        u32 ack = mod(l_ptr->next_in_no - 1);
        u32 seqno = mod(l_ptr->next_out_no++);
@@ -1050,7 +1058,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
                msg_dbg(msg, "TIPC: Congestion, throwing away\n");
                buf_discard(buf);
                if (imp > CONN_MANAGER) {
-                       warn("Resetting <%s>, send queue full", l_ptr->name);
+                       warn("Resetting link <%s>, send queue full", l_ptr->name);
                        tipc_link_reset(l_ptr);
                }
                return dsz;
@@ -1135,9 +1143,13 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
        if (n_ptr) {
                tipc_node_lock(n_ptr);
                l_ptr = n_ptr->active_links[selector & 1];
-               dbg("tipc_link_send: found link %x for dest %x\n", l_ptr, dest);
                if (l_ptr) {
+                       dbg("tipc_link_send: found link %x for dest %x\n", l_ptr, dest);
                        res = tipc_link_send_buf(l_ptr, buf);
+               } else {
+                       dbg("Attempt to send msg to unreachable node:\n");
+                       msg_dbg(buf_msg(buf),">>>");
+                       buf_discard(buf);
                }
                tipc_node_unlock(n_ptr);
        } else {
@@ -1156,8 +1168,8 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
  * Link is locked. Returns user data length.
  */
 
-static inline int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
-                                    u32 *used_max_pkt)
+static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
+                             u32 *used_max_pkt)
 {
        struct tipc_msg *msg = buf_msg(buf);
        int res = msg_data_sz(msg);
@@ -1242,8 +1254,6 @@ int tipc_link_send_sections_fast(struct port *sender,
        int res;
        u32 selector = msg_origport(hdr) & 1;
 
-       assert(destaddr != tipc_own_addr);
-
 again:
        /*
         * Try building message using port's max_pkt hint.
@@ -1355,7 +1365,7 @@ again:
        fragm_crs = 0;
        fragm_rest = 0;
        sect_rest = 0;
-       sect_crs = 0;
+       sect_crs = NULL;
        curr_sect = -1;
 
        /* Prepare reusable fragment header: */
@@ -1549,7 +1559,7 @@ u32 tipc_link_push_packet(struct link *l_ptr)
                        msg_dbg(buf_msg(buf), ">DEF-PROT>");
                        l_ptr->unacked_window = 0;
                        buf_discard(buf);
-                       l_ptr->proto_msg_queue = 0;
+                       l_ptr->proto_msg_queue = NULL;
                        return TIPC_OK;
                } else {
                        msg_dbg(buf_msg(buf), "|>DEF-PROT>");
@@ -1604,40 +1614,122 @@ void tipc_link_push_queue(struct link *l_ptr)
                tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
 }
 
+static void link_reset_all(unsigned long addr)
+{
+       struct node *n_ptr;
+       char addr_string[16];
+       u32 i;
+
+       read_lock_bh(&tipc_net_lock);
+       n_ptr = tipc_node_find((u32)addr);
+       if (!n_ptr) {
+               read_unlock_bh(&tipc_net_lock);
+               return; /* node no longer exists */
+       }
+
+       tipc_node_lock(n_ptr);
+
+       warn("Resetting all links to %s\n", 
+            addr_string_fill(addr_string, n_ptr->addr));
+
+       for (i = 0; i < MAX_BEARERS; i++) {
+               if (n_ptr->links[i]) {
+                       link_print(n_ptr->links[i], TIPC_OUTPUT, 
+                                  "Resetting link\n");
+                       tipc_link_reset(n_ptr->links[i]);
+               }
+       }
+
+       tipc_node_unlock(n_ptr);
+       read_unlock_bh(&tipc_net_lock);
+}
+
+static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+
+       warn("Retransmission failure on link <%s>\n", l_ptr->name);
+       tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>");
+
+       if (l_ptr->addr) {
+
+               /* Handle failure on standard link */
+
+               link_print(l_ptr, TIPC_OUTPUT, "Resetting link\n");
+               tipc_link_reset(l_ptr);
+
+       } else {
+
+               /* Handle failure on broadcast link */
+
+               struct node *n_ptr;
+               char addr_string[16];
+
+               tipc_printf(TIPC_OUTPUT, "Msg seq number: %u,  ", msg_seqno(msg));
+               tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n",
+                                    (unsigned long) TIPC_SKB_CB(buf)->handle);
+
+               n_ptr = l_ptr->owner->next;
+               tipc_node_lock(n_ptr);
+
+               addr_string_fill(addr_string, n_ptr->addr);
+               tipc_printf(TIPC_OUTPUT, "Multicast link info for %s\n", addr_string);
+               tipc_printf(TIPC_OUTPUT, "Supported: %d,  ", n_ptr->bclink.supported);
+               tipc_printf(TIPC_OUTPUT, "Acked: %u\n", n_ptr->bclink.acked);
+               tipc_printf(TIPC_OUTPUT, "Last in: %u,  ", n_ptr->bclink.last_in);
+               tipc_printf(TIPC_OUTPUT, "Gap after: %u,  ", n_ptr->bclink.gap_after);
+               tipc_printf(TIPC_OUTPUT, "Gap to: %u\n", n_ptr->bclink.gap_to);
+               tipc_printf(TIPC_OUTPUT, "Nack sync: %u\n\n", n_ptr->bclink.nack_sync);
+
+               tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr);
+
+               tipc_node_unlock(n_ptr);
+
+               l_ptr->stale_count = 0;
+       }
+}
+
 void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, 
                          u32 retransmits)
 {
        struct tipc_msg *msg;
 
+       if (!buf)
+               return;
+
+       msg = buf_msg(buf);
+       
        dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
 
-       if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr) && buf && !skb_cloned(buf)) {
-               msg_dbg(buf_msg(buf), ">NO_RETR->BCONG>");
-               dbg_print_link(l_ptr, "   ");
-               l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
-               l_ptr->retransm_queue_size = retransmits;
-               return;
+       if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
+               if (!skb_cloned(buf)) {
+                       msg_dbg(msg, ">NO_RETR->BCONG>");
+                       dbg_print_link(l_ptr, "   ");
+                       l_ptr->retransm_queue_head = msg_seqno(msg);
+                       l_ptr->retransm_queue_size = retransmits;
+                       return;
+               } else {
+                       /* Don't retransmit if driver already has the buffer */
+               }
+       } else {
+               /* Detect repeated retransmit failures on uncongested bearer */
+
+               if (l_ptr->last_retransmitted == msg_seqno(msg)) {
+                       if (++l_ptr->stale_count > 100) {
+                               link_retransmit_failure(l_ptr, buf);
+                               return;
+                       }
+               } else {
+                       l_ptr->last_retransmitted = msg_seqno(msg);
+                       l_ptr->stale_count = 1;
+               }
        }
+
        while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
                msg = buf_msg(buf);
                msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
                msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
                if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
-                        /* Catch if retransmissions fail repeatedly: */
-                        if (l_ptr->last_retransmitted == msg_seqno(msg)) {
-                                if (++l_ptr->stale_count > 100) {
-                                        tipc_msg_print(TIPC_CONS, buf_msg(buf), ">RETR>");
-                                        info("...Retransmitted %u times\n",
-                                            l_ptr->stale_count);
-                                        link_print(l_ptr, TIPC_CONS, "Resetting Link\n");;
-                                        tipc_link_reset(l_ptr);
-                                        break;
-                                }
-                        } else {
-                                l_ptr->stale_count = 0;
-                        }
-                        l_ptr->last_retransmitted = msg_seqno(msg);
-
                        msg_dbg(buf_msg(buf), ">RETR>");
                        buf = buf->next;
                        retransmits--;
@@ -1650,6 +1742,7 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
                        return;
                }
        }
+
        l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
 }
 
@@ -1720,6 +1813,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
                        link_recv_non_seq(buf);
                        continue;
                }
+               
+               if (unlikely(!msg_short(msg) &&
+                            (msg_destnode(msg) != tipc_own_addr)))
+                       goto cont;
+               
                n_ptr = tipc_node_find(msg_prevnode(msg));
                if (unlikely(!n_ptr))
                        goto cont;
@@ -1860,7 +1958,7 @@ u32 tipc_link_defer_pkt(struct sk_buff **head,
                        struct sk_buff **tail,
                        struct sk_buff *buf)
 {
-       struct sk_buff *prev = 0;
+       struct sk_buff *prev = NULL;
        struct sk_buff *crs = *head;
        u32 seq_no = msg_seqno(buf_msg(buf));
 
@@ -1953,7 +2051,7 @@ static void link_handle_out_of_seq_msg(struct link *l_ptr,
 void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
                              u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
 {
-       struct sk_buff *buf = 0;
+       struct sk_buff *buf = NULL;
        struct tipc_msg *msg = l_ptr->pmsg;
         u32 msg_size = sizeof(l_ptr->proto_msg);
 
@@ -2140,7 +2238,7 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
                
                if (msg_linkprio(msg) && 
                    (msg_linkprio(msg) != l_ptr->priority)) {
-                       warn("Changing prio <%s>: %u->%u\n",
+                       warn("Resetting link <%s>, priority change %u->%u\n",
                             l_ptr->name, l_ptr->priority, msg_linkprio(msg));
                        l_ptr->priority = msg_linkprio(msg);
                        tipc_link_reset(l_ptr); /* Enforce change to take effect */
@@ -2209,17 +2307,22 @@ void tipc_link_tunnel(struct link *l_ptr,
        u32 length = msg_size(msg);
 
        tunnel = l_ptr->owner->active_links[selector & 1];
-       if (!tipc_link_is_up(tunnel))
+       if (!tipc_link_is_up(tunnel)) {
+               warn("Link changeover error, "
+                    "tunnel link no longer available\n");
                return;
+       }
        msg_set_size(tunnel_hdr, length + INT_H_SIZE);
        buf = buf_acquire(length + INT_H_SIZE);
-       if (!buf)
+       if (!buf) {
+               warn("Link changeover error, "
+                    "unable to send tunnel msg\n");
                return;
+       }
        memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE);
        memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length);
        dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
        msg_dbg(buf_msg(buf), ">SEND>");
-       assert(tunnel);
        tipc_link_send_buf(tunnel, buf);
 }
 
@@ -2235,23 +2338,27 @@ void tipc_link_changeover(struct link *l_ptr)
        u32 msgcount = l_ptr->out_queue_size;
        struct sk_buff *crs = l_ptr->first_out;
        struct link *tunnel = l_ptr->owner->active_links[0];
-       int split_bundles = tipc_node_has_redundant_links(l_ptr->owner);
        struct tipc_msg tunnel_hdr;
+       int split_bundles;
 
        if (!tunnel)
                return;
 
-       if (!l_ptr->owner->permit_changeover)
+       if (!l_ptr->owner->permit_changeover) {
+               warn("Link changeover error, "
+                    "peer did not permit changeover\n");
                return;
+       }
 
        msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
                 ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
        msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
        msg_set_msgcnt(&tunnel_hdr, msgcount);
+       dbg("Link changeover requires %u tunnel messages\n", msgcount);
+
        if (!l_ptr->first_out) {
                struct sk_buff *buf;
 
-               assert(!msgcount);
                buf = buf_acquire(INT_H_SIZE);
                if (buf) {
                        memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
@@ -2261,10 +2368,15 @@ void tipc_link_changeover(struct link *l_ptr)
                        msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
                        tipc_link_send_buf(tunnel, buf);
                } else {
-                       warn("Memory squeeze; link changeover failed\n");
+                       warn("Link changeover error, "
+                            "unable to send changeover msg\n");
                }
                return;
        }
+
+       split_bundles = (l_ptr->owner->active_links[0] != 
+                        l_ptr->owner->active_links[1]);
+
        while (crs) {
                struct tipc_msg *msg = buf_msg(crs);
 
@@ -2310,7 +2422,8 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
                msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
                outbuf = buf_acquire(length + INT_H_SIZE);
                if (outbuf == NULL) {
-                       warn("Memory squeeze; buffer duplication failed\n");
+                       warn("Link changeover error, "
+                            "unable to send duplicate msg\n");
                        return;
                }
                memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
@@ -2364,11 +2477,15 @@ static int link_recv_changeover_msg(struct link **l_ptr,
        u32 msg_count = msg_msgcnt(tunnel_msg);
 
        dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
-       assert(dest_link != *l_ptr);
        if (!dest_link) {
                msg_dbg(tunnel_msg, "NOLINK/<REC<");
                goto exit;
        }
+       if (dest_link == *l_ptr) {
+               err("Unexpected changeover message on link <%s>\n", 
+                   (*l_ptr)->name);
+               goto exit;
+       }
        dbg("%c<-%c:", dest_link->b_ptr->net_plane,
            (*l_ptr)->b_ptr->net_plane);
        *l_ptr = dest_link;
@@ -2381,7 +2498,7 @@ static int link_recv_changeover_msg(struct link **l_ptr,
                }
                *buf = buf_extract(tunnel_buf,INT_H_SIZE);
                if (*buf == NULL) {
-                       warn("Memory squeeze; failed to extract msg\n");
+                       warn("Link changeover error, duplicate msg dropped\n");
                        goto exit;
                }
                msg_dbg(tunnel_msg, "TNL<REC<");
@@ -2393,13 +2510,17 @@ static int link_recv_changeover_msg(struct link **l_ptr,
 
        if (tipc_link_is_up(dest_link)) {
                msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
+               info("Resetting link <%s>, changeover initiated by peer\n",
+                    dest_link->name);
                tipc_link_reset(dest_link);
                dest_link->exp_msg_count = msg_count;
+               dbg("Expecting %u tunnelled messages\n", msg_count);
                if (!msg_count)
                        goto exit;
        } else if (dest_link->exp_msg_count == START_CHANGEOVER) {
                msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
                dest_link->exp_msg_count = msg_count;
+               dbg("Expecting %u tunnelled messages\n", msg_count);
                if (!msg_count)
                        goto exit;
        }
@@ -2407,6 +2528,8 @@ static int link_recv_changeover_msg(struct link **l_ptr,
        /* Receive original message */
 
        if (dest_link->exp_msg_count == 0) {
+               warn("Link switchover error, "
+                    "got too many tunnelled messages\n");
                msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
                dbg_print_link(dest_link, "LINK:");
                goto exit;
@@ -2422,11 +2545,11 @@ static int link_recv_changeover_msg(struct link **l_ptr,
                        buf_discard(tunnel_buf);
                        return 1;
                } else {
-                       warn("Memory squeeze; dropped incoming msg\n");
+                       warn("Link changeover error, original msg dropped\n");
                }
        }
 exit:
-       *buf = 0;
+       *buf = NULL;
        buf_discard(tunnel_buf);
        return 0;
 }
@@ -2444,13 +2567,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf)
        while (msgcount--) {
                obuf = buf_extract(buf, pos);
                if (obuf == NULL) {
-                       char addr_string[16];
-
-                       warn("Buffer allocation failure;\n");
-                       warn("  incoming message(s) from %s lost\n",
-                            addr_string_fill(addr_string, 
-                                             msg_orignode(buf_msg(buf))));
-                       return;
+                       warn("Link unable to unbundle message(s)\n");
+                       break;
                };
                pos += align(msg_size(buf_msg(obuf)));
                msg_dbg(buf_msg(obuf), "     /");
@@ -2508,7 +2626,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
                }
                fragm = buf_acquire(fragm_sz + INT_H_SIZE);
                if (fragm == NULL) {
-                       warn("Memory squeeze; failed to fragment msg\n");
+                       warn("Link unable to fragment message\n");
                        dsz = -ENOMEM;
                        goto exit;
                }
@@ -2539,42 +2657,37 @@ exit:
  * pending message. This makes dynamic memory allocation unecessary.
  */
 
-static inline u32 get_long_msg_seqno(struct sk_buff *buf)
-{
-       return msg_seqno(buf_msg(buf));
-}
-
-static inline void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
+static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
 {
        msg_set_seqno(buf_msg(buf), seqno);
 }
 
-static inline u32 get_fragm_size(struct sk_buff *buf)
+static u32 get_fragm_size(struct sk_buff *buf)
 {
        return msg_ack(buf_msg(buf));
 }
 
-static inline void set_fragm_size(struct sk_buff *buf, u32 sz)
+static void set_fragm_size(struct sk_buff *buf, u32 sz)
 {
        msg_set_ack(buf_msg(buf), sz);
 }
 
-static inline u32 get_expected_frags(struct sk_buff *buf)
+static u32 get_expected_frags(struct sk_buff *buf)
 {
        return msg_bcast_ack(buf_msg(buf));
 }
 
-static inline void set_expected_frags(struct sk_buff *buf, u32 exp)
+static void set_expected_frags(struct sk_buff *buf, u32 exp)
 {
        msg_set_bcast_ack(buf_msg(buf), exp);
 }
 
-static inline u32 get_timer_cnt(struct sk_buff *buf)
+static u32 get_timer_cnt(struct sk_buff *buf)
 {
        return msg_reroute_cnt(buf_msg(buf));
 }
 
-static inline void incr_timer_cnt(struct sk_buff *buf)
+static void incr_timer_cnt(struct sk_buff *buf)
 {
        msg_incr_reroute_cnt(buf_msg(buf));
 }
@@ -2586,13 +2699,13 @@ static inline void incr_timer_cnt(struct sk_buff *buf)
 int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, 
                            struct tipc_msg **m)
 {
-       struct sk_buff *prev = 0;
+       struct sk_buff *prev = NULL;
        struct sk_buff *fbuf = *fb;
        struct tipc_msg *fragm = buf_msg(fbuf);
        struct sk_buff *pbuf = *pending;
        u32 long_msg_seq_no = msg_long_msgno(fragm);
 
-       *fb = 0;
+       *fb = NULL;
        msg_dbg(fragm,"FRG<REC<");
 
        /* Is there an incomplete message waiting for this fragment? */
@@ -2628,7 +2741,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
                        set_fragm_size(pbuf,fragm_sz); 
                        set_expected_frags(pbuf,exp_fragm_cnt - 1); 
                } else {
-                       warn("Memory squeeze; got no defragmenting buffer\n");
+                       warn("Link unable to reassemble fragmented message\n");
                }
                buf_discard(fbuf);
                return 0;
@@ -2670,8 +2783,8 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
 
 static void link_check_defragm_bufs(struct link *l_ptr)
 {
-       struct sk_buff *prev = 0;
-       struct sk_buff *next = 0;
+       struct sk_buff *prev = NULL;
+       struct sk_buff *next = NULL;
        struct sk_buff *buf = l_ptr->defragm_buf;
 
        if (!buf)
@@ -2750,19 +2863,19 @@ static struct link *link_find_link(const char *name, struct node **node)
        struct link *l_ptr; 
 
        if (!link_name_validate(name, &link_name_parts))
-               return 0;
+               return NULL;
 
        b_ptr = tipc_bearer_find_interface(link_name_parts.if_local);
        if (!b_ptr)
-               return 0;
+               return NULL;
 
        *node = tipc_node_find(link_name_parts.addr_peer); 
        if (!*node)
-               return 0;
+               return NULL;
 
        l_ptr = (*node)->links[b_ptr->identity];
        if (!l_ptr || strcmp(l_ptr->name, name))
-               return 0;
+               return NULL;
 
        return l_ptr;
 }