diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/addr.h | 7 | ||||
-rw-r--r-- | net/tipc/bcast.c | 28 | ||||
-rw-r--r-- | net/tipc/bearer.c | 46 | ||||
-rw-r--r-- | net/tipc/bearer.h | 2 | ||||
-rw-r--r-- | net/tipc/core.c | 3 | ||||
-rw-r--r-- | net/tipc/core.h | 8 | ||||
-rw-r--r-- | net/tipc/discover.c | 150 | ||||
-rw-r--r-- | net/tipc/discover.h | 11 | ||||
-rw-r--r-- | net/tipc/link.c | 110 | ||||
-rw-r--r-- | net/tipc/link.h | 1 | ||||
-rw-r--r-- | net/tipc/msg.c | 31 | ||||
-rw-r--r-- | net/tipc/msg.h | 195 | ||||
-rw-r--r-- | net/tipc/name_distr.c | 6 | ||||
-rw-r--r-- | net/tipc/name_table.c | 289 | ||||
-rw-r--r-- | net/tipc/name_table.h | 14 | ||||
-rw-r--r-- | net/tipc/port.c | 339 | ||||
-rw-r--r-- | net/tipc/port.h | 14 | ||||
-rw-r--r-- | net/tipc/socket.c | 30 | ||||
-rw-r--r-- | net/tipc/subscr.c | 4 |
19 files changed, 597 insertions, 691 deletions
diff --git a/net/tipc/addr.h b/net/tipc/addr.h index 8971aba99ae..e4f35afe320 100644 --- a/net/tipc/addr.h +++ b/net/tipc/addr.h @@ -37,14 +37,17 @@ #ifndef _TIPC_ADDR_H #define _TIPC_ADDR_H +#define TIPC_ZONE_MASK 0xff000000u +#define TIPC_CLUSTER_MASK 0xfffff000u + static inline u32 tipc_zone_mask(u32 addr) { - return addr & 0xff000000u; + return addr & TIPC_ZONE_MASK; } static inline u32 tipc_cluster_mask(u32 addr) { - return addr & 0xfffff000u; + return addr & TIPC_CLUSTER_MASK; } static inline int in_own_cluster(u32 addr) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 7dc1dc7151e..759b318b5ff 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -44,13 +44,6 @@ #define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */ -/* - * Loss rate for incoming broadcast frames; used to test retransmission code. - * Set to N to cause every N'th frame to be discarded; 0 => don't discard any. - */ - -#define TIPC_BCAST_LOSS_RATE 0 - /** * struct bcbearer_pair - a pair of bearers used by broadcast link * @primary: pointer to primary bearer @@ -414,9 +407,7 @@ int tipc_bclink_send_msg(struct sk_buff *buf) spin_lock_bh(&bc_lock); res = tipc_link_send_buf(bcl, buf); - if (unlikely(res == -ELINKCONG)) - buf_discard(buf); - else + if (likely(res > 0)) bclink_set_last_sent(); bcl->stats.queue_sz_counts++; @@ -434,9 +425,6 @@ int tipc_bclink_send_msg(struct sk_buff *buf) void tipc_bclink_recv_pkt(struct sk_buff *buf) { -#if (TIPC_BCAST_LOSS_RATE) - static int rx_count; -#endif struct tipc_msg *msg = buf_msg(buf); struct tipc_node *node = tipc_node_find(msg_prevnode(msg)); u32 next_in; @@ -470,14 +458,6 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) return; } -#if (TIPC_BCAST_LOSS_RATE) - if (++rx_count == TIPC_BCAST_LOSS_RATE) { - rx_count = 0; - buf_discard(buf); - return; - } -#endif - tipc_node_lock(node); receive: deferred = node->bclink.deferred_head; @@ -572,12 +552,16 @@ static int tipc_bcbearer_send(struct sk_buff *buf, if (likely(!msg_non_seq(buf_msg(buf)))) { struct tipc_msg *msg; - assert(tipc_bcast_nmap.count != 0); bcbuf_set_acks(buf, tipc_bcast_nmap.count); msg = buf_msg(buf); msg_set_non_seq(msg, 1); msg_set_mc_netid(msg, tipc_net_id); bcl->stats.sent_info++; + + if (WARN_ON(!tipc_bcast_nmap.count)) { + dump_stack(); + return 0; + } } /* Send buffer over bearers until all targets reached */ diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 411719feb80..85eba9c08ee 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -46,6 +46,8 @@ static u32 media_count; struct tipc_bearer tipc_bearers[MAX_BEARERS]; +static void bearer_disable(struct tipc_bearer *b_ptr); + /** * media_name_valid - validate media name * @@ -342,15 +344,15 @@ struct sk_buff *tipc_bearer_get_names(void) void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest) { tipc_nmap_add(&b_ptr->nodes, dest); - tipc_disc_update_link_req(b_ptr->link_req); tipc_bcbearer_sort(); + tipc_disc_add_dest(b_ptr->link_req); } void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest) { tipc_nmap_remove(&b_ptr->nodes, dest); - tipc_disc_update_link_req(b_ptr->link_req); tipc_bcbearer_sort(); + tipc_disc_remove_dest(b_ptr->link_req); } /* @@ -400,7 +402,6 @@ void tipc_bearer_lock_push(struct tipc_bearer *b_ptr) void tipc_continue(struct tipc_bearer *b_ptr) { spin_lock_bh(&b_ptr->lock); - b_ptr->continue_count++; if (!list_empty(&b_ptr->cong_links)) tipc_k_signal((Handler)tipc_bearer_lock_push, (unsigned long)b_ptr); b_ptr->blocked = 0; @@ -493,8 +494,15 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) warn("Bearer <%s> rejected, illegal name\n", name); return -EINVAL; } - if (!tipc_addr_domain_valid(disc_domain) || - !tipc_in_scope(disc_domain, tipc_own_addr)) { + if (tipc_addr_domain_valid(disc_domain) && + (disc_domain != tipc_own_addr)) { + if (tipc_in_scope(disc_domain, tipc_own_addr)) { + disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK; + res = 0; /* accept any node in own cluster */ + } else if (in_own_cluster(disc_domain)) + res = 0; /* accept specified node in own cluster */ + } + if (res) { warn("Bearer <%s> rejected, illegal discovery domain\n", name); return -EINVAL; } @@ -511,7 +519,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) if (!m_ptr) { warn("Bearer <%s> rejected, media <%s> not registered\n", name, b_name.media_name); - goto failed; + goto exit; } if (priority == TIPC_MEDIA_LINK_PRI) @@ -527,14 +535,14 @@ restart: } if (!strcmp(name, tipc_bearers[i].name)) { warn("Bearer <%s> rejected, already enabled\n", name); - goto failed; + goto exit; } if ((tipc_bearers[i].priority == priority) && (++with_this_prio > 2)) { if (priority-- == 0) { warn("Bearer <%s> rejected, duplicate priority\n", name); - goto failed; + goto exit; } warn("Bearer <%s> priority adjustment required %u->%u\n", name, priority + 1, priority); @@ -544,7 +552,7 @@ restart: if (bearer_id >= MAX_BEARERS) { warn("Bearer <%s> rejected, bearer limit reached (%u)\n", name, MAX_BEARERS); - goto failed; + goto exit; } b_ptr = &tipc_bearers[bearer_id]; @@ -552,7 +560,7 @@ restart: res = m_ptr->enable_bearer(b_ptr); if (res) { warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res); - goto failed; + goto exit; } b_ptr->identity = bearer_id; @@ -562,14 +570,18 @@ restart: b_ptr->priority = priority; INIT_LIST_HEAD(&b_ptr->cong_links); INIT_LIST_HEAD(&b_ptr->links); - b_ptr->link_req = tipc_disc_init_link_req(b_ptr, &m_ptr->bcast_addr, - disc_domain); spin_lock_init(&b_ptr->lock); - write_unlock_bh(&tipc_net_lock); + + res = tipc_disc_create(b_ptr, &m_ptr->bcast_addr, disc_domain); + if (res) { + bearer_disable(b_ptr); + warn("Bearer <%s> rejected, discovery object creation failed\n", + name); + goto exit; + } info("Enabled bearer <%s>, discovery domain %s, priority %u\n", name, tipc_addr_string_fill(addr_string, disc_domain), priority); - return 0; -failed: +exit: write_unlock_bh(&tipc_net_lock); return res; } @@ -620,14 +632,14 @@ static void bearer_disable(struct tipc_bearer *b_ptr) struct link *temp_l_ptr; info("Disabling bearer <%s>\n", b_ptr->name); - tipc_disc_stop_link_req(b_ptr->link_req); spin_lock_bh(&b_ptr->lock); - b_ptr->link_req = NULL; b_ptr->blocked = 1; b_ptr->media->disable_bearer(b_ptr); list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { tipc_link_delete(l_ptr); } + if (b_ptr->link_req) + tipc_disc_delete(b_ptr->link_req); spin_unlock_bh(&b_ptr->lock); memset(b_ptr, 0, sizeof(struct tipc_bearer)); } diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 31d6172b20f..5ad70eff1eb 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -107,7 +107,6 @@ struct media { * @link_req: ptr to (optional) structure making periodic link setup requests * @links: list of non-congested links associated with bearer * @cong_links: list of congested links associated with bearer - * @continue_count: # of times bearer has resumed after congestion or blocking * @active: non-zero if bearer structure is represents a bearer * @net_plane: network plane ('A' through 'H') currently associated with bearer * @nodes: indicates which nodes in cluster can be reached through bearer @@ -129,7 +128,6 @@ struct tipc_bearer { struct link_req *link_req; struct list_head links; struct list_head cong_links; - u32 continue_count; int active; char net_plane; struct tipc_node_map nodes; diff --git a/net/tipc/core.c b/net/tipc/core.c index c9a73e7763f..943b6af8426 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -179,8 +179,7 @@ static int __init tipc_init(void) if (tipc_log_resize(CONFIG_TIPC_LOG) != 0) warn("Unable to create log buffer\n"); - info("Activated (version " TIPC_MOD_VER - " compiled " __DATE__ " " __TIME__ ")\n"); + info("Activated (version " TIPC_MOD_VER ")\n"); tipc_own_addr = 0; tipc_remote_management = 1; diff --git a/net/tipc/core.h b/net/tipc/core.h index 436dda1159d..2761af36d14 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -47,7 +47,7 @@ #include <linux/string.h> #include <asm/uaccess.h> #include <linux/interrupt.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <asm/hardirq.h> #include <linux/netdevice.h> #include <linux/in.h> @@ -62,12 +62,6 @@ struct tipc_msg; /* msg.h */ struct print_buf; /* log.h */ /* - * TIPC sanity test macros - */ - -#define assert(i) BUG_ON(!(i)) - -/* * TIPC system monitoring code */ diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 491eff56b9d..0987933155b 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -39,19 +39,17 @@ #include "discover.h" #define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */ -#define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */ -#define TIPC_LINK_REQ_SLOW 600000 /* normal delay if bearer has links */ - -/* - * TODO: Most of the inter-cluster setup stuff should be - * rewritten, and be made conformant with specification. - */ +#define TIPC_LINK_REQ_FAST 1000 /* max delay if bearer has no links */ +#define TIPC_LINK_REQ_SLOW 60000 /* max delay if bearer has links */ +#define TIPC_LINK_REQ_INACTIVE 0xffffffff /* indicates no timer in use */ /** * struct link_req - information about an ongoing link setup request * @bearer: bearer issuing requests * @dest: destination address for request messages + * @domain: network domain to which links can be established + * @num_nodes: number of nodes currently discovered (i.e. with an active link) * @buf: request message to be (repeatedly) sent * @timer: timer governing period between requests * @timer_intv: current interval between requests (in ms) @@ -59,6 +57,8 @@ struct link_req { struct tipc_bearer *bearer; struct tipc_media_addr dest; + u32 domain; + int num_nodes; struct sk_buff *buf; struct timer_list timer; unsigned int timer_intv; @@ -147,7 +147,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } if (!tipc_in_scope(dest, tipc_own_addr)) return; - if (!in_own_cluster(orig)) + if (!tipc_in_scope(b_ptr->link_req->domain, orig)) return; /* Locate structure corresponding to requesting node */ @@ -214,44 +214,54 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } /** - * tipc_disc_stop_link_req - stop sending periodic link setup requests + * disc_update - update frequency of periodic link setup requests * @req: ptr to link request structure + * + * Reinitiates discovery process if discovery object has no associated nodes + * and is either not currently searching or is searching at a slow rate */ -void tipc_disc_stop_link_req(struct link_req *req) +static void disc_update(struct link_req *req) { - if (!req) - return; + if (!req->num_nodes) { + if ((req->timer_intv == TIPC_LINK_REQ_INACTIVE) || + (req->timer_intv > TIPC_LINK_REQ_FAST)) { + req->timer_intv = TIPC_LINK_REQ_INIT; + k_start_timer(&req->timer, req->timer_intv); + } + } +} - k_cancel_timer(&req->timer); - k_term_timer(&req->timer); - buf_discard(req->buf); - kfree(req); +/** + * tipc_disc_add_dest - increment set of discovered nodes + * @req: ptr to link request structure + */ + +void tipc_disc_add_dest(struct link_req *req) +{ + req->num_nodes++; } /** - * tipc_disc_update_link_req - update frequency of periodic link setup requests + * tipc_disc_remove_dest - decrement set of discovered nodes * @req: ptr to link request structure */ -void tipc_disc_update_link_req(struct link_req *req) +void tipc_disc_remove_dest(struct link_req *req) { - if (!req) - return; + req->num_nodes--; + disc_update(req); +} - if (req->timer_intv == TIPC_LINK_REQ_SLOW) { - if (!req->bearer->nodes.count) { - req->timer_intv = TIPC_LINK_REQ_FAST; - k_start_timer(&req->timer, req->timer_intv); - } - } else if (req->timer_intv == TIPC_LINK_REQ_FAST) { - if (req->bearer->nodes.count) { - req->timer_intv = TIPC_LINK_REQ_SLOW; - k_start_timer(&req->timer, req->timer_intv); - } - } else { - /* leave timer "as is" if haven't yet reached a "normal" rate */ - } +/** + * disc_send_msg - send link setup request message + * @req: ptr to link request structure + */ + +static void disc_send_msg(struct link_req *req) +{ + if (!req->bearer->blocked) + tipc_bearer_send(req->bearer, req->buf, &req->dest); } /** @@ -263,56 +273,86 @@ void tipc_disc_update_link_req(struct link_req *req) static void disc_timeout(struct link_req *req) { + int max_delay; + spin_lock_bh(&req->bearer->lock); - req->bearer->media->send_msg(req->buf, req->bearer, &req->dest); - - if ((req->timer_intv == TIPC_LINK_REQ_SLOW) || - (req->timer_intv == TIPC_LINK_REQ_FAST)) { - /* leave timer interval "as is" if already at a "normal" rate */ - } else { - req->timer_intv *= 2; - if (req->timer_intv > TIPC_LINK_REQ_FAST) - req->timer_intv = TIPC_LINK_REQ_FAST; - if ((req->timer_intv == TIPC_LINK_REQ_FAST) && - (req->bearer->nodes.count)) - req->timer_intv = TIPC_LINK_REQ_SLOW; + /* Stop searching if only desired node has been found */ + + if (tipc_node(req->domain) && req->num_nodes) { + req->timer_intv = TIPC_LINK_REQ_INACTIVE; + goto exit; } - k_start_timer(&req->timer, req->timer_intv); + /* + * Send discovery message, then update discovery timer + * + * Keep doubling time between requests until limit is reached; + * hold at fast polling rate if don't have any associated nodes, + * otherwise hold at slow polling rate + */ + + disc_send_msg(req); + + req->timer_intv *= 2; + if (req->num_nodes) + max_delay = TIPC_LINK_REQ_SLOW; + else + max_delay = TIPC_LINK_REQ_FAST; + if (req->timer_intv > max_delay) + req->timer_intv = max_delay; + + k_start_timer(&req->timer, req->timer_intv); +exit: spin_unlock_bh(&req->bearer->lock); } /** - * tipc_disc_init_link_req - start sending periodic link setup requests + * tipc_disc_create - create object to send periodic link setup requests * @b_ptr: ptr to bearer issuing requests * @dest: destination address for request messages - * @dest_domain: network domain of node(s) which should respond to message + * @dest_domain: network domain to which links can be established * - * Returns pointer to link request structure, or NULL if unable to create. + * Returns 0 if successful, otherwise -errno. */ -struct link_req *tipc_disc_init_link_req(struct tipc_bearer *b_ptr, - const struct tipc_media_addr *dest, - u32 dest_domain) +int tipc_disc_create(struct tipc_bearer *b_ptr, + struct tipc_media_addr *dest, u32 dest_domain) { struct link_req *req; req = kmalloc(sizeof(*req), GFP_ATOMIC); if (!req) - return NULL; + return -ENOMEM; req->buf = tipc_disc_init_msg(DSC_REQ_MSG, dest_domain, b_ptr); if (!req->buf) { kfree(req); - return NULL; + return -ENOMSG; } memcpy(&req->dest, dest, sizeof(*dest)); req->bearer = b_ptr; + req->domain = dest_domain; + req->num_nodes = 0; req->timer_intv = TIPC_LINK_REQ_INIT; k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); k_start_timer(&req->timer, req->timer_intv); - return req; + b_ptr->link_req = req; + disc_send_msg(req); + return 0; +} + +/** + * tipc_disc_delete - destroy object sending periodic link setup requests + * @req: ptr to link request structure + */ + +void tipc_disc_delete(struct link_req *req) +{ + k_cancel_timer(&req->timer); + k_term_timer(&req->timer); + buf_discard(req->buf); + kfree(req); } diff --git a/net/tipc/discover.h b/net/tipc/discover.h index e48a167e47b..a3af595b86c 100644 --- a/net/tipc/discover.h +++ b/net/tipc/discover.h @@ -39,12 +39,11 @@ struct link_req; -struct link_req *tipc_disc_init_link_req(struct tipc_bearer *b_ptr, - const struct tipc_media_addr *dest, - u32 dest_domain); -void tipc_disc_update_link_req(struct link_req *req); -void tipc_disc_stop_link_req(struct link_req *req); - +int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest, + u32 dest_domain); +void tipc_disc_delete(struct link_req *req); +void tipc_disc_add_dest(struct link_req *req); +void tipc_disc_remove_dest(struct link_req *req); void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr); #endif diff --git a/net/tipc/link.c b/net/tipc/link.c index ebf338f7b14..f89570c54f5 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -92,7 +92,8 @@ static int link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf); static void link_set_supervision_props(struct link *l_ptr, u32 tolerance); static int link_send_sections_long(struct tipc_port *sender, struct iovec const *msg_sect, - u32 num_sect, u32 destnode); + u32 num_sect, unsigned int total_len, + u32 destnode); static void link_check_defragm_bufs(struct link *l_ptr); static void link_state_event(struct link *l_ptr, u32 event); static void link_reset_statistics(struct link *l_ptr); @@ -842,6 +843,25 @@ static void link_add_to_outqueue(struct link *l_ptr, l_ptr->stats.max_queue_sz = l_ptr->out_queue_size; } +static void link_add_chain_to_outqueue(struct link *l_ptr, + struct sk_buff *buf_chain, + u32 long_msgno) +{ + struct sk_buff *buf; + struct tipc_msg *msg; + + if (!l_ptr->next_out) + l_ptr->next_out = buf_chain; + while (buf_chain) { + buf = buf_chain; + buf_chain = buf_chain->next; + + msg = buf_msg(buf); + msg_set_long_msgno(msg, long_msgno); + link_add_to_outqueue(l_ptr, buf, msg); + } +} + /* * tipc_link_send_buf() is the 'full path' for messages, called from * inside TIPC when the 'fast path' in tipc_send_buf @@ -864,8 +884,9 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf) if (unlikely(queue_size >= queue_limit)) { if (imp <= TIPC_CRITICAL_IMPORTANCE) { - return link_schedule_port(l_ptr, msg_origport(msg), - size); + link_schedule_port(l_ptr, msg_origport(msg), size); + buf_discard(buf); + return -ELINKCONG; } buf_discard(buf); if (imp > CONN_MANAGER) { @@ -1042,6 +1063,7 @@ int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode) int tipc_link_send_sections_fast(struct tipc_port *sender, struct iovec const *msg_sect, const u32 num_sect, + unsigned int total_len, u32 destaddr) { struct tipc_msg *hdr = &sender->phdr; @@ -1057,8 +1079,8 @@ again: * (Must not hold any locks while building message.) */ - res = tipc_msg_build(hdr, msg_sect, num_sect, sender->max_pkt, - !sender->user_port, &buf); + res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, + sender->max_pkt, !sender->user_port, &buf); read_lock_bh(&tipc_net_lock); node = tipc_node_find(destaddr); @@ -1069,8 +1091,6 @@ again: if (likely(buf)) { res = link_send_buf_fast(l_ptr, buf, &sender->max_pkt); - if (unlikely(res < 0)) - buf_discard(buf); exit: tipc_node_unlock(node); read_unlock_bh(&tipc_net_lock); @@ -1105,7 +1125,8 @@ exit: goto again; return link_send_sections_long(sender, msg_sect, - num_sect, destaddr); + num_sect, total_len, + destaddr); } tipc_node_unlock(node); } @@ -1117,7 +1138,7 @@ exit: return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); if (res >= 0) return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, - TIPC_ERR_NO_NODE); + total_len, TIPC_ERR_NO_NODE); return res; } @@ -1138,12 +1159,13 @@ exit: static int link_send_sections_long(struct tipc_port *sender, struct iovec const *msg_sect, u32 num_sect, + unsigned int total_len, u32 destaddr) { struct link *l_ptr; struct tipc_node *node; struct tipc_msg *hdr = &sender->phdr; - u32 dsz = msg_data_sz(hdr); + u32 dsz = total_len; u32 max_pkt, fragm_sz, rest; struct tipc_msg fragm_hdr; struct sk_buff *buf, *buf_chain, *prev; @@ -1169,7 +1191,6 @@ again: tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(hdr)); - msg_set_link_selector(&fragm_hdr, sender->ref); msg_set_size(&fragm_hdr, max_pkt); msg_set_fragm_no(&fragm_hdr, 1); @@ -1271,28 +1292,15 @@ reject: buf_discard(buf_chain); } return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, - TIPC_ERR_NO_NODE); + total_len, TIPC_ERR_NO_NODE); } - /* Append whole chain to send queue: */ + /* Append chain of fragments to send queue & send them */ - buf = buf_chain; - l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1); - if (!l_ptr->next_out) - l_ptr->next_out = buf_chain; + l_ptr->long_msg_seq_no++; + link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); + l_ptr->stats.sent_fragments += fragm_no; l_ptr->stats.sent_fragmented++; - while (buf) { - struct sk_buff *next = buf->next; - struct tipc_msg *msg = buf_msg(buf); - - l_ptr->stats.sent_fragments++; - msg_set_long_msgno(msg, l_ptr->long_msg_seq_no); - link_add_to_outqueue(l_ptr, buf, msg); - buf = next; - } - - /* Send it, if possible: */ - tipc_link_push_queue(l_ptr); tipc_node_unlock(node); return dsz; @@ -1564,7 +1572,7 @@ static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr, static int link_recv_buf_validate(struct sk_buff *buf) { static u32 min_data_hdr_size[8] = { - SHORT_H_SIZE, MCAST_H_SIZE, LONG_H_SIZE, DIR_MSG_H_SIZE, + SHORT_H_SIZE, MCAST_H_SIZE, NAMED_H_SIZE, BASIC_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE }; @@ -2407,6 +2415,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf) */ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) { + struct sk_buff *buf_chain = NULL; + struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain; struct tipc_msg *inmsg = buf_msg(buf); struct tipc_msg fragm_hdr; u32 insize = msg_size(inmsg); @@ -2415,7 +2425,7 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) u32 rest = insize; u32 pack_sz = l_ptr->max_pkt; u32 fragm_sz = pack_sz - INT_H_SIZE; - u32 fragm_no = 1; + u32 fragm_no = 0; u32 destaddr; if (msg_short(inmsg)) @@ -2427,10 +2437,6 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, destaddr); - msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg)); - msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++)); - msg_set_fragm_no(&fragm_hdr, fragm_no); - l_ptr->stats.sent_fragmented++; /* Chop up message: */ @@ -2443,27 +2449,37 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) } fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); if (fragm == NULL) { - warn("Link unable to fragment message\n"); - dsz = -ENOMEM; - goto exit; + buf_discard(buf); + while (buf_chain) { + buf = buf_chain; + buf_chain = buf_chain->next; + buf_discard(buf); + } + return -ENOMEM; } msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); + fragm_no++; + msg_set_fragm_no(&fragm_hdr, fragm_no); skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, fragm_sz); - /* Send queued messages first, if any: */ + buf_chain_tail->next = fragm; + buf_chain_tail = fragm; - l_ptr->stats.sent_fragments++; - tipc_link_send_buf(l_ptr, fragm); - if (!tipc_link_is_up(l_ptr)) - return dsz; - msg_set_fragm_no(&fragm_hdr, ++fragm_no); rest -= fragm_sz; crs += fragm_sz; msg_set_type(&fragm_hdr, FRAGMENT); } -exit: buf_discard(buf); + + /* Append chain of fragments to send queue & send them */ + + l_ptr->long_msg_seq_no++; + link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); + l_ptr->stats.sent_fragments += fragm_no; + l_ptr->stats.sent_fragmented++; + tipc_link_push_queue(l_ptr); + return dsz; } @@ -2537,7 +2553,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, u32 msg_sz = msg_size(imsg); u32 fragm_sz = msg_data_sz(fragm); u32 exp_fragm_cnt = msg_sz/fragm_sz + !!(msg_sz % fragm_sz); - u32 max = TIPC_MAX_USER_MSG_SIZE + LONG_H_SIZE; + u32 max = TIPC_MAX_USER_MSG_SIZE + NAMED_H_SIZE; if (msg_type(imsg) == TIPC_MCAST_MSG) max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE; if (msg_size(imsg) > max) { @@ -2866,7 +2882,7 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size) profile_total = 1; tipc_printf(&pb, " TX profile sample:%u packets average:%u octets\n" " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% " - "-16354:%u%% -32768:%u%% -66000:%u%%\n", + "-16384:%u%% -32768:%u%% -66000:%u%%\n", l_ptr->stats.msg_length_counts, l_ptr->stats.msg_lengths_total / profile_total, percent(l_ptr->stats.msg_length_profile[0], profile_total), diff --git a/net/tipc/link.h b/net/tipc/link.h index e6a30dbe1aa..74fbecab1ea 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -228,6 +228,7 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector); int tipc_link_send_sections_fast(struct tipc_port *sender, struct iovec const *msg_sect, const u32 num_sect, + unsigned int total_len, u32 destnode); void tipc_link_recv_bundle(struct sk_buff *buf); int tipc_link_recv_fragment(struct sk_buff **pending, diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 6d92d17e7fb..83d50967910 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -61,24 +61,8 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, msg_set_size(m, hsize); msg_set_prevnode(m, tipc_own_addr); msg_set_type(m, type); - if (!msg_short(m)) { - msg_set_orignode(m, tipc_own_addr); - msg_set_destnode(m, destnode); - } -} - -/** - * tipc_msg_calc_data_size - determine total data size for message - */ - -int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect) -{ - int dsz = 0; - int i; - - for (i = 0; i < num_sect; i++) - dsz += msg_sect[i].iov_len; - return dsz; + msg_set_orignode(m, tipc_own_addr); + msg_set_destnode(m, destnode); } /** @@ -89,18 +73,13 @@ int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect) * Returns message data size or errno */ -int tipc_msg_build(struct tipc_msg *hdr, - struct iovec const *msg_sect, u32 num_sect, +int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, + u32 num_sect, unsigned int total_len, int max_size, int usrmem, struct sk_buff **buf) { int dsz, sz, hsz, pos, res, cnt; - dsz = tipc_msg_calc_data_size(msg_sect, num_sect); - if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) { - *buf = NULL; - return -EINVAL; - } - + dsz = total_len; pos = hsz = msg_hdr_sz(hdr); sz = hsz + dsz; msg_set_size(hdr, sz); diff --git a/net/tipc/msg.h b/net/tipc/msg.h index de02339fc17..d93178f2e85 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -39,41 +39,24 @@ #include "bearer.h" +/* + * Constants and routines used to read and write TIPC payload message headers + * + * Note: Some items are also used with TIPC internal message headers + */ + #define TIPC_VERSION 2 /* - * TIPC user data message header format, version 2: - * - * - * 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w0:|vers | user |hdr sz |n|d|s|-| message size | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w1:|mstyp| error |rer cnt|lsc|opt p| broadcast ack no | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w2:| link level ack no | broadcast/link level seq no | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w3:| previous node | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w4:| originating port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w5:| destination port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w6:| originating node | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w7:| destination node | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w8:| name type / transport sequence number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w9:| name instance/multicast lower bound | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * wA:| multicast upper bound | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * / / - * \ options \ - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * + * Payload message users are defined in TIPC's public API: + * - TIPC_LOW_IMPORTANCE + * - TIPC_MEDIUM_IMPORTANCE + * - TIPC_HIGH_IMPORTANCE + * - TIPC_CRITICAL_IMPORTANCE + */ + +/* + * Payload message types */ #define TIPC_CONN_MSG 0 @@ -81,11 +64,14 @@ #define TIPC_NAMED_MSG 2 #define TIPC_DIRECT_MSG 3 +/* + * Message header sizes + */ -#define SHORT_H_SIZE 24 /* Connected, in-cluster messages */ -#define DIR_MSG_H_SIZE 32 /* Directly addressed messages */ -#define LONG_H_SIZE 40 /* Named messages */ -#define MCAST_H_SIZE 44 /* Multicast messages */ +#define SHORT_H_SIZE 24 /* In-cluster basic payload message */ +#define BASIC_H_SIZE 32 /* Basic payload message */ +#define NAMED_H_SIZE 40 /* Named payload message */ +#define MCAST_H_SIZE 44 /* Multicast payload message */ #define INT_H_SIZE 40 /* Internal messages */ #define MIN_H_SIZE 24 /* Smallest legal TIPC header size */ #define MAX_H_SIZE 60 /* Largest possible TIPC header size */ @@ -325,26 +311,6 @@ static inline void msg_set_seqno(struct tipc_msg *m, u32 n) } /* - * TIPC may utilize the "link ack #" and "link seq #" fields of a short - * message header to hold the destination node for the message, since the - * normal "dest node" field isn't present. This cache is only referenced - * when required, so populating the cache of a longer message header is - * harmless (as long as the header has the two link sequence fields present). - * - * Note: Host byte order is OK here, since the info never goes off-card. - */ - -static inline u32 msg_destnode_cache(struct tipc_msg *m) -{ - return m->hdr[2]; -} - -static inline void msg_set_destnode_cache(struct tipc_msg *m, u32 dnode) -{ - m->hdr[2] = dnode; -} - -/* * Words 3-10 */ @@ -391,7 +357,7 @@ static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p) static inline int msg_short(struct tipc_msg *m) { - return msg_hdr_sz(m) == 24; + return msg_hdr_sz(m) == SHORT_H_SIZE; } static inline u32 msg_orignode(struct tipc_msg *m) @@ -473,40 +439,11 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) /* - TIPC internal message header format, version 2 - - 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w0:|vers |msg usr|hdr sz |n|resrv| packet size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w1:|m typ| sequence gap | broadcast ack no | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w2:| link level ack no/bc_gap_from | seq no / bcast_gap_to | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w3:| previous node | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w4:| next sent broadcast/fragm no | next sent pkt/ fragm msg no | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w5:| session no |rsv=0|r|berid|link prio|netpl|p| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w6:| originating node | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w7:| destination node | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w8:| transport sequence number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w9:| msg count / bcast tag | link tolerance | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - \ \ - / User Specific Data / - \ \ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - NB: CONN_MANAGER use data message format. LINK_CONFIG has own format. -*/ + * Constants and routines used to read and write TIPC internal message headers + */ /* - * Internal users + * Internal message users */ #define BCAST_PROTOCOL 5 @@ -520,7 +457,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) #define LINK_CONFIG 13 /* - * Connection management protocol messages + * Connection management protocol message types */ #define CONN_PROBE 0 @@ -528,12 +465,41 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) #define CONN_ACK 2 /* - * Name distributor messages + * Name distributor message types */ #define PUBLICATION 0 #define WITHDRAWAL 1 +/* + * Segmentation message types + */ + +#define FIRST_FRAGMENT 0 +#define FRAGMENT 1 +#define LAST_FRAGMENT 2 + +/* + * Link management protocol message types + */ + +#define STATE_MSG 0 +#define RESET_MSG 1 +#define ACTIVATE_MSG 2 + +/* + * Changeover tunnel message types + */ +#define DUPLICATE_MSG 0 +#define ORIGINAL_MSG 1 + +/* + * Config protocol message types + */ + +#define DSC_REQ_MSG 0 +#define DSC_RESP_MSG 1 + /* * Word 1 @@ -649,7 +615,7 @@ static inline u32 msg_link_selector(struct tipc_msg *m) static inline void msg_set_link_selector(struct tipc_msg *m, u32 n) { - msg_set_bits(m, 4, 0, 1, (n & 1)); + msg_set_bits(m, 4, 0, 1, n); } /* @@ -673,7 +639,7 @@ static inline u32 msg_probe(struct tipc_msg *m) static inline void msg_set_probe(struct tipc_msg *m, u32 val) { - msg_set_bits(m, 5, 0, 1, (val & 1)); + msg_set_bits(m, 5, 0, 1, val); } static inline char msg_net_plane(struct tipc_msg *m) @@ -761,50 +727,11 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) msg_set_bits(m, 9, 0, 0xffff, n); } -/* - * Segmentation message types - */ - -#define FIRST_FRAGMENT 0 -#define FRAGMENT 1 -#define LAST_FRAGMENT 2 - -/* - * Link management protocol message types - */ - -#define STATE_MSG 0 -#define RESET_MSG 1 -#define ACTIVATE_MSG 2 - -/* - * Changeover tunnel message types - */ -#define DUPLICATE_MSG 0 -#define ORIGINAL_MSG 1 - -/* - * Routing table message types - */ -#define EXT_ROUTING_TABLE 0 -#define LOCAL_ROUTING_TABLE 1 /* obsoleted */ -#define SLAVE_ROUTING_TABLE 2 -#define ROUTE_ADDITION 3 -#define ROUTE_REMOVAL 4 - -/* - * Config protocol message types - */ - -#define DSC_REQ_MSG 0 -#define DSC_RESP_MSG 1 - u32 tipc_msg_tot_importance(struct tipc_msg *m); void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); -int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect); -int tipc_msg_build(struct tipc_msg *hdr, - struct iovec const *msg_sect, u32 num_sect, +int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, + u32 num_sect, unsigned int total_len, int max_size, int usrmem, struct sk_buff **buf); static inline void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a) diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 80025a1b3bf..cd356e50433 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -94,13 +94,13 @@ static void publ_to_item(struct distr_item *i, struct publication *p) static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest) { - struct sk_buff *buf = tipc_buf_acquire(LONG_H_SIZE + size); + struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE + size); struct tipc_msg *msg; if (buf != NULL) { msg = buf_msg(buf); - tipc_msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest); - msg_set_size(msg, LONG_H_SIZE + size); + tipc_msg_init(msg, NAME_DISTRIBUTOR, type, INT_H_SIZE, dest); + msg_set_size(msg, INT_H_SIZE + size); } return buf; } diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 205ed4a4e18..46e6b6c2ecc 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -2,7 +2,7 @@ * net/tipc/name_table.c: TIPC name table code * * Copyright (c) 2000-2006, Ericsson AB - * Copyright (c) 2004-2008, Wind River Systems + * Copyright (c) 2004-2008, 2010-2011, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,9 +44,7 @@ static int tipc_nametbl_size = 1024; /* must be a power of 2 */ /** - * struct sub_seq - container for all published instances of a name sequence - * @lower: name sequence lower bound - * @upper: name sequence upper bound + * struct name_info - name sequence publication info * @node_list: circular list of publications made by own node * @cluster_list: circular list of publications made by own cluster * @zone_list: circular list of publications made by own zone @@ -59,18 +57,29 @@ static int tipc_nametbl_size = 1024; /* must be a power of 2 */ * (The cluster and node lists may be empty.) */ -struct sub_seq { - u32 lower; - u32 upper; - struct publication *node_list; - struct publication *cluster_list; - struct publication *zone_list; +struct name_info { + struct list_head node_list; + struct list_head cluster_list; + struct list_head zone_list; u32 node_list_size; u32 cluster_list_size; u32 zone_list_size; }; /** + * struct sub_seq - container for all published instances of a name sequence + * @lower: name sequence lower bound + * @upper: name sequence upper bound + * @info: pointer to name sequence publication info + */ + +struct sub_seq { + u32 lower; + u32 upper; + struct name_info *info; +}; + +/** * struct name_seq - container for all published instances of a name type * @type: 32 bit 'type' value for name sequence * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type'; @@ -246,6 +255,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, struct subscription *st; struct publication *publ; struct sub_seq *sseq; + struct name_info *info; int created_subseq = 0; sseq = nameseq_find_subseq(nseq, lower); @@ -258,6 +268,8 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, type, lower, upper); return NULL; } + + info = sseq->info; } else { u32 inspos; struct sub_seq *freesseq; @@ -292,6 +304,17 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, nseq->alloc *= 2; } + info = kzalloc(sizeof(*info), GFP_ATOMIC); + if (!info) { + warn("Cannot publish {%u,%u,%u}, no memory\n", + type, lower, upper); + return NULL; + } + + INIT_LIST_HEAD(&info->node_list); + INIT_LIST_HEAD(&info->cluster_list); + INIT_LIST_HEAD(&info->zone_list); + /* Insert new sub-sequence */ sseq = &nseq->sseqs[inspos]; @@ -301,6 +324,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, nseq->first_free++; sseq->lower = lower; sseq->upper = upper; + sseq->info = info; created_subseq = 1; } @@ -310,33 +334,17 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, if (!publ) return NULL; - sseq->zone_list_size++; - if (!sseq->zone_list) - sseq->zone_list = publ->zone_list_next = publ; - else { - publ->zone_list_next = sseq->zone_list->zone_list_next; - sseq->zone_list->zone_list_next = publ; - } + list_add(&publ->zone_list, &info->zone_list); + info->zone_list_size++; if (in_own_cluster(node)) { - sseq->cluster_list_size++; - if (!sseq->cluster_list) - sseq->cluster_list = publ->cluster_list_next = publ; - else { - publ->cluster_list_next = - sseq->cluster_list->cluster_list_next; - sseq->cluster_list->cluster_list_next = publ; - } + list_add(&publ->cluster_list, &info->cluster_list); + info->cluster_list_size++; } if (node == tipc_own_addr) { - sseq->node_list_size++; - if (!sseq->node_list) - sseq->node_list = publ->node_list_next = publ; - else { - publ->node_list_next = sseq->node_list->node_list_next; - sseq->node_list->node_list_next = publ; - } + list_add(&publ->node_list, &info->node_list); + info->node_list_size++; } /* @@ -370,9 +378,8 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i u32 node, u32 ref, u32 key) { struct publication *publ; - struct publication *curr; - struct publication *prev; struct sub_seq *sseq = nameseq_find_subseq(nseq, inst); + struct name_info *info; struct sub_seq *free; struct subscription *s, *st; int removed_subseq = 0; @@ -380,96 +387,41 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i if (!sseq) return NULL; - /* Remove publication from zone scope list */ + info = sseq->info; - prev = sseq->zone_list; - publ = sseq->zone_list->zone_list_next; - while ((publ->key != key) || (publ->ref != ref) || - (publ->node && (publ->node != node))) { - prev = publ; - publ = publ->zone_list_next; - if (prev == sseq->zone_list) { + /* Locate publication, if it exists */ - /* Prevent endless loop if publication not found */ - - return NULL; - } - } - if (publ != sseq->zone_list) - prev->zone_list_next = publ->zone_list_next; - else if (publ->zone_list_next != publ) { - prev->zone_list_next = publ->zone_list_next; - sseq->zone_list = publ->zone_list_next; - } else { - sseq->zone_list = NULL; + list_for_each_entry(publ, &info->zone_list, zone_list) { + if ((publ->key == key) && (publ->ref == ref) && + (!publ->node || (publ->node == node))) + goto found; } - sseq->zone_list_size--; + return NULL; + +found: + /* Remove publication from zone scope list */ + + list_del(&publ->zone_list); + info->zone_list_size--; /* Remove publication from cluster scope list, if present */ if (in_own_cluster(node)) { - prev = sseq->cluster_list; - curr = sseq->cluster_list->cluster_list_next; - while (curr != publ) { - prev = curr; - curr = curr->cluster_list_next; - if (prev == sseq->cluster_list) { - - /* Prevent endless loop for malformed list */ - - err("Unable to de-list cluster publication\n" - "{%u%u}, node=0x%x, ref=%u, key=%u)\n", - publ->type, publ->lower, publ->node, - publ->ref, publ->key); - goto end_cluster; - } - } - if (publ != sseq->cluster_list) - prev->cluster_list_next = publ->cluster_list_next; - else if (publ->cluster_list_next != publ) { - prev->cluster_list_next = publ->cluster_list_next; - sseq->cluster_list = publ->cluster_list_next; - } else { - sseq->cluster_list = NULL; - } - sseq->cluster_list_size--; + list_del(&publ->cluster_list); + info->cluster_list_size--; } -end_cluster: /* Remove publication from node scope list, if present */ if (node == tipc_own_addr) { - prev = sseq->node_list; - curr = sseq->node_list->node_list_next; - while (curr != publ) { - prev = curr; - curr = curr->node_list_next; - if (prev == sseq->node_list) { - - /* Prevent endless loop for malformed list */ - - err("Unable to de-list node publication\n" - "{%u%u}, node=0x%x, ref=%u, key=%u)\n", - publ->type, publ->lower, publ->node, - publ->ref, publ->key); - goto end_node; - } - } - if (publ != sseq->node_list) - prev->node_list_next = publ->node_list_next; - else if (publ->node_list_next != publ) { - prev->node_list_next = publ->node_list_next; - sseq->node_list = publ->node_list_next; - } else { - sseq->node_list = NULL; - } - sseq->node_list_size--; + list_del(&publ->node_list); + info->node_list_size--; } -end_node: /* Contract subseq list if no more publications for that subseq */ - if (!sseq->zone_list) { + if (list_empty(&info->zone_list)) { + kfree(info); free = &nseq->sseqs[nseq->first_free--]; memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof(*sseq)); removed_subseq = 1; @@ -506,12 +458,12 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq, struct subscription *s return; while (sseq != &nseq->sseqs[nseq->first_free]) { - struct publication *zl = sseq->zone_list; - if (zl && tipc_subscr_overlap(s, sseq->lower, sseq->upper)) { - struct publication *crs = zl; + if (tipc_subscr_overlap(s, sseq->lower, sseq->upper)) { + struct publication *crs; + struct name_info *info = sseq->info; int must_report = 1; - do { + list_for_each_entry(crs, &info->zone_list, zone_list) { tipc_subscr_report_overlap(s, sseq->lower, sseq->upper, @@ -520,8 +472,7 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq, struct subscription *s crs->node, must_report); must_report = 0; - crs = crs->zone_list_next; - } while (crs != zl); + } } sseq++; } @@ -591,9 +542,10 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) { struct sub_seq *sseq; - struct publication *publ = NULL; + struct name_info *info; + struct publication *publ; struct name_seq *seq; - u32 ref; + u32 ref = 0; if (!tipc_in_scope(*destnode, tipc_own_addr)) return 0; @@ -606,55 +558,57 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) if (unlikely(!sseq)) goto not_found; spin_lock_bh(&seq->lock); + info = sseq->info; /* Closest-First Algorithm: */ if (likely(!*destnode)) { - publ = sseq->node_list; - if (publ) { - sseq->node_list = publ->node_list_next; -found: - ref = publ->ref; - *destnode = publ->node; - spin_unlock_bh(&seq->lock); - read_unlock_bh(&tipc_nametbl_lock); - return ref; - } - publ = sseq->cluster_list; - if (publ) { - sseq->cluster_list = publ->cluster_list_next; - goto found; - } - publ = sseq->zone_list; - if (publ) { - sseq->zone_list = publ->zone_list_next; - goto found; + if (!list_empty(&info->node_list)) { + publ = list_first_entry(&info->node_list, + struct publication, + node_list); + list_move_tail(&publ->node_list, + &info->node_list); + } else if (!list_empty(&info->cluster_list)) { + publ = list_first_entry(&info->cluster_list, + struct publication, + cluster_list); + list_move_tail(&publ->cluster_list, + &info->cluster_list); + } else { + publ = list_first_entry(&info->zone_list, + struct publication, + zone_list); + list_move_tail(&publ->zone_list, + &info->zone_list); } } /* Round-Robin Algorithm: */ else if (*destnode == tipc_own_addr) { - publ = sseq->node_list; - if (publ) { - sseq->node_list = publ->node_list_next; - goto found; - } + if (list_empty(&info->node_list)) + goto no_match; + publ = list_first_entry(&info->node_list, struct publication, + node_list); + list_move_tail(&publ->node_list, &info->node_list); } else if (in_own_cluster(*destnode)) { - publ = sseq->cluster_list; - if (publ) { - sseq->cluster_list = publ->cluster_list_next; - goto found; - } + if (list_empty(&info->cluster_list)) + goto no_match; + publ = list_first_entry(&info->cluster_list, struct publication, + cluster_list); + list_move_tail(&publ->cluster_list, &info->cluster_list); } else { - publ = sseq->zone_list; - if (publ) { - sseq->zone_list = publ->zone_list_next; - goto found; - } + publ = list_first_entry(&info->zone_list, struct publication, + zone_list); + list_move_tail(&publ->zone_list, &info->zone_list); } + + ref = publ->ref; + *destnode = publ->node; +no_match: spin_unlock_bh(&seq->lock); not_found: read_unlock_bh(&tipc_nametbl_lock); - return 0; + return ref; } /** @@ -676,6 +630,7 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, struct name_seq *seq; struct sub_seq *sseq; struct sub_seq *sseq_stop; + struct name_info *info; int res = 0; read_lock_bh(&tipc_nametbl_lock); @@ -693,16 +648,13 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, if (sseq->lower > upper) break; - publ = sseq->node_list; - if (publ) { - do { - if (publ->scope <= limit) - tipc_port_list_add(dports, publ->ref); - publ = publ->node_list_next; - } while (publ != sseq->node_list); + info = sseq->info; + list_for_each_entry(publ, &info->node_list, node_list) { + if (publ->scope <= limit) + tipc_port_list_add(dports, publ->ref); } - if (sseq->cluster_list_size != sseq->node_list_size) + if (info->cluster_list_size != info->node_list_size) res = 1; } @@ -840,16 +792,19 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth, { char portIdStr[27]; const char *scope_str[] = {"", " zone", " cluster", " node"}; - struct publication *publ = sseq->zone_list; + struct publication *publ; + struct name_info *info; tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper); - if (depth == 2 || !publ) { + if (depth == 2) { tipc_printf(buf, "\n"); return; } - do { + info = sseq->info; + + list_for_each_entry(publ, &info->zone_list, zone_list) { sprintf(portIdStr, "<%u.%u.%u:%u>", tipc_zone(publ->node), tipc_cluster(publ->node), tipc_node(publ->node), publ->ref); @@ -858,13 +813,9 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth, tipc_printf(buf, "%-10u %s", publ->key, scope_str[publ->scope]); } - - publ = publ->zone_list_next; - if (publ == sseq->zone_list) - break; - - tipc_printf(buf, "\n%33s", " "); - } while (1); + if (!list_is_last(&publ->zone_list, &info->zone_list)) + tipc_printf(buf, "\n%33s", " "); + }; tipc_printf(buf, "\n"); } diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index d228bd68265..62d77e5e902 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h @@ -2,7 +2,7 @@ * net/tipc/name_table.h: Include file for TIPC name table code * * Copyright (c) 2000-2006, Ericsson AB - * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2004-2005, 2010-2011, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,9 +61,9 @@ struct port_list; * @subscr: subscription to "node down" event (for off-node publications only) * @local_list: adjacent entries in list of publications made by this node * @pport_list: adjacent entries in list of publications made by this port - * @node_list: next matching name seq publication with >= node scope - * @cluster_list: next matching name seq publication with >= cluster scope - * @zone_list: next matching name seq publication with >= zone scope + * @node_list: adjacent matching name seq publications with >= node scope + * @cluster_list: adjacent matching name seq publications with >= cluster scope + * @zone_list: adjacent matching name seq publications with >= zone scope * * Note that the node list, cluster list, and zone list are circular lists. */ @@ -79,9 +79,9 @@ struct publication { struct tipc_node_subscr subscr; struct list_head local_list; struct list_head pport_list; - struct publication *node_list_next; - struct publication *cluster_list_next; - struct publication *zone_list_next; + struct list_head node_list; + struct list_head cluster_list; + struct list_head zone_list; }; diff --git a/net/tipc/port.c b/net/tipc/port.c index 6ff78f9c7d6..54d812a5a4d 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -74,7 +74,8 @@ static u32 port_peerport(struct tipc_port *p_ptr) */ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, - u32 num_sect, struct iovec const *msg_sect) + u32 num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_msg *hdr; struct sk_buff *buf; @@ -91,11 +92,14 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, hdr = &oport->phdr; msg_set_type(hdr, TIPC_MCAST_MSG); + msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE); + msg_set_destport(hdr, 0); + msg_set_destnode(hdr, 0); msg_set_nametype(hdr, seq->type); msg_set_namelower(hdr, seq->lower); msg_set_nameupper(hdr, seq->upper); msg_set_hdr_sz(hdr, MCAST_H_SIZE); - res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE, + res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, !oport->user_port, &buf); if (unlikely(!buf)) return res; @@ -161,6 +165,7 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp) /* Deliver a copy of message to each destination port */ if (dp->count != 0) { + msg_set_destnode(msg, tipc_own_addr); if (dp->count == 1) { msg_set_destport(msg, dp->ports[0]); tipc_port_recv_msg(buf); @@ -217,7 +222,7 @@ struct tipc_port *tipc_createport_raw(void *usr_handle, p_ptr->max_pkt = MAX_PKT_DEFAULT; p_ptr->ref = ref; msg = &p_ptr->phdr; - tipc_msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0); + tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0); msg_set_origport(msg, ref); INIT_LIST_HEAD(&p_ptr->wait_list); INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); @@ -322,26 +327,23 @@ int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable) } /* - * port_build_proto_msg(): build a port level protocol - * or a connection abortion message. Called with - * tipc_port lock on. + * port_build_proto_msg(): create connection protocol message for port + * + * On entry the port must be locked and connected. */ -static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode, - u32 origport, u32 orignode, - u32 usr, u32 type, u32 err, - u32 ack) +static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, + u32 type, u32 ack) { struct sk_buff *buf; struct tipc_msg *msg; - buf = tipc_buf_acquire(LONG_H_SIZE); + buf = tipc_buf_acquire(INT_H_SIZE); if (buf) { msg = buf_msg(buf); - tipc_msg_init(msg, usr, type, LONG_H_SIZE, destnode); - msg_set_errcode(msg, err); - msg_set_destport(msg, destport); - msg_set_origport(msg, origport); - msg_set_orignode(msg, orignode); + tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE, + port_peernode(p_ptr)); + msg_set_destport(msg, port_peerport(p_ptr)); + msg_set_origport(msg, p_ptr->ref); msg_set_msgcnt(msg, ack); } return buf; @@ -353,45 +355,48 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) struct sk_buff *rbuf; struct tipc_msg *rmsg; int hdr_sz; - u32 imp = msg_importance(msg); + u32 imp; u32 data_sz = msg_data_sz(msg); - - if (data_sz > MAX_REJECT_SIZE) - data_sz = MAX_REJECT_SIZE; - if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE)) - imp++; + u32 src_node; + u32 rmsg_sz; /* discard rejected message if it shouldn't be returned to sender */ - if (msg_errcode(msg) || msg_dest_droppable(msg)) { - buf_discard(buf); - return data_sz; - } - /* construct rejected message */ - if (msg_mcast(msg)) - hdr_sz = MCAST_H_SIZE; - else - hdr_sz = LONG_H_SIZE; - rbuf = tipc_buf_acquire(data_sz + hdr_sz); - if (rbuf == NULL) { - buf_discard(buf); - return data_sz; + if (WARN(!msg_isdata(msg), + "attempt to reject message with user=%u", msg_user(msg))) { + dump_stack(); + goto exit; } + if (msg_errcode(msg) || msg_dest_droppable(msg)) + goto exit; + + /* + * construct returned message by copying rejected message header and + * data (or subset), then updating header fields that need adjusting + */ + + hdr_sz = msg_hdr_sz(msg); + rmsg_sz = hdr_sz + min_t(u32, data_sz, MAX_REJECT_SIZE); + + rbuf = tipc_buf_acquire(rmsg_sz); + if (rbuf == NULL) + goto exit; + rmsg = buf_msg(rbuf); - tipc_msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg)); - msg_set_errcode(rmsg, err); - msg_set_destport(rmsg, msg_origport(msg)); - msg_set_origport(rmsg, msg_destport(msg)); - if (msg_short(msg)) { - msg_set_orignode(rmsg, tipc_own_addr); - /* leave name type & instance as zeroes */ - } else { - msg_set_orignode(rmsg, msg_destnode(msg)); - msg_set_nametype(rmsg, msg_nametype(msg)); - msg_set_nameinst(rmsg, msg_nameinst(msg)); + skb_copy_to_linear_data(rbuf, msg, rmsg_sz); + + if (msg_connected(rmsg)) { + imp = msg_importance(rmsg); + if (imp < TIPC_CRITICAL_IMPORTANCE) + msg_set_importance(rmsg, ++imp); } - msg_set_size(rmsg, data_sz + hdr_sz); - skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz); + msg_set_non_seq(rmsg, 0); + msg_set_size(rmsg, rmsg_sz); + msg_set_errcode(rmsg, err); + msg_set_prevnode(rmsg, tipc_own_addr); + msg_swap_words(rmsg, 4, 5); + if (!msg_short(rmsg)) + msg_swap_words(rmsg, 6, 7); /* send self-abort message when rejecting on a connected port */ if (msg_connected(msg)) { @@ -406,20 +411,26 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) tipc_net_route_msg(abuf); } - /* send rejected message */ + /* send returned message & dispose of rejected message */ + + src_node = msg_prevnode(msg); + if (src_node == tipc_own_addr) + tipc_port_recv_msg(rbuf); + else + tipc_link_send(rbuf, src_node, msg_link_selector(rmsg)); +exit: buf_discard(buf); - tipc_net_route_msg(rbuf); return data_sz; } int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, struct iovec const *msg_sect, u32 num_sect, - int err) + unsigned int total_len, int err) { struct sk_buff *buf; int res; - res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE, + res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, !p_ptr->user_port, &buf); if (!buf) return res; @@ -444,14 +455,7 @@ static void port_timeout(unsigned long ref) if (p_ptr->probing_state == PROBING) { buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); } else { - buf = port_build_proto_msg(port_peerport(p_ptr), - port_peernode(p_ptr), - p_ptr->ref, - tipc_own_addr, - CONN_MANAGER, - CONN_PROBE, - TIPC_OK, - 0); + buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); p_ptr->probing_state = PROBING; k_start_timer(&p_ptr->timer, p_ptr->probing_interval); } @@ -475,100 +479,94 @@ static void port_handle_node_down(unsigned long ref) static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err) { - u32 imp = msg_importance(&p_ptr->phdr); + struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err); - if (!p_ptr->connected) - return NULL; - if (imp < TIPC_CRITICAL_IMPORTANCE) - imp++; - return port_build_proto_msg(p_ptr->ref, - tipc_own_addr, - port_peerport(p_ptr), - port_peernode(p_ptr), - imp, - TIPC_CONN_MSG, - err, - 0); + if (buf) { + struct tipc_msg *msg = buf_msg(buf); + msg_swap_words(msg, 4, 5); + msg_swap_words(msg, 6, 7); + } + return buf; } static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err) { - u32 imp = msg_importance(&p_ptr->phdr); + struct sk_buff *buf; + struct tipc_msg *msg; + u32 imp; if (!p_ptr->connected) return NULL; - if (imp < TIPC_CRITICAL_IMPORTANCE) - imp++; - return port_build_proto_msg(port_peerport(p_ptr), - port_peernode(p_ptr), - p_ptr->ref, - tipc_own_addr, - imp, - TIPC_CONN_MSG, - err, - 0); + + buf = tipc_buf_acquire(BASIC_H_SIZE); + if (buf) { + msg = buf_msg(buf); + memcpy(msg, &p_ptr->phdr, BASIC_H_SIZE); + msg_set_hdr_sz(msg, BASIC_H_SIZE); + msg_set_size(msg, BASIC_H_SIZE); + imp = msg_importance(msg); + if (imp < TIPC_CRITICAL_IMPORTANCE) + msg_set_importance(msg, ++imp); + msg_set_errcode(msg, err); + } + return buf; } void tipc_port_recv_proto_msg(struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); - struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg)); - u32 err = TIPC_OK; + struct tipc_port *p_ptr; struct sk_buff *r_buf = NULL; - struct sk_buff *abort_buf = NULL; - - if (!p_ptr) { - err = TIPC_ERR_NO_PORT; - } else if (p_ptr->connected) { - if ((port_peernode(p_ptr) != msg_orignode(msg)) || - (port_peerport(p_ptr) != msg_origport(msg))) { - err = TIPC_ERR_NO_PORT; - } else if (msg_type(msg) == CONN_ACK) { - int wakeup = tipc_port_congested(p_ptr) && - p_ptr->congested && - p_ptr->wakeup; - p_ptr->acked += msg_msgcnt(msg); - if (tipc_port_congested(p_ptr)) - goto exit; - p_ptr->congested = 0; - if (!wakeup) - goto exit; - p_ptr->wakeup(p_ptr); - goto exit; + u32 orignode = msg_orignode(msg); + u32 origport = msg_origport(msg); + u32 destport = msg_destport(msg); + int wakeable; + + /* Validate connection */ + + p_ptr = tipc_port_lock(destport); + if (!p_ptr || !p_ptr->connected || + (port_peernode(p_ptr) != orignode) || + (port_peerport(p_ptr) != origport)) { + r_buf = tipc_buf_acquire(BASIC_H_SIZE); + if (r_buf) { + msg = buf_msg(r_buf); + tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG, + BASIC_H_SIZE, orignode); + msg_set_errcode(msg, TIPC_ERR_NO_PORT); + msg_set_origport(msg, destport); + msg_set_destport(msg, origport); } - } else if (p_ptr->published) { - err = TIPC_ERR_NO_PORT; - } - if (err) { - r_buf = port_build_proto_msg(msg_origport(msg), - msg_orignode(msg), - msg_destport(msg), - tipc_own_addr, - TIPC_HIGH_IMPORTANCE, - TIPC_CONN_MSG, - err, - 0); + if (p_ptr) + tipc_port_unlock(p_ptr); goto exit; } - /* All is fine */ - if (msg_type(msg) == CONN_PROBE) { - r_buf = port_build_proto_msg(msg_origport(msg), - msg_orignode(msg), - msg_destport(msg), - tipc_own_addr, - CONN_MANAGER, - CONN_PROBE_REPLY, - TIPC_OK, - 0); + /* Process protocol message sent by peer */ + + switch (msg_type(msg)) { + case CONN_ACK: + wakeable = tipc_port_congested(p_ptr) && p_ptr->congested && + p_ptr->wakeup; + p_ptr->acked += msg_msgcnt(msg); + if (!tipc_port_congested(p_ptr)) { + p_ptr->congested = 0; + if (wakeable) + p_ptr->wakeup(p_ptr); + } + break; + case CONN_PROBE: + r_buf = port_build_proto_msg(p_ptr, CONN_PROBE_REPLY, 0); + break; + default: + /* CONN_PROBE_REPLY or unrecognized - no action required */ + break; } p_ptr->probing_state = CONFIRMED; + tipc_port_unlock(p_ptr); exit: - if (p_ptr) - tipc_port_unlock(p_ptr); tipc_net_route_msg(r_buf); - tipc_net_route_msg(abort_buf); buf_discard(buf); } @@ -884,14 +882,7 @@ void tipc_acknowledge(u32 ref, u32 ack) return; if (p_ptr->connected) { p_ptr->conn_unacked -= ack; - buf = port_build_proto_msg(port_peerport(p_ptr), - port_peernode(p_ptr), - ref, - tipc_own_addr, - CONN_MANAGER, - CONN_ACK, - TIPC_OK, - ack); + buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); } tipc_port_unlock(p_ptr); tipc_net_route_msg(buf); @@ -1065,6 +1056,7 @@ int tipc_connect2port(u32 ref, struct tipc_portid const *peer) msg_set_orignode(msg, tipc_own_addr); msg_set_origport(msg, p_ptr->ref); msg_set_type(msg, TIPC_CONN_MSG); + msg_set_lookup_scope(msg, 0); msg_set_hdr_sz(msg, SHORT_H_SIZE); p_ptr->probing_interval = PROBING_INTERVAL; @@ -1134,19 +1126,7 @@ int tipc_shutdown(u32 ref) if (!p_ptr) return -EINVAL; - if (p_ptr->connected) { - u32 imp = msg_importance(&p_ptr->phdr); - if (imp < TIPC_CRITICAL_IMPORTANCE) - imp++; - buf = port_build_proto_msg(port_peerport(p_ptr), - port_peernode(p_ptr), - ref, - tipc_own_addr, - imp, - TIPC_CONN_MSG, - TIPC_CONN_SHUTDOWN, - 0); - } + buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); tipc_port_unlock(p_ptr); tipc_net_route_msg(buf); return tipc_disconnect(ref); @@ -1158,12 +1138,13 @@ int tipc_shutdown(u32 ref) */ static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_sect, - struct iovec const *msg_sect) + struct iovec const *msg_sect, + unsigned int total_len) { struct sk_buff *buf; int res; - res = tipc_msg_build(&sender->phdr, msg_sect, num_sect, + res = tipc_msg_build(&sender->phdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, !sender->user_port, &buf); if (likely(buf)) tipc_port_recv_msg(buf); @@ -1174,7 +1155,8 @@ static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_se * tipc_send - send message sections on connection */ -int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) +int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_port *p_ptr; u32 destnode; @@ -1189,9 +1171,10 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) destnode = port_peernode(p_ptr); if (likely(destnode != tipc_own_addr)) res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect, - destnode); + total_len, destnode); else - res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect); + res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect, + total_len); if (likely(res != -ELINKCONG)) { p_ptr->congested = 0; @@ -1202,8 +1185,7 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) } if (port_unreliable(p_ptr)) { p_ptr->congested = 0; - /* Just calculate msg length and return */ - return tipc_msg_calc_data_size(msg_sect, num_sect); + return total_len; } return -ELINKCONG; } @@ -1213,7 +1195,8 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) */ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, - unsigned int num_sect, struct iovec const *msg_sect) + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_port *p_ptr; struct tipc_msg *msg; @@ -1229,7 +1212,7 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, msg_set_type(msg, TIPC_NAMED_MSG); msg_set_orignode(msg, tipc_own_addr); msg_set_origport(msg, ref); - msg_set_hdr_sz(msg, LONG_H_SIZE); + msg_set_hdr_sz(msg, NAMED_H_SIZE); msg_set_nametype(msg, name->type); msg_set_nameinst(msg, name->instance); msg_set_lookup_scope(msg, tipc_addr_scope(domain)); @@ -1240,23 +1223,23 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, if (likely(destport)) { if (likely(destnode == tipc_own_addr)) res = tipc_port_recv_sections(p_ptr, num_sect, - msg_sect); + msg_sect, total_len); else res = tipc_link_send_sections_fast(p_ptr, msg_sect, - num_sect, destnode); + num_sect, total_len, + destnode); if (likely(res != -ELINKCONG)) { if (res > 0) p_ptr->sent++; return res; } if (port_unreliable(p_ptr)) { - /* Just calculate msg length and return */ - return tipc_msg_calc_data_size(msg_sect, num_sect); + return total_len; } return -ELINKCONG; } return tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect, - TIPC_ERR_NO_NAME); + total_len, TIPC_ERR_NO_NAME); } /** @@ -1264,7 +1247,8 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, */ int tipc_send2port(u32 ref, struct tipc_portid const *dest, - unsigned int num_sect, struct iovec const *msg_sect) + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_port *p_ptr; struct tipc_msg *msg; @@ -1276,25 +1260,26 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest, msg = &p_ptr->phdr; msg_set_type(msg, TIPC_DIRECT_MSG); + msg_set_lookup_scope(msg, 0); msg_set_orignode(msg, tipc_own_addr); msg_set_origport(msg, ref); msg_set_destnode(msg, dest->node); msg_set_destport(msg, dest->ref); - msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); + msg_set_hdr_sz(msg, BASIC_H_SIZE); if (dest->node == tipc_own_addr) - res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect); + res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect, + total_len); else res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect, - dest->node); + total_len, dest->node); if (likely(res != -ELINKCONG)) { if (res > 0) p_ptr->sent++; return res; } if (port_unreliable(p_ptr)) { - /* Just calculate msg length and return */ - return tipc_msg_calc_data_size(msg_sect, num_sect); + return total_len; } return -ELINKCONG; } @@ -1320,13 +1305,13 @@ int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest, msg_set_origport(msg, ref); msg_set_destnode(msg, dest->node); msg_set_destport(msg, dest->ref); - msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); - msg_set_size(msg, DIR_MSG_H_SIZE + dsz); - if (skb_cow(buf, DIR_MSG_H_SIZE)) + msg_set_hdr_sz(msg, BASIC_H_SIZE); + msg_set_size(msg, BASIC_H_SIZE + dsz); + if (skb_cow(buf, BASIC_H_SIZE)) return -ENOMEM; - skb_push(buf, DIR_MSG_H_SIZE); - skb_copy_to_linear_data(buf, msg, DIR_MSG_H_SIZE); + skb_push(buf, BASIC_H_SIZE); + skb_copy_to_linear_data(buf, msg, BASIC_H_SIZE); if (dest->node == tipc_own_addr) res = tipc_port_recv_msg(buf); diff --git a/net/tipc/port.h b/net/tipc/port.h index 87b9424ae0e..b9aa34195ae 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -205,23 +205,27 @@ int tipc_disconnect_port(struct tipc_port *tp_ptr); /* * TIPC messaging routines */ -int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect); +int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len); int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain, - unsigned int num_sect, struct iovec const *msg_sect); + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len); int tipc_send2port(u32 portref, struct tipc_portid const *dest, - unsigned int num_sect, struct iovec const *msg_sect); + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len); int tipc_send_buf2port(u32 portref, struct tipc_portid const *dest, struct sk_buff *buf, unsigned int dsz); int tipc_multicast(u32 portref, struct tipc_name_seq const *seq, - unsigned int section_count, struct iovec const *msg); + unsigned int section_count, struct iovec const *msg, + unsigned int total_len); int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, struct iovec const *msg_sect, u32 num_sect, - int err); + unsigned int total_len, int err); struct sk_buff *tipc_port_get_ports(void); void tipc_port_recv_proto_msg(struct sk_buff *buf); void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 29d94d53198..adb2eff4a10 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -36,9 +36,6 @@ #include <net/sock.h> -#include <linux/tipc.h> -#include <linux/tipc_config.h> - #include "core.h" #include "port.h" @@ -535,6 +532,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, if (unlikely((m->msg_namelen < sizeof(*dest)) || (dest->family != AF_TIPC))) return -EINVAL; + if ((total_len > TIPC_MAX_USER_MSG_SIZE) || + (m->msg_iovlen > (unsigned)INT_MAX)) + return -EMSGSIZE; if (iocb) lock_sock(sk); @@ -573,12 +573,14 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, &dest->addr.name.name, dest->addr.name.domain, m->msg_iovlen, - m->msg_iov); + m->msg_iov, + total_len); } else if (dest->addrtype == TIPC_ADDR_ID) { res = tipc_send2port(tport->ref, &dest->addr.id, m->msg_iovlen, - m->msg_iov); + m->msg_iov, + total_len); } else if (dest->addrtype == TIPC_ADDR_MCAST) { if (needs_conn) { res = -EOPNOTSUPP; @@ -590,7 +592,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, res = tipc_multicast(tport->ref, &dest->addr.nameseq, m->msg_iovlen, - m->msg_iov); + m->msg_iov, + total_len); } if (likely(res != -ELINKCONG)) { if (needs_conn && (res >= 0)) @@ -640,6 +643,10 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, if (unlikely(dest)) return send_msg(iocb, sock, m, total_len); + if ((total_len > TIPC_MAX_USER_MSG_SIZE) || + (m->msg_iovlen > (unsigned)INT_MAX)) + return -EMSGSIZE; + if (iocb) lock_sock(sk); @@ -652,7 +659,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, break; } - res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov); + res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov, + total_len); if (likely(res != -ELINKCONG)) break; if (m->msg_flags & MSG_DONTWAIT) { @@ -723,6 +731,12 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, goto exit; } + if ((total_len > (unsigned)INT_MAX) || + (m->msg_iovlen > (unsigned)INT_MAX)) { + res = -EMSGSIZE; + goto exit; + } + /* * Send each iovec entry using one or more messages * @@ -753,7 +767,7 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, bytes_to_send = curr_left; my_iov.iov_base = curr_start; my_iov.iov_len = bytes_to_send; - res = send_packet(NULL, sock, &my_msg, 0); + res = send_packet(NULL, sock, &my_msg, bytes_to_send); if (res < 0) { if (bytes_sent) res = bytes_sent; diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index aae9eae1340..6cf72686348 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -109,7 +109,7 @@ static void subscr_send_event(struct subscription *sub, sub->evt.found_upper = htohl(found_upper, sub->swap); sub->evt.port.ref = htohl(port_ref, sub->swap); sub->evt.port.node = htohl(node, sub->swap); - tipc_send(sub->server_ref, 1, &msg_sect); + tipc_send(sub->server_ref, 1, &msg_sect, msg_sect.iov_len); } /** @@ -521,7 +521,7 @@ static void subscr_named_msg_event(void *usr_handle, /* Send an ACK- to complete connection handshaking */ - tipc_send(server_port_ref, 0, NULL); + tipc_send(server_port_ref, 0, NULL, 0); /* Handle optional subscription request */ |