Commit 61a46dc9 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (42 commits)
  [IOAT]: Do not dereference THIS_MODULE directly to set unsafe.
  [NETROM]: Fix possible null pointer dereference.
  [NET] netpoll: break recursive loop in netpoll rx path
  [NET] netpoll: don't spin forever sending to stopped queues
  [IRDA]: add some IBM think pads
  [ATM]: atm/mpc.c warning fix
  [NET]: skb_find_text ignores to argument
  [NET]: make net/core/dev.c:netdev_nit static
  [NET]: Fix GSO problems in dev_hard_start_xmit()
  [NET]: Fix CHECKSUM_HW GSO problems.
  [TIPC]: Fix incorrect correction to discovery timer frequency computation.
  [TIPC]: Get rid of dynamically allocated arrays in broadcast code.
  [TIPC]: Fixed link switchover bugs
  [TIPC]: Enhanced & cleaned up system messages; fixed 2 obscure memory leaks.
  [TIPC]: First phase of assert() cleanup
  [TIPC]: Disallow config operations that aren't supported in certain modes.
  [TIPC]: Fixed memory leak in tipc_link_send() when destination is unreachable
  [TIPC]: Added missing warning for out-of-memory condition
  [TIPC]: Withdrawing all names from nameless port now returns success, not error
  [TIPC]: Optimized argument validation done by connect().
  ...
parents b78709cf 8070b2b1
...@@ -824,10 +824,9 @@ static int __init ioat_init_module(void) ...@@ -824,10 +824,9 @@ static int __init ioat_init_module(void)
{ {
/* it's currently unsafe to unload this module */ /* it's currently unsafe to unload this module */
/* if forced, worst case is that rmmod hangs */ /* if forced, worst case is that rmmod hangs */
if (THIS_MODULE != NULL) __unsafe(THIS_MODULE);
THIS_MODULE->unsafe = 1;
return pci_module_init(&ioat_pci_drv); pci_module_init(&ioat_pci_drv);
} }
module_init(ioat_init_module); module_init(ioat_init_module);
......
...@@ -115,8 +115,12 @@ static nsc_chip_t chips[] = { ...@@ -115,8 +115,12 @@ static nsc_chip_t chips[] = {
/* Contributed by Jan Frey - IBM A30/A31 */ /* Contributed by Jan Frey - IBM A30/A31 */
{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x }, nsc_ircc_probe_39x, nsc_ircc_init_39x },
{ "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, /* IBM ThinkPads using PC8738x (T60/X60/Z60) */
nsc_ircc_probe_39x, nsc_ircc_init_39x }, { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x },
/* IBM ThinkPads using PC8394T (T43/R52/?) */
{ "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x },
{ NULL } { NULL }
}; };
......
...@@ -699,7 +699,6 @@ extern int dev_hard_start_xmit(struct sk_buff *skb, ...@@ -699,7 +699,6 @@ extern int dev_hard_start_xmit(struct sk_buff *skb,
extern void dev_init(void); extern void dev_init(void);
extern int netdev_nit;
extern int netdev_budget; extern int netdev_budget;
/* Called by rtnetlink.c:rtnl_unlock() */ /* Called by rtnetlink.c:rtnl_unlock() */
......
...@@ -31,6 +31,7 @@ struct netpoll_info { ...@@ -31,6 +31,7 @@ struct netpoll_info {
int rx_flags; int rx_flags;
spinlock_t rx_lock; spinlock_t rx_lock;
struct netpoll *rx_np; /* netpoll that registered an rx_hook */ struct netpoll *rx_np; /* netpoll that registered an rx_hook */
struct sk_buff_head arp_tx; /* list of arp requests to reply to */
}; };
void netpoll_poll(struct netpoll *np); void netpoll_poll(struct netpoll *np);
......
...@@ -49,10 +49,18 @@ ...@@ -49,10 +49,18 @@
#define TIPC_MEDIA_TYPE_ETH 1 #define TIPC_MEDIA_TYPE_ETH 1
/*
* Destination address structure used by TIPC bearers when sending messages
*
* IMPORTANT: The fields of this structure MUST be stored using the specified
* byte order indicated below, as the structure is exchanged between nodes
* as part of a link setup process.
*/
struct tipc_media_addr { struct tipc_media_addr {
__u32 type; __u32 type; /* bearer type (network byte order) */
union { union {
__u8 eth_addr[6]; /* Ethernet bearer */ __u8 eth_addr[6]; /* 48 bit Ethernet addr (byte array) */
#if 0 #if 0
/* Prototypes for other possible bearer types */ /* Prototypes for other possible bearer types */
......
...@@ -1113,10 +1113,9 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien ...@@ -1113,10 +1113,9 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien
static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
{ {
unsigned char *ip;
uint32_t dst_ip = msg->content.in_info.in_dst_ip; uint32_t dst_ip = msg->content.in_info.in_dst_ip;
in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc);
dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip)); dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip));
ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry); ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry);
if(entry == NULL){ if(entry == NULL){
......
...@@ -230,7 +230,7 @@ extern void netdev_unregister_sysfs(struct net_device *); ...@@ -230,7 +230,7 @@ extern void netdev_unregister_sysfs(struct net_device *);
* For efficiency * For efficiency
*/ */
int netdev_nit; static int netdev_nit;
/* /*
* Add a protocol ID to the list. Now that the input handler is * Add a protocol ID to the list. Now that the input handler is
...@@ -1325,9 +1325,12 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1325,9 +1325,12 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
nskb->next = NULL; nskb->next = NULL;
rc = dev->hard_start_xmit(nskb, dev); rc = dev->hard_start_xmit(nskb, dev);
if (unlikely(rc)) { if (unlikely(rc)) {
nskb->next = skb->next;
skb->next = nskb; skb->next = nskb;
return rc; return rc;
} }
if (unlikely(netif_queue_stopped(dev) && skb->next))
return NETDEV_TX_BUSY;
} while (skb->next); } while (skb->next);
skb->destructor = DEV_GSO_CB(skb)->destructor; skb->destructor = DEV_GSO_CB(skb)->destructor;
......
...@@ -54,6 +54,7 @@ static atomic_t trapped; ...@@ -54,6 +54,7 @@ static atomic_t trapped;
sizeof(struct iphdr) + sizeof(struct ethhdr)) sizeof(struct iphdr) + sizeof(struct ethhdr))
static void zap_completion_queue(void); static void zap_completion_queue(void);
static void arp_reply(struct sk_buff *skb);
static void queue_process(void *p) static void queue_process(void *p)
{ {
...@@ -153,6 +154,22 @@ static void poll_napi(struct netpoll *np) ...@@ -153,6 +154,22 @@ static void poll_napi(struct netpoll *np)
} }
} }
static void service_arp_queue(struct netpoll_info *npi)
{
struct sk_buff *skb;
if (unlikely(!npi))
return;
skb = skb_dequeue(&npi->arp_tx);
while (skb != NULL) {
arp_reply(skb);
skb = skb_dequeue(&npi->arp_tx);
}
return;
}
void netpoll_poll(struct netpoll *np) void netpoll_poll(struct netpoll *np)
{ {
if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller) if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller)
...@@ -163,6 +180,8 @@ void netpoll_poll(struct netpoll *np) ...@@ -163,6 +180,8 @@ void netpoll_poll(struct netpoll *np)
if (np->dev->poll) if (np->dev->poll)
poll_napi(np); poll_napi(np);
service_arp_queue(np->dev->npinfo);
zap_completion_queue(); zap_completion_queue();
} }
...@@ -279,14 +298,10 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) ...@@ -279,14 +298,10 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
* network drivers do not expect to be called if the queue is * network drivers do not expect to be called if the queue is
* stopped. * stopped.
*/ */
if (netif_queue_stopped(np->dev)) { status = NETDEV_TX_BUSY;
netif_tx_unlock(np->dev); if (!netif_queue_stopped(np->dev))
netpoll_poll(np); status = np->dev->hard_start_xmit(skb, np->dev);
udelay(50);
continue;
}
status = np->dev->hard_start_xmit(skb, np->dev);
netif_tx_unlock(np->dev); netif_tx_unlock(np->dev);
/* success */ /* success */
...@@ -446,7 +461,9 @@ int __netpoll_rx(struct sk_buff *skb) ...@@ -446,7 +461,9 @@ int __netpoll_rx(struct sk_buff *skb)
int proto, len, ulen; int proto, len, ulen;
struct iphdr *iph; struct iphdr *iph;
struct udphdr *uh; struct udphdr *uh;
struct netpoll *np = skb->dev->npinfo->rx_np; struct netpoll_info *npi = skb->dev->npinfo;
struct netpoll *np = npi->rx_np;
if (!np) if (!np)
goto out; goto out;
...@@ -456,7 +473,7 @@ int __netpoll_rx(struct sk_buff *skb) ...@@ -456,7 +473,7 @@ int __netpoll_rx(struct sk_buff *skb)
/* check if netpoll clients need ARP */ /* check if netpoll clients need ARP */
if (skb->protocol == __constant_htons(ETH_P_ARP) && if (skb->protocol == __constant_htons(ETH_P_ARP) &&
atomic_read(&trapped)) { atomic_read(&trapped)) {
arp_reply(skb); skb_queue_tail(&npi->arp_tx, skb);
return 1; return 1;
} }
...@@ -651,6 +668,7 @@ int netpoll_setup(struct netpoll *np) ...@@ -651,6 +668,7 @@ int netpoll_setup(struct netpoll *np)
npinfo->poll_owner = -1; npinfo->poll_owner = -1;
npinfo->tries = MAX_RETRIES; npinfo->tries = MAX_RETRIES;
spin_lock_init(&npinfo->rx_lock); spin_lock_init(&npinfo->rx_lock);
skb_queue_head_init(&npinfo->arp_tx);
} else } else
npinfo = ndev->npinfo; npinfo = ndev->npinfo;
......
...@@ -1739,12 +1739,15 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, ...@@ -1739,12 +1739,15 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
unsigned int to, struct ts_config *config, unsigned int to, struct ts_config *config,
struct ts_state *state) struct ts_state *state)
{ {
unsigned int ret;
config->get_next_block = skb_ts_get_next_block; config->get_next_block = skb_ts_get_next_block;
config->finish = skb_ts_finish; config->finish = skb_ts_finish;
skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state)); skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state));
return textsearch_find(config, state); ret = textsearch_find(config, state);
return (ret <= to - from ? ret : UINT_MAX);
} }
/** /**
......
...@@ -2166,7 +2166,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) ...@@ -2166,7 +2166,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
if (!pskb_may_pull(skb, thlen)) if (!pskb_may_pull(skb, thlen))
goto out; goto out;
oldlen = ~htonl(skb->len); oldlen = (u16)~skb->len;
__skb_pull(skb, thlen); __skb_pull(skb, thlen);
segs = skb_segment(skb, sg); segs = skb_segment(skb, sg);
...@@ -2174,7 +2174,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) ...@@ -2174,7 +2174,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
goto out; goto out;
len = skb_shinfo(skb)->gso_size; len = skb_shinfo(skb)->gso_size;
delta = csum_add(oldlen, htonl(thlen + len)); delta = htonl(oldlen + (thlen + len));
skb = segs; skb = segs;
th = skb->h.th; th = skb->h.th;
...@@ -2183,10 +2183,10 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) ...@@ -2183,10 +2183,10 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
do { do {
th->fin = th->psh = 0; th->fin = th->psh = 0;
if (skb->ip_summed == CHECKSUM_NONE) { th->check = ~csum_fold(th->check + delta);
th->check = csum_fold(csum_partial( if (skb->ip_summed != CHECKSUM_HW)
skb->h.raw, thlen, csum_add(skb->csum, delta))); th->check = csum_fold(csum_partial(skb->h.raw, thlen,
} skb->csum));
seq += len; seq += len;
skb = skb->next; skb = skb->next;
...@@ -2196,11 +2196,11 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) ...@@ -2196,11 +2196,11 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
th->cwr = 0; th->cwr = 0;
} while (skb->next); } while (skb->next);
if (skb->ip_summed == CHECKSUM_NONE) { delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw)); th->check = ~csum_fold(th->check + delta);
th->check = csum_fold(csum_partial( if (skb->ip_summed != CHECKSUM_HW)
skb->h.raw, thlen, csum_add(skb->csum, delta))); th->check = csum_fold(csum_partial(skb->h.raw, thlen,
} skb->csum));
out: out:
return segs; return segs;
......
...@@ -725,15 +725,17 @@ void nr_link_failed(ax25_cb *ax25, int reason) ...@@ -725,15 +725,17 @@ void nr_link_failed(ax25_cb *ax25, int reason)
struct nr_node *nr_node = NULL; struct nr_node *nr_node = NULL;
spin_lock_bh(&nr_neigh_list_lock); spin_lock_bh(&nr_neigh_list_lock);
nr_neigh_for_each(s, node, &nr_neigh_list) nr_neigh_for_each(s, node, &nr_neigh_list) {
if (s->ax25 == ax25) { if (s->ax25 == ax25) {
nr_neigh_hold(s); nr_neigh_hold(s);
nr_neigh = s; nr_neigh = s;
break; break;
} }
}
spin_unlock_bh(&nr_neigh_list_lock); spin_unlock_bh(&nr_neigh_list_lock);
if (nr_neigh == NULL) return; if (nr_neigh == NULL)
return;
nr_neigh->ax25 = NULL; nr_neigh->ax25 = NULL;
ax25_cb_put(ax25); ax25_cb_put(ax25);
...@@ -743,11 +745,13 @@ void nr_link_failed(ax25_cb *ax25, int reason) ...@@ -743,11 +745,13 @@ void nr_link_failed(ax25_cb *ax25, int reason)
return; return;
} }
spin_lock_bh(&nr_node_list_lock); spin_lock_bh(&nr_node_list_lock);
nr_node_for_each(nr_node, node, &nr_node_list) nr_node_for_each(nr_node, node, &nr_node_list) {
nr_node_lock(nr_node); nr_node_lock(nr_node);
if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh) if (nr_node->which < nr_node->count &&
nr_node->routes[nr_node->which].neighbour == nr_neigh)
nr_node->which++; nr_node->which++;
nr_node_unlock(nr_node); nr_node_unlock(nr_node);
}
spin_unlock_bh(&nr_node_list_lock); spin_unlock_bh(&nr_node_list_lock);
nr_neigh_put(nr_neigh); nr_neigh_put(nr_neigh);
} }
......
...@@ -49,13 +49,19 @@ ...@@ -49,13 +49,19 @@
#include "name_table.h" #include "name_table.h"
#include "bcast.h" #include "bcast.h"
#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */ #define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
#define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */ #define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */
#define BCLINK_LOG_BUF_SIZE 0 #define BCLINK_LOG_BUF_SIZE 0
/*
* 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 * struct bcbearer_pair - a pair of bearers used by broadcast link
* @primary: pointer to primary bearer * @primary: pointer to primary bearer
...@@ -75,7 +81,14 @@ struct bcbearer_pair { ...@@ -75,7 +81,14 @@ struct bcbearer_pair {
* @bearer: (non-standard) broadcast bearer structure * @bearer: (non-standard) broadcast bearer structure
* @media: (non-standard) broadcast media structure * @media: (non-standard) broadcast media structure
* @bpairs: array of bearer pairs * @bpairs: array of bearer pairs
* @bpairs_temp: array of bearer pairs used during creation of "bpairs" * @bpairs_temp: temporary array of bearer pairs used by tipc_bcbearer_sort()
* @remains: temporary node map used by tipc_bcbearer_send()
* @remains_new: temporary node map used tipc_bcbearer_send()
*
* Note: The fields labelled "temporary" are incorporated into the bearer
* to avoid consuming potentially limited stack space through the use of
* large local variables within multicast routines. Concurrent access is
* prevented through use of the spinlock "bc_lock".
*/ */
struct bcbearer { struct bcbearer {
...@@ -83,6 +96,8 @@ struct bcbearer { ...@@ -83,6 +96,8 @@ struct bcbearer {
struct media media; struct media media;
struct bcbearer_pair bpairs[MAX_BEARERS]; struct bcbearer_pair bpairs[MAX_BEARERS];
struct bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1]; struct bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
struct node_map remains;
struct node_map remains_new;
}; };
/** /**
...@@ -165,21 +180,18 @@ static int bclink_ack_allowed(u32 n) ...@@ -165,21 +180,18 @@ static int bclink_ack_allowed(u32 n)
* @after: sequence number of last packet to *not* retransmit * @after: sequence number of last packet to *not* retransmit
* @to: sequence number of last packet to retransmit * @to: sequence number of last packet to retransmit
* *
* Called with 'node' locked, bc_lock unlocked * Called with bc_lock locked
*/ */
static void bclink_retransmit_pkt(u32 after, u32 to) static void bclink_retransmit_pkt(u32 after, u32 to)
{ {
struct sk_buff *buf; struct sk_buff *buf;
spin_lock_bh(&bc_lock);
buf = bcl->first_out; buf = bcl->first_out;
while (buf && less_eq(buf_seqno(buf), after)) { while (buf && less_eq(buf_seqno(buf), after)) {
buf = buf->next; buf = buf->next;
} }
if (buf != NULL) tipc_link_retransmit(bcl, buf, mod(to - after));
tipc_link_retransmit(bcl, buf, mod(to - after));
spin_unlock_bh(&bc_lock);
} }
/** /**
...@@ -346,8 +358,10 @@ static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 g ...@@ -346,8 +358,10 @@ static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 g
for (; buf; buf = buf->next) { for (; buf; buf = buf->next) {
u32 seqno = buf_seqno(buf); u32 seqno = buf_seqno(buf);
if (mod(seqno - prev) != 1) if (mod(seqno - prev) != 1) {
buf = NULL; buf = NULL;
break;
}
if (seqno == gap_after) if (seqno == gap_after)
break; break;
prev = seqno; prev = seqno;
...@@ -399,7 +413,10 @@ int tipc_bclink_send_msg(struct sk_buff *buf) ...@@ -399,7 +413,10 @@ int tipc_bclink_send_msg(struct sk_buff *buf)
*/ */
void tipc_bclink_recv_pkt(struct sk_buff *buf) void tipc_bclink_recv_pkt(struct sk_buff *buf)
{ {
#if (TIPC_BCAST_LOSS_RATE)
static int rx_count = 0;
#endif
struct tipc_msg *msg = buf_msg(buf); struct tipc_msg *msg = buf_msg(buf);
struct node* node = tipc_node_find(msg_prevnode(msg)); struct node* node = tipc_node_find(msg_prevnode(msg));
u32 next_in; u32 next_in;
...@@ -420,9 +437,13 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) ...@@ -420,9 +437,13 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
tipc_node_lock(node); tipc_node_lock(node);
tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
tipc_node_unlock(node); tipc_node_unlock(node);
spin_lock_bh(&bc_lock);
bcl->stats.recv_nacks++; bcl->stats.recv_nacks++;
bcl->owner->next = node; /* remember requestor */
bclink_retransmit_pkt(msg_bcgap_after(msg), bclink_retransmit_pkt(msg_bcgap_after(msg),
msg_bcgap_to(msg)); msg_bcgap_to(msg));
bcl->owner->next = NULL;
spin_unlock_bh(&bc_lock);
} else { } else {
tipc_bclink_peek_nack(msg_destnode(msg), tipc_bclink_peek_nack(msg_destnode(msg),
msg_bcast_tag(msg), msg_bcast_tag(msg),
...@@ -433,6 +454,14 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) ...@@ -433,6 +454,14 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
return; 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); tipc_node_lock(node);
receive: receive:
deferred = node->bclink.deferred_head; deferred = node->bclink.deferred_head;
...@@ -531,12 +560,8 @@ static int tipc_bcbearer_send(struct sk_buff *buf, ...@@ -531,12 +560,8 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
{ {
static int send_count = 0; static int send_count = 0;
struct node_map *remains;
struct node_map *remains_new;
struct node_map *remains_tmp;
int bp_index; int bp_index;
int swap_time; int swap_time;
int err;
/* Prepare buffer for broadcasting (if first time trying to send it) */ /* Prepare buffer for broadcasting (if first time trying to send it) */
...@@ -557,9 +582,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, ...@@ -557,9 +582,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
/* Send buffer over bearers until all targets reached */ /* Send buffer over bearers until all targets reached */
remains = kmalloc(sizeof(struct node_map), GFP_ATOMIC); bcbearer->remains = tipc_cltr_bcast_nodes;
remains_new = kmalloc(sizeof(struct node_map), GFP_ATOMIC);
*remains = tipc_cltr_bcast_nodes;
for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
struct bearer *p = bcbearer->bpairs[bp_index].primary; struct bearer *p = bcbearer->bpairs[bp_index].primary;
...@@ -568,8 +591,8 @@ static int tipc_bcbearer_send(struct sk_buff *buf, ...@@ -568,8 +591,8 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
if (!p) if (!p)
break; /* no more bearers to try */ break; /* no more bearers to try */
tipc_nmap_diff(remains, &p->nodes, remains_new); tipc_nmap_diff(&bcbearer->remains, &p->nodes, &bcbearer->remains_new);
if (remains_new->count == remains->count) if (bcbearer->remains_new.count == bcbearer->remains.count)
continue; /* bearer pair doesn't add anything */ continue; /* bearer pair doesn't add anything */
if (!p->publ.blocked && if (!p->publ.blocked &&
...@@ -587,27 +610,17 @@ static int tipc_bcbearer_send(struct sk_buff *buf, ...@@ -587,27 +610,17 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
bcbearer->bpairs[bp_index].primary = s; bcbearer->bpairs[bp_index].primary = s;
bcbearer->bpairs[bp_index].secondary = p; bcbearer->bpairs[bp_index].secondary = p;
update: update:
if (remains_new->count == 0) { if (bcbearer->remains_new.count == 0)
err = TIPC_OK; return TIPC_OK;
goto out;
}
/* swap map */ bcbearer->remains = bcbearer->remains_new;
remains_tmp = remains;
remains = remains_new;
remains_new = remains_tmp;
} }
/* Unable to reach all targets */ /* Unable to reach all targets */
bcbearer->bearer.publ.blocked = 1; bcbearer->bearer.publ.blocked = 1;
bcl->stats.bearer_congs++; bcl->stats.bearer_congs++;
err = ~TIPC_OK; return ~TIPC_OK;
out:
kfree(remains_new);
kfree(remains);
return err;
} }
/** /**
...@@ -765,7 +778,7 @@ int tipc_bclink_init(void) ...@@ -765,7 +778,7 @@ int tipc_bclink_init(void)
bclink = kmalloc(sizeof(*bclink), GFP_ATOMIC); bclink = kmalloc(sizeof(*bclink), GFP_ATOMIC);
if (!bcbearer || !bclink) { if (!bcbearer || !bclink) {
nomem: nomem:
warn("Memory squeeze; Failed to create multicast link\n"); warn("Multicast link creation failed, no memory\n");
kfree(bcbearer); kfree(bcbearer);
bcbearer = NULL; bcbearer = NULL;
kfree(bclink); kfree(bclink);
......
...@@ -180,7 +180,7 @@ static inline void tipc_port_list_add(struct port_list *pl_ptr, u32 port) ...@@ -180,7 +180,7 @@ static inline void tipc_port_list_add(struct port_list *pl_ptr, u32 port)
if (!item->next) { if (!item->next) {
item->next = kmalloc(sizeof(*item), GFP_ATOMIC); item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
if (!item->next) { if (!item->next) {
warn("Memory squeeze: multicast destination port list is incomplete\n"); warn("Incomplete multicast delivery, no memory\n");
return; return;
} }
item->next->next = NULL; item->next->next = NULL;
......
...@@ -112,39 +112,42 @@ int tipc_register_media(u32 media_type, ...@@ -112,39 +112,42 @@ int tipc_register_media(u32 media_type,
goto exit; goto exit;
if (!media_name_valid(name)) { if (!media_name_valid(name)) {
warn("Media registration error: illegal name <%s>\n", name); warn("Media <%s> rejected, illegal name\n", name);
goto exit; goto exit;
} }
if (!bcast_addr) { if (!bcast_addr) {
warn("Media registration error: no broadcast address supplied\n"); warn("Media <%s> rejected, no broadcast address\n", name);
goto exit; goto exit;
} }
if ((bearer_priority < TIPC_MIN_LINK_PRI) && if ((bearer_priority < TIPC_MIN_LINK_PRI) &&
(bearer_priority > TIPC_MAX_LINK_PRI)) { (bearer_priority > TIPC_MAX_LINK_PRI)) {
warn("Media registration error: priority %u\n", bearer_priority); warn("Media <%s> rejected, illegal priority (%u)\n", name,
bearer_priority);
goto exit; goto exit;
} }
if ((link_tolerance < TIPC_MIN_LINK_TOL) || if ((link_tolerance < TIPC_MIN_LINK_TOL) ||
(link_tolerance > TIPC_MAX_LINK_TOL)) { (link_tolerance > TIPC_MAX_LINK_TOL)) {
warn("Media registration error: tolerance %u\n", link_tolerance); warn("Media <%s> rejected, illegal tolerance (%u)\n", name,
link_tolerance);
goto exit; goto exit;
} }
media_id = media_count++; media_id = media_count++;
if (media_id >= MAX_MEDIA) { if (media_id >= MAX_MEDIA) {
warn("Attempt to register more than %u media\n", MAX_MEDIA); warn("Media <%s> rejected, media limit reached (%u)\n", name,
MAX_MEDIA);
media_count--; media_count--;
goto exit; goto exit;
} }
for (i = 0; i < media_id; i++) { for (i = 0; i < media_id; i++) {
if (media_list[i].type_id == media_type) { if (media_list[i].type_id == media_type) {
warn("Attempt to register second media with type %u\n", warn("Media <%s> rejected, duplicate type (%u)\n", name,
media_type); media_type);
media_count--; media_count--;
goto exit; goto exit;
} }
if (!strcmp(name, media_list[i].name)) { if (!strcmp(name, media_list[i].name)) {
warn("Attempt to re-register media name <%s>\n", name); warn("Media <%s> rejected, duplicate name\n", name);
media_count--; media_count--;
goto exit; goto exit;
} }
...@@ -283,6 +286,9 @@ static struct bearer *bearer_find(const char *name) ...@@ -283,6 +286,9 @@ static struct bearer *bearer_find(const char *name)
struct bearer *b_ptr; struct bearer *b_ptr;
u32 i; u32 i;
if (tipc_mode != TIPC_NET_MODE)
return NULL;
for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) { for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
if (b_ptr->active && (!strcmp(b_ptr->publ.name, name))) if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
return b_ptr; return b_ptr;
...@@ -475,26 +481,33 @@ int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority) ...@@ -475,26 +481,33 @@ int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
u32 i; u32 i;
int res = -EINVAL; int res = -EINVAL;
if (tipc_mode != TIPC_NET_MODE) if (tipc_mode != TIPC_NET_MODE) {
warn("Bearer <%s> rejected, not supported in standalone mode\n",
name);
return -ENOPROTOOPT; return -ENOPROTOOPT;
}
if (!bearer_name_validate(name, &b_name) || if (!bearer_name_validate(name, &b_name)) {
!tipc_addr_domain_valid(bcast_scope) || warn("Bearer <%s> rejected, illegal name\n", name);
!in_scope(bcast_scope, tipc_own_addr))
return -EINVAL; return -EINVAL;
}
if (!tipc_addr_domain_valid(bcast_scope) ||
!in_scope(bcast_scope, tipc_own_addr)) {
warn("Bearer <%s> rejected, illegal broadcast scope\n", name);
return -EINVAL;
}
if ((priority < TIPC_MIN_LINK_PRI || if ((priority < TIPC_MIN_LINK_PRI ||
priority > TIPC_MAX_LINK_PRI) && priority > TIPC_MAX_LINK_PRI) &&
(priority != TIPC_MEDIA_LINK_PRI)) (priority != TIPC_MEDIA_LINK_PRI)) {
warn("Bearer <%s> rejected, illegal priority\n", name);
return -EINVAL; return -EINVAL;
}
write_lock_bh(&tipc_net_lock); write_lock_bh(&tipc_net_lock);
if (!tipc_bearers)
goto failed;
m_ptr = media_find(b_name.media_name); m_ptr = media_find(b_name.media_name);
if (!m_ptr) { if (!m_ptr) {
warn("No media <%s>\n", b_name.media_name); warn("Bearer <%s> rejected, media <%s> not registered\n", name,
b_name.media_name);
goto failed; goto failed;
} }
...@@ -510,23 +523,24 @@ int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority) ...@@ -510,23 +523,24 @@ int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
continue; continue;
} }
if (!strcmp(name, tipc_bearers[i].publ.name)) { if (!strcmp(name, tipc_bearers[i].publ.name)) {
warn("Bearer <%s> already enabled\n", name); warn("Bearer <%s> rejected, already enabled\n", name);
goto failed; goto failed;
} }
if ((tipc_bearers[i].priority == priority) && if ((tipc_bearers[i].priority == priority) &&
(++with_this_prio > 2)) { (++with_this_prio > 2)) {
if (priority-- == 0) { if (priority-- == 0) {
warn("Third bearer <%s> with priority %u, unable to lower to %u\n", warn("Bearer <%s> rejected, duplicate priority\n",
name, priority + 1, priority); name);
goto failed; goto failed;
} }
warn("Third bearer <%s> with priority %u, lowering to %u\n", warn("Bearer <%s> priority adjustment required %u->%u\n",
name, priority + 1, priority); name, priority + 1, priority);
goto restart; goto restart;
} }
} }
if (bearer_id >= MAX_BEARERS) { if (bearer_id >= MAX_BEARERS) {
warn("Attempt to enable more than %d bearers\n", MAX_BEARERS); warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
name, MAX_BEARERS);
goto failed; goto failed;
} }
...@@ -536,7 +550,7 @@ int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority) ...@@ -536,7 +550,7 @@ int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
strcpy(b_ptr->publ.name, name); strcpy(b_ptr->publ.name, name);
res = m_ptr->enable_bearer(&b_ptr->publ); res = m_ptr->enable_bearer(&b_ptr->publ);
if (res) { if (res) {
warn("Failed to enable bearer <%s>\n", name); warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res);
goto failed; goto failed;
} }
...@@ -573,9 +587,6 @@ int tipc_block_bearer(const char *name) ...@@ -573,9 +587,6 @@ int tipc_block_bearer(const char *name)
struct link *l_ptr; struct link *l_ptr;
struct link *temp_l_ptr; struct link *temp_l_ptr;
if (tipc_mode != TIPC_NET_MODE)
return -ENOPROTOOPT;
read_lock_bh(&tipc_net_lock); read_lock_bh(&tipc_net_lock);
b_ptr = bearer_find(name); b_ptr = bearer_find(name);
if (!b_ptr) { if (!b_ptr) {
...@@ -584,6 +595,7 @@ int tipc_block_bearer(const char *name) ...@@ -584,6 +595,7 @@ int tipc_block_bearer(const char *name)
return -EINVAL; return -EINVAL;
} }
info("Blocking bearer <%s>\n", name);
spin_lock_bh(&b_ptr->publ.lock); spin_lock_bh(&b_ptr->publ.lock);
b_ptr->publ.blocked = 1; b_ptr->publ.blocked = 1;
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
...@@ -595,7 +607,6 @@ int tipc_block_bearer(const char *name) ...@@ -595,7 +607,6 @@ int tipc_block_bearer(const char *name)
} }
spin_unlock_bh(&b_ptr->publ.lock); spin_unlock_bh(&b_ptr->publ.lock);
read_unlock_bh(&tipc_net_lock); read_unlock_bh(&tipc_net_lock);
info("Blocked bearer <%s>\n", name);
return TIPC_OK; return TIPC_OK;
} }
...@@ -611,15 +622,13 @@ static int bearer_disable(const char *name) ...@@ -611,15 +622,13 @@ static int bearer_disable(const char *name)
struct link *l_ptr; struct link *l_ptr;
struct link *temp_l_ptr; struct link *temp_l_ptr;
if (tipc_mode != TIPC_NET_MODE)
return -ENOPROTOOPT;
b_ptr = bearer_find(name); b_ptr = bearer_find(name);
if (!b_ptr) { if (!b_ptr) {
warn("Attempt to disable unknown bearer <%s>\n", name); warn("Attempt to disable unknown bearer <%s>\n", name);
return -EINVAL; return -EINVAL;
} }
info("Disabling bearer <%s>\n", name);
tipc_disc_stop_link_req(b_ptr->link_req); tipc_disc_stop_link_req(b_ptr->link_req);
spin_lock_bh(&b_ptr->publ.lock); spin_lock_bh(&b_ptr->publ.lock);
b_ptr->link_req = NULL; b_ptr->link_req = NULL;
...@@ -635,7 +644,6 @@ static int bearer_disable(const char *name) ...@@ -635,7 +644,6 @@ static int bearer_disable(const char *name)
tipc_link_delete(l_ptr); tipc_link_delete(l_ptr);
} }
spin_unlock_bh(&b_ptr->publ.lock); spin_unlock_bh(&b_ptr->publ.lock);
info("Disabled bearer <%s>\n", name);
memset(b_ptr, 0, sizeof(struct bearer)); memset(b_ptr, 0, sizeof(struct bearer));
return TIPC_OK; return TIPC_OK;
} }
......
...@@ -60,8 +60,10 @@ struct cluster *tipc_cltr_create(u32 addr) ...@@ -60,8 +60,10 @@ struct cluster *tipc_cltr_create(u32 addr)
int alloc; int alloc;
c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC); c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC);
if (c_ptr == NULL) if (c_ptr == NULL) {
warn("Cluster creation failure, no memory\n");
return NULL; return NULL;
}
memset(c_ptr, 0, sizeof(*c_ptr)); memset(c_ptr, 0, sizeof(*c_ptr));
c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0); c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
...@@ -70,30 +72,32 @@ struct cluster *tipc_cltr_create(u32 addr) ...@@ -70,30 +72,32 @@ struct cluster *tipc_cltr_create(u32 addr)
else else
max_nodes = tipc_max_nodes + 1; max_nodes = tipc_max_nodes + 1;
alloc = sizeof(void *) * (max_nodes + 1); alloc = sizeof(void *) * (max_nodes + 1);
c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC); c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC);
if (c_ptr->nodes == NULL) { if (c_ptr->nodes == NULL) {
warn("Cluster creation failure, no memory for node area\n");
kfree(c_ptr); kfree(c_ptr);
return NULL; return NULL;
} }
memset(c_ptr->nodes, 0, alloc); memset(c_ptr->nodes, 0, alloc);
if (in_own_cluster(addr)) if (in_own_cluster(addr))
tipc_local_nodes = c_ptr->nodes; tipc_local_nodes = c_ptr->nodes;
c_ptr->highest_slave = LOWEST_SLAVE - 1; c_ptr->highest_slave = LOWEST_SLAVE - 1;
c_ptr->highest_node = 0; c_ptr->highest_node = 0;
z_ptr = tipc_zone_find(tipc_zone(addr)); z_ptr = tipc_zone_find(tipc_zone(addr));
if (z_ptr == NULL) { if (!z_ptr) {
z_ptr = tipc_zone_create(addr); z_ptr = tipc_zone_create(addr);
} }
if (z_ptr != NULL) { if (!z_ptr) {
tipc_zone_attach_cluster(z_ptr, c_ptr); kfree(c_ptr->nodes);
c_ptr->owner = z_ptr;
}
else {
kfree(c_ptr); kfree(c_ptr);
c_ptr = NULL; return NULL;
} }
tipc_zone_attach_cluster(z_ptr, c_ptr);
c_ptr->owner = z_ptr;
return c_ptr; return c_ptr;
} }
......
...@@ -291,13 +291,22 @@ static struct sk_buff *cfg_set_own_addr(void) ...@@ -291,13 +291,22 @@ static struct sk_buff *cfg_set_own_addr(void)
if (!tipc_addr_node_valid(addr)) if (!tipc_addr_node_valid(addr))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (node address)"); " (node address)");
if (tipc_own_addr) if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)"); " (cannot change node address once assigned)");
tipc_own_addr = addr;
/*
* Must release all spinlocks before calling start_net() because
* Linux version of TIPC calls eth_media_start() which calls
* register_netdevice_notifier() which may block!
*
* Temporarily releasing the lock should be harmless for non-Linux TIPC,
* but Linux version of eth_media_start() should really be reworked
* so that it can be called with spinlocks held.
*/
spin_unlock_bh(&config_lock); spin_unlock_bh(&config_lock);
tipc_core_stop_net();
tipc_own_addr = addr;
tipc_core_start_net(); tipc_core_start_net();
spin_lock_bh(&config_lock); spin_lock_bh(&config_lock);
return tipc_cfg_reply_none(); return tipc_cfg_reply_none();
...@@ -350,50 +359,21 @@ static struct sk_buff *cfg_set_max_subscriptions(void) ...@@ -350,50 +359,21 @@ static struct sk_buff *cfg_set_max_subscriptions(void)
static struct sk_buff *cfg_set_max_ports(void) static struct sk_buff *cfg_set_max_ports(void)
{ {
int orig_mode;
u32 value; u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = *(u32 *)TLV_DATA(req_tlv_area); value = *(u32 *)TLV_DATA(req_tlv_area);
value = ntohl(value); value = ntohl(value);
if (value == tipc_max_ports)
return tipc_cfg_reply_none();
if (value != delimit(value, 127, 65535)) if (value != delimit(value, 127, 65535))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max ports must be 127-65535)"); " (max ports must be 127-65535)");
if (tipc_mode != TIPC_NOT_RUNNING)
if (value == tipc_max_ports)
return tipc_cfg_reply_none();
if (atomic_read(&tipc_user_count) > 2)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change max ports while TIPC users exist)"); " (cannot change max ports while TIPC is active)");
spin_unlock_bh(&config_lock);
orig_mode = tipc_get_mode();
if (orig_mode == TIPC_NET_MODE)
tipc_core_stop_net();
tipc_core_stop();
tipc_max_ports = value; tipc_max_ports = value;
tipc_core_start();
if (orig_mode == TIPC_NET_MODE)
tipc_core_start_net();
spin_lock_bh(&config_lock);
return tipc_cfg_reply_none();
}
static struct sk_buff *set_net_max(int value, int *parameter)
{
int orig_mode;
if (value != *parameter) {
orig_mode = tipc_get_mode();
if (orig_mode == TIPC_NET_MODE)
tipc_core_stop_net();
*parameter = value;
if (orig_mode == TIPC_NET_MODE)
tipc_core_start_net();
}
return tipc_cfg_reply_none(); return tipc_cfg_reply_none();
} }
...@@ -405,10 +385,16 @@ static struct sk_buff *cfg_set_max_zones(void) ...@@ -405,10 +385,16 @@ static struct sk_buff *cfg_set_max_zones(void)
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = *(u32 *)TLV_DATA(req_tlv_area); value = *(u32 *)TLV_DATA(req_tlv_area);
value = ntohl(value); value = ntohl(value);
if (value == tipc_max_zones)
return tipc_cfg_reply_none();
if (value != delimit(value, 1, 255)) if (value != delimit(value, 1, 255))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max zones must be 1-255)"); " (max zones must be 1-255)");
return set_net_max(value, &tipc_max_zones); if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change max zones once TIPC has joined a network)");
tipc_max_zones = value;
return tipc_cfg_reply_none();
} }
static struct sk_buff *cfg_set_max_clusters(void) static struct sk_buff *cfg_set_max_clusters(void)
...@@ -419,8 +405,8 @@ static struct sk_buff *cfg_set_max_clusters(void) ...@@ -419,8 +405,8 @@ static struct sk_buff *cfg_set_max_clusters(void)
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = *(u32 *)TLV_DATA(req_tlv_area); value = *(u32 *)TLV_DATA(req_tlv_area);
value = ntohl(value); value = ntohl(value);
if (value != 1) if (value != delimit(value, 1, 1))
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max clusters fixed at 1)"); " (max clusters fixed at 1)");
return tipc_cfg_reply_none(); return tipc_cfg_reply_none();
} }
...@@ -433,10 +419,16 @@ static struct sk_buff *cfg_set_max_nodes(void) ...@@ -433,10 +419,16 @@ static struct sk_buff *cfg_set_max_nodes(void)
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = *(u32 *)TLV_DATA(req_tlv_area); value = *(u32 *)TLV_DATA(req_tlv_area);
value = ntohl(value); value = ntohl(value);
if (value == tipc_max_nodes)
return tipc_cfg_reply_none();
if (value != delimit(value, 8, 2047)) if (value != delimit(value, 8, 2047))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max nodes must be 8-2047)"); " (max nodes must be 8-2047)");
return set_net_max(value, &tipc_max_nodes); if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change max nodes once TIPC has joined a network)");
tipc_max_nodes = value;
return tipc_cfg_reply_none();
} }
static struct sk_buff *cfg_set_max_slaves(void) static struct sk_buff *cfg_set_max_slaves(void)
...@@ -461,15 +453,16 @@ static struct sk_buff *cfg_set_netid(void) ...@@ -461,15 +453,16 @@ static struct sk_buff *cfg_set_netid(void)
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = *(u32 *)TLV_DATA(req_tlv_area); value = *(u32 *)TLV_DATA(req_tlv_area);
value = ntohl(value); value = ntohl(value);
if (value == tipc_net_id)
return tipc_cfg_reply_none();
if (value != delimit(value, 1, 9999)) if (value != delimit(value, 1, 9999))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network id must be 1-9999)"); " (network id must be 1-9999)");
if (tipc_mode == TIPC_NET_MODE)
if (tipc_own_addr)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change network id once part of network)"); " (cannot change network id once TIPC has joined a network)");
tipc_net_id = value;
return set_net_max(value, &tipc_net_id); return tipc_cfg_reply_none();
} }
struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area, struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
...@@ -649,7 +642,7 @@ static void cfg_named_msg_event(void *userdata, ...@@ -649,7 +642,7 @@ static void cfg_named_msg_event(void *userdata,
if ((size < sizeof(*req_hdr)) || if ((size < sizeof(*req_hdr)) ||
(size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) || (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
(ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) { (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
warn("discarded invalid configuration message\n"); warn("Invalid configuration message discarded\n");
return; return;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* net/tipc/core.c: TIPC module code * net/tipc/core.c: TIPC module code
* *
* Copyright (c) 2003-2006, Ericsson AB * Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -57,7 +57,7 @@ void tipc_socket_stop(void); ...@@ -57,7 +57,7 @@ void tipc_socket_stop(void);
int tipc_netlink_start(void); int tipc_netlink_start(void);
void tipc_netlink_stop(void); void tipc_netlink_stop(void);
#define MOD_NAME "tipc_start: " #define TIPC_MOD_VER "1.6.1"
#ifndef CONFIG_TIPC_ZONES #ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3 #define CONFIG_TIPC_ZONES 3
...@@ -198,7 +198,7 @@ static int __init tipc_init(void) ...@@ -198,7 +198,7 @@ static int __init tipc_init(void)
tipc_max_publications = 10000; tipc_max_publications = 10000;
tipc_max_subscriptions = 2000; tipc_max_subscriptions = 2000;
tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536); tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536);
tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 511); tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 255);
tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1); tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1);
tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047); tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047);
tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047); tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047);
...@@ -224,6 +224,7 @@ module_exit(tipc_exit); ...@@ -224,6 +224,7 @@ module_exit(tipc_exit);
MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication"); MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(TIPC_MOD_VER);
/* Native TIPC API for kernel-space applications (see tipc.h) */ /* Native TIPC API for kernel-space applications (see tipc.h) */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* net/tipc/core.h: Include file for TIPC global declarations * net/tipc/core.h: Include file for TIPC global declarations
* *
* Copyright (c) 2005-2006, Ericsson AB * Copyright (c) 2005-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -111,10 +111,6 @@ void tipc_dump(struct print_buf*,const char *fmt, ...); ...@@ -111,10 +111,6 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#else #else
#ifndef DBG_OUTPUT
#define DBG_OUTPUT NULL
#endif
/* /*
* TIPC debug support not included: * TIPC debug support not included:
* - system messages are printed to system console * - system messages are printed to system console
...@@ -129,6 +125,19 @@ void tipc_dump(struct print_buf*,const char *fmt, ...); ...@@ -129,6 +125,19 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#define msg_dbg(msg,txt) do {} while (0) #define msg_dbg(msg,txt) do {} while (0)
#define dump(fmt,arg...) do {} while (0) #define dump(fmt,arg...) do {} while (0)
/*
* TIPC_OUTPUT is defined to be the system console, while DBG_OUTPUT is
* the null print buffer. Thes ensures that any system or debug messages
* that are generated without using the above macros are handled correctly.
*/
#undef TIPC_OUTPUT
#define TIPC_OUTPUT TIPC_CONS
#undef DBG_OUTPUT
#define DBG_OUTPUT NULL
#endif #endif
...@@ -309,7 +318,7 @@ static inline struct sk_buff *buf_acquire(u32 size) ...@@ -309,7 +318,7 @@ static inline struct sk_buff *buf_acquire(u32 size)
* buf_discard - frees a TIPC message buffer * buf_discard - frees a TIPC message buffer
* @skb: message buffer * @skb: message buffer
* *
* Frees a new buffer. If passed NULL, just returns. * Frees a message buffer. If passed NULL, just returns.
*/ */
static inline void buf_discard(struct sk_buff *skb) static inline void buf_discard(struct sk_buff *skb)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* net/tipc/discover.c * net/tipc/discover.c
* *
* Copyright (c) 2003-2006, Ericsson AB * Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -176,7 +176,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf) ...@@ -176,7 +176,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
n_ptr = tipc_node_create(orig); n_ptr = tipc_node_create(orig);
} }
if (n_ptr == NULL) { if (n_ptr == NULL) {
warn("Memory squeeze; Failed to create node\n");
return; return;
} }
spin_lock_bh(&n_ptr->lock); spin_lock_bh(&n_ptr->lock);
...@@ -191,10 +190,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf) ...@@ -191,10 +190,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
} }
addr = &link->media_addr; addr = &link->media_addr;
if (memcmp(addr, &media_addr, sizeof(*addr))) { if (memcmp(addr, &media_addr, sizeof(*addr))) {
char addr_string[16]; warn("Resetting link <%s>, peer interface address changed\n",
link->name);
warn("New bearer address for %s\n",
addr_string_fill(addr_string, orig));
memcpy(addr, &media_addr, sizeof(*addr)); memcpy(addr, &media_addr, sizeof(*addr));
tipc_link_reset(link); tipc_link_reset(link);
} }
...@@ -270,8 +267,8 @@ static void disc_timeout(struct link_req *req) ...@@ -270,8 +267,8 @@ static void disc_timeout(struct link_req *req)
/* leave timer interval "as is" if already at a "normal" rate */ /* leave timer interval "as is" if already at a "normal" rate */
} else { } else {
req->timer_intv *= 2; req->timer_intv *= 2;
if (req->timer_intv > TIPC_LINK_REQ_SLOW) if (req->timer_intv > TIPC_LINK_REQ_FAST)
req->timer_intv = TIPC_LINK_REQ_SLOW; req->timer_intv = TIPC_LINK_REQ_FAST;
if ((req->timer_intv == TIPC_LINK_REQ_FAST) && if ((req->timer_intv == TIPC_LINK_REQ_FAST) &&
(req->bearer->nodes.count)) (req->bearer->nodes.count))
req->timer_intv = TIPC_LINK_REQ_SLOW; req->timer_intv = TIPC_LINK_REQ_SLOW;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* net/tipc/eth_media.c: Ethernet bearer support for TIPC * net/tipc/eth_media.c: Ethernet bearer support for TIPC
* *
* Copyright (c) 2001-2006, Ericsson AB * Copyright (c) 2001-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -98,17 +98,19 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, ...@@ -98,17 +98,19 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
u32 size; u32 size;
if (likely(eb_ptr->bearer)) { if (likely(eb_ptr->bearer)) {
size = msg_size((struct tipc_msg *)buf->data); if (likely(!dev->promiscuity) ||
skb_trim(buf, size); !memcmp(buf->mac.raw,dev->dev_addr,ETH_ALEN) ||
if (likely(buf->len == size)) { !memcmp(buf->mac.raw,dev->broadcast,ETH_ALEN)) {
buf->next = NULL; size = msg_size((struct tipc_msg *)buf->data);
tipc_recv_msg(buf, eb_ptr->bearer); skb_trim(buf, size);
} else { if (likely(buf->len == size)) {
kfree_skb(buf); buf->next = NULL;
tipc_recv_msg(buf, eb_ptr->bearer);
return TIPC_OK;
}
} }
} else {
kfree_skb(buf);
} }
kfree_skb(buf);
return TIPC_OK; return TIPC_OK;
} }
...@@ -125,8 +127,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) ...@@ -125,8 +127,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr)
/* Find device with specified name */ /* Find device with specified name */
while (dev && dev->name && while (dev && dev->name && strncmp(dev->name, driver_name, IFNAMSIZ)) {
(memcmp(dev->name, driver_name, strlen(dev->name)))) {
dev = dev->next; dev = dev->next;
} }
if (!dev) if (!dev)
...@@ -252,7 +253,9 @@ int tipc_eth_media_start(void) ...@@ -252,7 +253,9 @@ int tipc_eth_media_start(void)
if (eth_started) if (eth_started)
return -EINVAL; return -EINVAL;
memset(&bcast_addr, 0xff, sizeof(bcast_addr)); bcast_addr.type = htonl(TIPC_MEDIA_TYPE_ETH);
memset(&bcast_addr.dev_addr, 0xff, ETH_ALEN);
memset(eth_bearers, 0, sizeof(eth_bearers)); memset(eth_bearers, 0, sizeof(eth_bearers));
res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth", res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth",
......
...@@ -419,7 +419,7 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer, ...@@ -419,7 +419,7 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
l_ptr = (struct link *)kmalloc(sizeof(*l_ptr), GFP_ATOMIC); l_ptr = (struct link *)kmalloc(sizeof(*l_ptr), GFP_ATOMIC);
if (!l_ptr) { if (!l_ptr) {
warn("Memory squeeze; Failed to create link\n"); warn("Link creation failed, no memory\n");
return NULL; return NULL;
} }
memset(l_ptr, 0, sizeof(*l_ptr)); memset(l_ptr, 0, sizeof(*l_ptr));
...@@ -469,7 +469,7 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer, ...@@ -469,7 +469,7 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
if (!pb) { if (!pb) {
kfree(l_ptr); kfree(l_ptr);
warn("Memory squeeze; Failed to create link\n"); warn("Link creation failed, no memory for print buffer\n");
return NULL; return NULL;
} }
tipc_printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE); tipc_printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
...@@ -574,7 +574,6 @@ void tipc_link_wakeup_ports(struct link *l_ptr, int all) ...@@ -574,7 +574,6 @@ void tipc_link_wakeup_ports(struct link *l_ptr, int all)
break; break;
list_del_init(&p_ptr->wait_list); list_del_init(&p_ptr->wait_list);
p_ptr->congested_link = NULL; p_ptr->congested_link = NULL;
assert(p_ptr->wakeup);
spin_lock_bh(p_ptr->publ.lock); spin_lock_bh(p_ptr->publ.lock);
p_ptr->publ.congested = 0; p_ptr->publ.congested = 0;
p_ptr->wakeup(&p_ptr->publ); p_ptr->wakeup(&p_ptr->publ);
...@@ -691,6 +690,7 @@ void tipc_link_reset(struct link *l_ptr) ...@@ -691,6 +690,7 @@ void tipc_link_reset(struct link *l_ptr)
struct sk_buff *buf; struct sk_buff *buf;
u32 prev_state = l_ptr->state; u32 prev_state = l_ptr->state;
u32 checkpoint = l_ptr->next_in_no; 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); msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
...@@ -712,7 +712,7 @@ void tipc_link_reset(struct link *l_ptr) ...@@ -712,7 +712,7 @@ void tipc_link_reset(struct link *l_ptr)
tipc_printf(TIPC_CONS, "\nReset link <%s>\n", l_ptr->name); tipc_printf(TIPC_CONS, "\nReset link <%s>\n", l_ptr->name);
dbg_link_dump(); dbg_link_dump();
#endif #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->owner->permit_changeover) {
l_ptr->reset_checkpoint = checkpoint; l_ptr->reset_checkpoint = checkpoint;
l_ptr->exp_msg_count = START_CHANGEOVER; l_ptr->exp_msg_count = START_CHANGEOVER;
...@@ -755,7 +755,7 @@ void tipc_link_reset(struct link *l_ptr) ...@@ -755,7 +755,7 @@ void tipc_link_reset(struct link *l_ptr)
static void link_activate(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_node_link_up(l_ptr->owner, l_ptr);
tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr); tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
link_send_event(tipc_cfg_link_event, l_ptr, 1); link_send_event(tipc_cfg_link_event, l_ptr, 1);
...@@ -820,6 +820,8 @@ static void link_state_event(struct link *l_ptr, unsigned event) ...@@ -820,6 +820,8 @@ static void link_state_event(struct link *l_ptr, unsigned event)
break; break;
case RESET_MSG: case RESET_MSG:
dbg_link("RES -> RR\n"); dbg_link("RES -> RR\n");
info("Resetting link <%s>, requested by peer\n",
l_ptr->name);
tipc_link_reset(l_ptr); tipc_link_reset(l_ptr);
l_ptr->state = RESET_RESET; l_ptr->state = RESET_RESET;
l_ptr->fsm_msg_cnt = 0; l_ptr->fsm_msg_cnt = 0;
...@@ -844,6 +846,8 @@ static void link_state_event(struct link *l_ptr, unsigned event) ...@@ -844,6 +846,8 @@ static void link_state_event(struct link *l_ptr, unsigned event)
break; break;
case RESET_MSG: case RESET_MSG:
dbg_link("RES -> RR\n"); dbg_link("RES -> RR\n");
info("Resetting link <%s>, requested by peer "
"while probing\n", l_ptr->name);
tipc_link_reset(l_ptr); tipc_link_reset(l_ptr);
l_ptr->state = RESET_RESET; l_ptr->state = RESET_RESET;
l_ptr->fsm_msg_cnt = 0; l_ptr->fsm_msg_cnt = 0;
...@@ -875,6 +879,8 @@ static void link_state_event(struct link *l_ptr, unsigned event) ...@@ -875,6 +879,8 @@ static void link_state_event(struct link *l_ptr, unsigned event)
} else { /* Link has failed */ } else { /* Link has failed */
dbg_link("-> RU (%u probes unanswered)\n", dbg_link("-> RU (%u probes unanswered)\n",
l_ptr->fsm_msg_cnt); l_ptr->fsm_msg_cnt);
warn("Resetting link <%s>, peer not responding\n",
l_ptr->name);
tipc_link_reset(l_ptr); tipc_link_reset(l_ptr);
l_ptr->state = RESET_UNKNOWN; l_ptr->state = RESET_UNKNOWN;
l_ptr->fsm_msg_cnt = 0; l_ptr->fsm_msg_cnt = 0;
...@@ -1050,7 +1056,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf) ...@@ -1050,7 +1056,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
msg_dbg(msg, "TIPC: Congestion, throwing away\n"); msg_dbg(msg, "TIPC: Congestion, throwing away\n");
buf_discard(buf); buf_discard(buf);
if (imp > CONN_MANAGER) { 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); tipc_link_reset(l_ptr);
} }
return dsz; return dsz;
...@@ -1135,9 +1141,13 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector) ...@@ -1135,9 +1141,13 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
if (n_ptr) { if (n_ptr) {
tipc_node_lock(n_ptr); tipc_node_lock(n_ptr);
l_ptr = n_ptr->active_links[selector & 1]; 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) { 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); 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); tipc_node_unlock(n_ptr);
} else { } else {
...@@ -1242,8 +1252,6 @@ int tipc_link_send_sections_fast(struct port *sender, ...@@ -1242,8 +1252,6 @@ int tipc_link_send_sections_fast(struct port *sender,
int res; int res;
u32 selector = msg_origport(hdr) & 1; u32 selector = msg_origport(hdr) & 1;
assert(destaddr != tipc_own_addr);
again: again:
/* /*
* Try building message using port's max_pkt hint. * Try building message using port's max_pkt hint.
...@@ -1604,40 +1612,121 @@ void tipc_link_push_queue(struct link *l_ptr) ...@@ -1604,40 +1612,121 @@ void tipc_link_push_queue(struct link *l_ptr)
tipc_bearer_schedule(l_ptr->b_ptr, 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: %u\n", (u32)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, void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
u32 retransmits) u32 retransmits)
{ {
struct tipc_msg *msg; struct tipc_msg *msg;
if (!buf)
return;
msg = buf_msg(buf);
dbg("Retransmitting %u in link %x\n", retransmits, l_ptr); dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr) && buf && !skb_cloned(buf)) { if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
msg_dbg(buf_msg(buf), ">NO_RETR->BCONG>"); if (!skb_cloned(buf)) {
dbg_print_link(l_ptr, " "); msg_dbg(msg, ">NO_RETR->BCONG>");
l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf)); dbg_print_link(l_ptr, " ");
l_ptr->retransm_queue_size = retransmits; l_ptr->retransm_queue_head = msg_seqno(msg);
return; 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)) { while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
msg = buf_msg(buf); msg = buf_msg(buf);
msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { 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>"); msg_dbg(buf_msg(buf), ">RETR>");
buf = buf->next; buf = buf->next;
retransmits--; retransmits--;
...@@ -1650,6 +1739,7 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, ...@@ -1650,6 +1739,7 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
return; return;
} }
} }
l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0; l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
} }
...@@ -1720,6 +1810,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) ...@@ -1720,6 +1810,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
link_recv_non_seq(buf); link_recv_non_seq(buf);
continue; continue;
} }
if (unlikely(!msg_short(msg) &&
(msg_destnode(msg) != tipc_own_addr)))
goto cont;
n_ptr = tipc_node_find(msg_prevnode(msg)); n_ptr = tipc_node_find(msg_prevnode(msg));
if (unlikely(!n_ptr)) if (unlikely(!n_ptr))
goto cont; goto cont;
...@@ -2140,7 +2235,7 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) ...@@ -2140,7 +2235,7 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
if (msg_linkprio(msg) && if (msg_linkprio(msg) &&
(msg_linkprio(msg) != l_ptr->priority)) { (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->name, l_ptr->priority, msg_linkprio(msg));
l_ptr->priority = msg_linkprio(msg); l_ptr->priority = msg_linkprio(msg);
tipc_link_reset(l_ptr); /* Enforce change to take effect */ tipc_link_reset(l_ptr); /* Enforce change to take effect */
...@@ -2209,17 +2304,22 @@ void tipc_link_tunnel(struct link *l_ptr, ...@@ -2209,17 +2304,22 @@ void tipc_link_tunnel(struct link *l_ptr,
u32 length = msg_size(msg); u32 length = msg_size(msg);
tunnel = l_ptr->owner->active_links[selector & 1]; 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; return;
}
msg_set_size(tunnel_hdr, length + INT_H_SIZE); msg_set_size(tunnel_hdr, length + INT_H_SIZE);
buf = buf_acquire(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; return;
}
memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE); memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE);
memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length); memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length);
dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane); dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
msg_dbg(buf_msg(buf), ">SEND>"); msg_dbg(buf_msg(buf), ">SEND>");
assert(tunnel);
tipc_link_send_buf(tunnel, buf); tipc_link_send_buf(tunnel, buf);
} }
...@@ -2235,23 +2335,27 @@ void tipc_link_changeover(struct link *l_ptr) ...@@ -2235,23 +2335,27 @@ void tipc_link_changeover(struct link *l_ptr)
u32 msgcount = l_ptr->out_queue_size; u32 msgcount = l_ptr->out_queue_size;
struct sk_buff *crs = l_ptr->first_out; struct sk_buff *crs = l_ptr->first_out;
struct link *tunnel = l_ptr->owner->active_links[0]; 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; struct tipc_msg tunnel_hdr;
int split_bundles;
if (!tunnel) if (!tunnel)
return; return;
if (!l_ptr->owner->permit_changeover) if (!l_ptr->owner->permit_changeover) {
warn("Link changeover error, "
"peer did not permit changeover\n");
return; return;
}
msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr); ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
msg_set_msgcnt(&tunnel_hdr, msgcount); msg_set_msgcnt(&tunnel_hdr, msgcount);
dbg("Link changeover requires %u tunnel messages\n", msgcount);
if (!l_ptr->first_out) { if (!l_ptr->first_out) {
struct sk_buff *buf; struct sk_buff *buf;
assert(!msgcount);
buf = buf_acquire(INT_H_SIZE); buf = buf_acquire(INT_H_SIZE);
if (buf) { if (buf) {
memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE); memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
...@@ -2261,10 +2365,15 @@ void tipc_link_changeover(struct link *l_ptr) ...@@ -2261,10 +2365,15 @@ void tipc_link_changeover(struct link *l_ptr)
msg_dbg(&tunnel_hdr, "EMPTY>SEND>"); msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
tipc_link_send_buf(tunnel, buf); tipc_link_send_buf(tunnel, buf);
} else { } else {
warn("Memory squeeze; link changeover failed\n"); warn("Link changeover error, "
"unable to send changeover msg\n");
} }
return; return;
} }
split_bundles = (l_ptr->owner->active_links[0] !=
l_ptr->owner->active_links[1]);
while (crs) { while (crs) {
struct tipc_msg *msg = buf_msg(crs); struct tipc_msg *msg = buf_msg(crs);
...@@ -2310,7 +2419,8 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel) ...@@ -2310,7 +2419,8 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
msg_set_size(&tunnel_hdr, length + INT_H_SIZE); msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
outbuf = buf_acquire(length + INT_H_SIZE); outbuf = buf_acquire(length + INT_H_SIZE);
if (outbuf == NULL) { if (outbuf == NULL) {
warn("Memory squeeze; buffer duplication failed\n"); warn("Link changeover error, "
"unable to send duplicate msg\n");
return; return;
} }
memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE); memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
...@@ -2364,11 +2474,15 @@ static int link_recv_changeover_msg(struct link **l_ptr, ...@@ -2364,11 +2474,15 @@ static int link_recv_changeover_msg(struct link **l_ptr,
u32 msg_count = msg_msgcnt(tunnel_msg); u32 msg_count = msg_msgcnt(tunnel_msg);
dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)]; dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
assert(dest_link != *l_ptr);
if (!dest_link) { if (!dest_link) {
msg_dbg(tunnel_msg, "NOLINK/<REC<"); msg_dbg(tunnel_msg, "NOLINK/<REC<");
goto exit; 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, dbg("%c<-%c:", dest_link->b_ptr->net_plane,
(*l_ptr)->b_ptr->net_plane); (*l_ptr)->b_ptr->net_plane);
*l_ptr = dest_link; *l_ptr = dest_link;
...@@ -2381,7 +2495,7 @@ static int link_recv_changeover_msg(struct link **l_ptr, ...@@ -2381,7 +2495,7 @@ static int link_recv_changeover_msg(struct link **l_ptr,
} }
*buf = buf_extract(tunnel_buf,INT_H_SIZE); *buf = buf_extract(tunnel_buf,INT_H_SIZE);
if (*buf == NULL) { if (*buf == NULL) {
warn("Memory squeeze; failed to extract msg\n"); warn("Link changeover error, duplicate msg dropped\n");
goto exit; goto exit;
} }
msg_dbg(tunnel_msg, "TNL<REC<"); msg_dbg(tunnel_msg, "TNL<REC<");
...@@ -2393,13 +2507,17 @@ static int link_recv_changeover_msg(struct link **l_ptr, ...@@ -2393,13 +2507,17 @@ static int link_recv_changeover_msg(struct link **l_ptr,
if (tipc_link_is_up(dest_link)) { if (tipc_link_is_up(dest_link)) {
msg_dbg(tunnel_msg, "UP/FIRST/<REC<"); msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
info("Resetting link <%s>, changeover initiated by peer\n",
dest_link->name);
tipc_link_reset(dest_link); tipc_link_reset(dest_link);
dest_link->exp_msg_count = msg_count; dest_link->exp_msg_count = msg_count;
dbg("Expecting %u tunnelled messages\n", msg_count);
if (!msg_count) if (!msg_count)
goto exit; goto exit;
} else if (dest_link->exp_msg_count == START_CHANGEOVER) { } else if (dest_link->exp_msg_count == START_CHANGEOVER) {
msg_dbg(tunnel_msg, "BLK/FIRST/<REC<"); msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
dest_link->exp_msg_count = msg_count; dest_link->exp_msg_count = msg_count;
dbg("Expecting %u tunnelled messages\n", msg_count);
if (!msg_count) if (!msg_count)
goto exit; goto exit;
} }
...@@ -2407,6 +2525,8 @@ static int link_recv_changeover_msg(struct link **l_ptr, ...@@ -2407,6 +2525,8 @@ static int link_recv_changeover_msg(struct link **l_ptr,
/* Receive original message */ /* Receive original message */
if (dest_link->exp_msg_count == 0) { if (dest_link->exp_msg_count == 0) {
warn("Link switchover error, "
"got too many tunnelled messages\n");
msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<"); msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
dbg_print_link(dest_link, "LINK:"); dbg_print_link(dest_link, "LINK:");
goto exit; goto exit;
...@@ -2422,7 +2542,7 @@ static int link_recv_changeover_msg(struct link **l_ptr, ...@@ -2422,7 +2542,7 @@ static int link_recv_changeover_msg(struct link **l_ptr,
buf_discard(tunnel_buf); buf_discard(tunnel_buf);
return 1; return 1;
} else { } else {
warn("Memory squeeze; dropped incoming msg\n"); warn("Link changeover error, original msg dropped\n");
} }
} }
exit: exit:
...@@ -2444,13 +2564,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf) ...@@ -2444,13 +2564,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf)
while (msgcount--) { while (msgcount--) {
obuf = buf_extract(buf, pos); obuf = buf_extract(buf, pos);
if (obuf == NULL) { if (obuf == NULL) {
char addr_string[16]; warn("Link unable to unbundle message(s)\n");
break;
warn("Buffer allocation failure;\n");
warn(" incoming message(s) from %s lost\n",
addr_string_fill(addr_string,
msg_orignode(buf_msg(buf))));
return;
}; };
pos += align(msg_size(buf_msg(obuf))); pos += align(msg_size(buf_msg(obuf)));
msg_dbg(buf_msg(obuf), " /"); msg_dbg(buf_msg(obuf), " /");
...@@ -2508,7 +2623,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) ...@@ -2508,7 +2623,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
} }
fragm = buf_acquire(fragm_sz + INT_H_SIZE); fragm = buf_acquire(fragm_sz + INT_H_SIZE);
if (fragm == NULL) { if (fragm == NULL) {
warn("Memory squeeze; failed to fragment msg\n"); warn("Link unable to fragment message\n");
dsz = -ENOMEM; dsz = -ENOMEM;
goto exit; goto exit;
} }
...@@ -2623,7 +2738,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, ...@@ -2623,7 +2738,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
set_fragm_size(pbuf,fragm_sz); set_fragm_size(pbuf,fragm_sz);
set_expected_frags(pbuf,exp_fragm_cnt - 1); set_expected_frags(pbuf,exp_fragm_cnt - 1);
} else { } else {
warn("Memory squeeze; got no defragmenting buffer\n"); warn("Link unable to reassemble fragmented message\n");
} }
buf_discard(fbuf); buf_discard(fbuf);
return 0; return 0;
......
...@@ -127,7 +127,7 @@ void tipc_named_publish(struct publication *publ) ...@@ -127,7 +127,7 @@ void tipc_named_publish(struct publication *publ)
buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0); buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
if (!buf) { if (!buf) {
warn("Memory squeeze; failed to distribute publication\n"); warn("Publication distribution failure\n");
return; return;
} }
...@@ -151,7 +151,7 @@ void tipc_named_withdraw(struct publication *publ) ...@@ -151,7 +151,7 @@ void tipc_named_withdraw(struct publication *publ)
buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0); buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
if (!buf) { if (!buf) {
warn("Memory squeeze; failed to distribute withdrawal\n"); warn("Withdrawl distribution failure\n");
return; return;
} }
...@@ -174,7 +174,6 @@ void tipc_named_node_up(unsigned long node) ...@@ -174,7 +174,6 @@ void tipc_named_node_up(unsigned long node)
u32 rest; u32 rest;
u32 max_item_buf; u32 max_item_buf;
assert(in_own_cluster(node));
read_lock_bh(&tipc_nametbl_lock); read_lock_bh(&tipc_nametbl_lock);
max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE; max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
max_item_buf *= ITEM_SIZE; max_item_buf *= ITEM_SIZE;
...@@ -185,8 +184,8 @@ void tipc_named_node_up(unsigned long node) ...@@ -185,8 +184,8 @@ void tipc_named_node_up(unsigned long node)
left = (rest <= max_item_buf) ? rest : max_item_buf; left = (rest <= max_item_buf) ? rest : max_item_buf;
rest -= left; rest -= left;
buf = named_prepare_buf(PUBLICATION, left, node); buf = named_prepare_buf(PUBLICATION, left, node);
if (buf == NULL) { if (!buf) {
warn("Memory Squeeze; could not send publication\n"); warn("Bulk publication distribution failure\n");
goto exit; goto exit;
} }
item = (struct distr_item *)msg_data(buf_msg(buf)); item = (struct distr_item *)msg_data(buf_msg(buf));
...@@ -221,15 +220,24 @@ void tipc_named_node_up(unsigned long node) ...@@ -221,15 +220,24 @@ void tipc_named_node_up(unsigned long node)
static void node_is_down(struct publication *publ) static void node_is_down(struct publication *publ)
{ {
struct publication *p; struct publication *p;
write_lock_bh(&tipc_nametbl_lock); write_lock_bh(&tipc_nametbl_lock);
dbg("node_is_down: withdrawing %u, %u, %u\n", dbg("node_is_down: withdrawing %u, %u, %u\n",
publ->type, publ->lower, publ->upper); publ->type, publ->lower, publ->upper);
publ->key += 1222345; publ->key += 1222345;
p = tipc_nametbl_remove_publ(publ->type, publ->lower, p = tipc_nametbl_remove_publ(publ->type, publ->lower,
publ->node, publ->ref, publ->key); publ->node, publ->ref, publ->key);
assert(p == publ);
write_unlock_bh(&tipc_nametbl_lock); write_unlock_bh(&tipc_nametbl_lock);
kfree(publ);
if (p != publ) {
err("Unable to remove publication from failed node\n"
"(type=%u, lower=%u, node=0x%x, ref=%u, key=%u)\n",
publ->type, publ->lower, publ->node, publ->ref, publ->key);
}
if (p) {
kfree(p);
}
} }
/** /**
...@@ -275,9 +283,15 @@ void tipc_named_recv(struct sk_buff *buf) ...@@ -275,9 +283,15 @@ void tipc_named_recv(struct sk_buff *buf)
if (publ) { if (publ) {
tipc_nodesub_unsubscribe(&publ->subscr); tipc_nodesub_unsubscribe(&publ->subscr);
kfree(publ); kfree(publ);
} else {
err("Unable to remove publication by node 0x%x\n"
"(type=%u, lower=%u, ref=%u, key=%u)\n",
msg_orignode(msg),
ntohl(item->type), ntohl(item->lower),
ntohl(item->ref), ntohl(item->key));
} }
} else { } else {
warn("tipc_named_recv: unknown msg\n"); warn("Unrecognized name table message received\n");
} }
item++; item++;
} }
......
...@@ -71,7 +71,7 @@ struct sub_seq { ...@@ -71,7 +71,7 @@ struct sub_seq {
* @sseq: pointer to dynamically-sized array of sub-sequences of this 'type'; * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
* sub-sequences are sorted in ascending order * sub-sequences are sorted in ascending order
* @alloc: number of sub-sequences currently in array * @alloc: number of sub-sequences currently in array
* @first_free: upper bound of highest sub-sequence + 1 * @first_free: array index of first unused sub-sequence entry
* @ns_list: links to adjacent name sequences in hash chain * @ns_list: links to adjacent name sequences in hash chain
* @subscriptions: list of subscriptions for this 'type' * @subscriptions: list of subscriptions for this 'type'
* @lock: spinlock controlling access to name sequence structure * @lock: spinlock controlling access to name sequence structure
...@@ -120,7 +120,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, ...@@ -120,7 +120,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper,
struct publication *publ = struct publication *publ =
(struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC); (struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC);
if (publ == NULL) { if (publ == NULL) {
warn("Memory squeeze; failed to create publication\n"); warn("Publication creation failure, no memory\n");
return NULL; return NULL;
} }
...@@ -165,7 +165,7 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea ...@@ -165,7 +165,7 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea
struct sub_seq *sseq = tipc_subseq_alloc(1); struct sub_seq *sseq = tipc_subseq_alloc(1);
if (!nseq || !sseq) { if (!nseq || !sseq) {
warn("Memory squeeze; failed to create name sequence\n"); warn("Name sequence creation failed, no memory\n");
kfree(nseq); kfree(nseq);
kfree(sseq); kfree(sseq);
return NULL; return NULL;
...@@ -175,7 +175,7 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea ...@@ -175,7 +175,7 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea
nseq->lock = SPIN_LOCK_UNLOCKED; nseq->lock = SPIN_LOCK_UNLOCKED;
nseq->type = type; nseq->type = type;
nseq->sseqs = sseq; nseq->sseqs = sseq;
dbg("tipc_nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n", dbg("tipc_nameseq_create(): nseq = %p, type %u, ssseqs %p, ff: %u\n",
nseq, type, nseq->sseqs, nseq->first_free); nseq, type, nseq->sseqs, nseq->first_free);
nseq->alloc = 1; nseq->alloc = 1;
INIT_HLIST_NODE(&nseq->ns_list); INIT_HLIST_NODE(&nseq->ns_list);
...@@ -253,16 +253,16 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, ...@@ -253,16 +253,16 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
struct sub_seq *sseq; struct sub_seq *sseq;
int created_subseq = 0; int created_subseq = 0;
assert(nseq->first_free <= nseq->alloc);
sseq = nameseq_find_subseq(nseq, lower); sseq = nameseq_find_subseq(nseq, lower);
dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n", dbg("nameseq_ins: for seq %p, {%u,%u}, found sseq %p\n",
nseq, type, lower, sseq); nseq, type, lower, sseq);
if (sseq) { if (sseq) {
/* Lower end overlaps existing entry => need an exact match */ /* Lower end overlaps existing entry => need an exact match */
if ((sseq->lower != lower) || (sseq->upper != upper)) { if ((sseq->lower != lower) || (sseq->upper != upper)) {
warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); warn("Cannot publish {%u,%u,%u}, overlap error\n",
type, lower, upper);
return NULL; return NULL;
} }
} else { } else {
...@@ -277,25 +277,27 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, ...@@ -277,25 +277,27 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
if ((inspos < nseq->first_free) && if ((inspos < nseq->first_free) &&
(upper >= nseq->sseqs[inspos].lower)) { (upper >= nseq->sseqs[inspos].lower)) {
warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); warn("Cannot publish {%u,%u,%u}, overlap error\n",
type, lower, upper);
return NULL; return NULL;
} }
/* Ensure there is space for new sub-sequence */ /* Ensure there is space for new sub-sequence */
if (nseq->first_free == nseq->alloc) { if (nseq->first_free == nseq->alloc) {
struct sub_seq *sseqs = nseq->sseqs; struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2);
nseq->sseqs = tipc_subseq_alloc(nseq->alloc * 2);
if (nseq->sseqs != NULL) { if (!sseqs) {
memcpy(nseq->sseqs, sseqs, warn("Cannot publish {%u,%u,%u}, no memory\n",
nseq->alloc * sizeof (struct sub_seq)); type, lower, upper);
kfree(sseqs);
dbg("Allocated %u sseqs\n", nseq->alloc);
nseq->alloc *= 2;
} else {
warn("Memory squeeze; failed to create sub-sequence\n");
return NULL; return NULL;
} }
dbg("Allocated %u more sseqs\n", nseq->alloc);
memcpy(sseqs, nseq->sseqs,
nseq->alloc * sizeof(struct sub_seq));
kfree(nseq->sseqs);
nseq->sseqs = sseqs;
nseq->alloc *= 2;
} }
dbg("Have %u sseqs for type %u\n", nseq->alloc, type); dbg("Have %u sseqs for type %u\n", nseq->alloc, type);
...@@ -311,7 +313,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, ...@@ -311,7 +313,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
sseq->upper = upper; sseq->upper = upper;
created_subseq = 1; created_subseq = 1;
} }
dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n", dbg("inserting {%u,%u,%u} from <0x%x:%u> into sseq %p(%u,%u) of seq %p\n",
type, lower, upper, node, port, sseq, type, lower, upper, node, port, sseq,
sseq->lower, sseq->upper, nseq); sseq->lower, sseq->upper, nseq);
...@@ -320,7 +322,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, ...@@ -320,7 +322,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
publ = publ_create(type, lower, upper, scope, node, port, key); publ = publ_create(type, lower, upper, scope, node, port, key);
if (!publ) if (!publ)
return NULL; return NULL;
dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n", dbg("inserting publ %p, node=0x%x publ->node=0x%x, subscr->node=%p\n",
publ, node, publ->node, publ->subscr.node); publ, node, publ->node, publ->subscr.node);
if (!sseq->zone_list) if (!sseq->zone_list)
...@@ -367,45 +369,47 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, ...@@ -367,45 +369,47 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
/** /**
* tipc_nameseq_remove_publ - * tipc_nameseq_remove_publ -
*
* NOTE: There may be cases where TIPC is asked to remove a publication
* that is not in the name table. For example, if another node issues a
* publication for a name sequence that overlaps an existing name sequence
* the publication will not be recorded, which means the publication won't
* be found when the name sequence is later withdrawn by that node.
* A failed withdraw request simply returns a failure indication and lets the
* caller issue any error or warning messages associated with such a problem.
*/ */
static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst, static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
u32 node, u32 ref, u32 key) u32 node, u32 ref, u32 key)
{ {
struct publication *publ; struct publication *publ;
struct publication *curr;
struct publication *prev; struct publication *prev;
struct sub_seq *sseq = nameseq_find_subseq(nseq, inst); struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
struct sub_seq *free; struct sub_seq *free;
struct subscription *s, *st; struct subscription *s, *st;
int removed_subseq = 0; int removed_subseq = 0;
assert(nseq); if (!sseq)
if (!sseq) {
int i;
warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst);
assert(nseq->sseqs);
dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n",
nseq->sseqs, nseq, nseq->alloc,
nseq->first_free);
for (i = 0; i < nseq->first_free; i++) {
dbg("Subseq %u(%x): lower = %u,upper = %u\n",
i, &nseq->sseqs[i], nseq->sseqs[i].lower,
nseq->sseqs[i].upper);
}
return NULL; return NULL;
}
dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n", dbg("tipc_nameseq_remove_publ: seq: %p, sseq %p, {%u,%u}, key %u\n",
nseq, sseq, nseq->type, inst, key); nseq, sseq, nseq->type, inst, key);
/* Remove publication from zone scope list */
prev = sseq->zone_list; prev = sseq->zone_list;
publ = sseq->zone_list->zone_list_next; publ = sseq->zone_list->zone_list_next;
while ((publ->key != key) || (publ->ref != ref) || while ((publ->key != key) || (publ->ref != ref) ||
(publ->node && (publ->node != node))) { (publ->node && (publ->node != node))) {
prev = publ; prev = publ;
publ = publ->zone_list_next; publ = publ->zone_list_next;
assert(prev != sseq->zone_list); if (prev == sseq->zone_list) {
/* Prevent endless loop if publication not found */
return NULL;
}
} }
if (publ != sseq->zone_list) if (publ != sseq->zone_list)
prev->zone_list_next = publ->zone_list_next; prev->zone_list_next = publ->zone_list_next;
...@@ -416,14 +420,24 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i ...@@ -416,14 +420,24 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i
sseq->zone_list = NULL; sseq->zone_list = NULL;
} }
/* Remove publication from cluster scope list, if present */
if (in_own_cluster(node)) { if (in_own_cluster(node)) {
prev = sseq->cluster_list; prev = sseq->cluster_list;
publ = sseq->cluster_list->cluster_list_next; curr = sseq->cluster_list->cluster_list_next;
while ((publ->key != key) || (publ->ref != ref) || while (curr != publ) {
(publ->node && (publ->node != node))) { prev = curr;
prev = publ; curr = curr->cluster_list_next;
publ = publ->cluster_list_next; if (prev == sseq->cluster_list) {
assert(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) if (publ != sseq->cluster_list)
prev->cluster_list_next = publ->cluster_list_next; prev->cluster_list_next = publ->cluster_list_next;
...@@ -434,15 +448,26 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i ...@@ -434,15 +448,26 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i
sseq->cluster_list = NULL; sseq->cluster_list = NULL;
} }
} }
end_cluster:
/* Remove publication from node scope list, if present */
if (node == tipc_own_addr) { if (node == tipc_own_addr) {
prev = sseq->node_list; prev = sseq->node_list;
publ = sseq->node_list->node_list_next; curr = sseq->node_list->node_list_next;
while ((publ->key != key) || (publ->ref != ref) || while (curr != publ) {
(publ->node && (publ->node != node))) { prev = curr;
prev = publ; curr = curr->node_list_next;
publ = publ->node_list_next; if (prev == sseq->node_list) {
assert(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) if (publ != sseq->node_list)
prev->node_list_next = publ->node_list_next; prev->node_list_next = publ->node_list_next;
...@@ -453,22 +478,18 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i ...@@ -453,22 +478,18 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i
sseq->node_list = NULL; sseq->node_list = NULL;
} }
} }
assert(!publ->node || (publ->node == node)); end_node:
assert(publ->ref == ref);
assert(publ->key == key);
/* /* Contract subseq list if no more publications for that subseq */
* Contract subseq list if no more publications:
*/ if (!sseq->zone_list) {
if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) {
free = &nseq->sseqs[nseq->first_free--]; free = &nseq->sseqs[nseq->first_free--];
memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq)); memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq));
removed_subseq = 1; removed_subseq = 1;
} }
/* /* Notify any waiting subscriptions */
* Any subscriptions waiting ?
*/
list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
tipc_subscr_report_overlap(s, tipc_subscr_report_overlap(s,
publ->lower, publ->lower,
...@@ -478,6 +499,7 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i ...@@ -478,6 +499,7 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i
publ->node, publ->node,
removed_subseq); removed_subseq);
} }
return publ; return publ;
} }
...@@ -530,7 +552,7 @@ static struct name_seq *nametbl_find_seq(u32 type) ...@@ -530,7 +552,7 @@ static struct name_seq *nametbl_find_seq(u32 type)
seq_head = &table.types[hash(type)]; seq_head = &table.types[hash(type)];
hlist_for_each_entry(ns, seq_node, seq_head, ns_list) { hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
if (ns->type == type) { if (ns->type == type) {
dbg("found %x\n", ns); dbg("found %p\n", ns);
return ns; return ns;
} }
} }
...@@ -543,22 +565,21 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, ...@@ -543,22 +565,21 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
{ {
struct name_seq *seq = nametbl_find_seq(type); struct name_seq *seq = nametbl_find_seq(type);
dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq); dbg("tipc_nametbl_insert_publ: {%u,%u,%u} found %p\n", type, lower, upper, seq);
if (lower > upper) { if (lower > upper) {
warn("Failed to publish illegal <%u,%u,%u>\n", warn("Failed to publish illegal {%u,%u,%u}\n",
type, lower, upper); type, lower, upper);
return NULL; return NULL;
} }
dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node); dbg("Publishing {%u,%u,%u} from 0x%x\n", type, lower, upper, node);
if (!seq) { if (!seq) {
seq = tipc_nameseq_create(type, &table.types[hash(type)]); seq = tipc_nameseq_create(type, &table.types[hash(type)]);
dbg("tipc_nametbl_insert_publ: created %x\n", seq); dbg("tipc_nametbl_insert_publ: created %p\n", seq);
} }
if (!seq) if (!seq)
return NULL; return NULL;
assert(seq->type == type);
return tipc_nameseq_insert_publ(seq, type, lower, upper, return tipc_nameseq_insert_publ(seq, type, lower, upper,
scope, node, port, key); scope, node, port, key);
} }
...@@ -572,7 +593,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, ...@@ -572,7 +593,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
if (!seq) if (!seq)
return NULL; return NULL;
dbg("Withdrawing <%u,%u> from %x\n", type, lower, node); dbg("Withdrawing {%u,%u} from 0x%x\n", type, lower, node);
publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key); publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
if (!seq->first_free && list_empty(&seq->subscriptions)) { if (!seq->first_free && list_empty(&seq->subscriptions)) {
...@@ -738,12 +759,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, ...@@ -738,12 +759,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
struct publication *publ; struct publication *publ;
if (table.local_publ_count >= tipc_max_publications) { if (table.local_publ_count >= tipc_max_publications) {
warn("Failed publish: max %u local publication\n", warn("Publication failed, local publication limit reached (%u)\n",
tipc_max_publications); tipc_max_publications);
return NULL; return NULL;
} }
if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) { if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
warn("Failed to publish reserved name <%u,%u,%u>\n", warn("Publication failed, reserved name {%u,%u,%u}\n",
type, lower, upper); type, lower, upper);
return NULL; return NULL;
} }
...@@ -767,10 +788,10 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) ...@@ -767,10 +788,10 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
{ {
struct publication *publ; struct publication *publ;
dbg("tipc_nametbl_withdraw:<%d,%d,%d>\n", type, lower, key); dbg("tipc_nametbl_withdraw: {%u,%u}, key=%u\n", type, lower, key);
write_lock_bh(&tipc_nametbl_lock); write_lock_bh(&tipc_nametbl_lock);
publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
if (publ) { if (likely(publ)) {
table.local_publ_count--; table.local_publ_count--;
if (publ->scope != TIPC_NODE_SCOPE) if (publ->scope != TIPC_NODE_SCOPE)
tipc_named_withdraw(publ); tipc_named_withdraw(publ);
...@@ -780,6 +801,9 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) ...@@ -780,6 +801,9 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
return 1; return 1;
} }
write_unlock_bh(&tipc_nametbl_lock); write_unlock_bh(&tipc_nametbl_lock);
err("Unable to remove local publication\n"
"(type=%u, lower=%u, ref=%u, key=%u)\n",
type, lower, ref, key);
return 0; return 0;
} }
...@@ -787,8 +811,7 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) ...@@ -787,8 +811,7 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
* tipc_nametbl_subscribe - add a subscription object to the name table * tipc_nametbl_subscribe - add a subscription object to the name table
*/ */
void void tipc_nametbl_subscribe(struct subscription *s)
tipc_nametbl_subscribe(struct subscription *s)
{ {
u32 type = s->seq.type; u32 type = s->seq.type;
struct name_seq *seq; struct name_seq *seq;
...@@ -800,11 +823,13 @@ tipc_nametbl_subscribe(struct subscription *s) ...@@ -800,11 +823,13 @@ tipc_nametbl_subscribe(struct subscription *s)
} }
if (seq){ if (seq){
spin_lock_bh(&seq->lock); spin_lock_bh(&seq->lock);
dbg("tipc_nametbl_subscribe:found %x for <%u,%u,%u>\n", dbg("tipc_nametbl_subscribe:found %p for {%u,%u,%u}\n",
seq, type, s->seq.lower, s->seq.upper); seq, type, s->seq.lower, s->seq.upper);
assert(seq->type == type);
tipc_nameseq_subscribe(seq, s); tipc_nameseq_subscribe(seq, s);
spin_unlock_bh(&seq->lock); spin_unlock_bh(&seq->lock);
} else {
warn("Failed to create subscription for {%u,%u,%u}\n",
s->seq.type, s->seq.lower, s->seq.upper);
} }
write_unlock_bh(&tipc_nametbl_lock); write_unlock_bh(&tipc_nametbl_lock);
} }
...@@ -813,8 +838,7 @@ tipc_nametbl_subscribe(struct subscription *s) ...@@ -813,8 +838,7 @@ tipc_nametbl_subscribe(struct subscription *s)
* tipc_nametbl_unsubscribe - remove a subscription object from name table * tipc_nametbl_unsubscribe - remove a subscription object from name table
*/ */
void void tipc_nametbl_unsubscribe(struct subscription *s)
tipc_nametbl_unsubscribe(struct subscription *s)
{ {
struct name_seq *seq; struct name_seq *seq;
...@@ -1049,35 +1073,20 @@ int tipc_nametbl_init(void) ...@@ -1049,35 +1073,20 @@ int tipc_nametbl_init(void)
void tipc_nametbl_stop(void) void tipc_nametbl_stop(void)
{ {
struct hlist_head *seq_head;
struct hlist_node *seq_node;
struct hlist_node *tmp;
struct name_seq *seq;
u32 i; u32 i;
if (!table.types) if (!table.types)
return; return;
/* Verify name table is empty, then release it */
write_lock_bh(&tipc_nametbl_lock); write_lock_bh(&tipc_nametbl_lock);
for (i = 0; i < tipc_nametbl_size; i++) { for (i = 0; i < tipc_nametbl_size; i++) {
seq_head = &table.types[i]; if (!hlist_empty(&table.types[i]))
hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) { err("tipc_nametbl_stop(): hash chain %u is non-null\n", i);
struct sub_seq *sseq = seq->sseqs;
for (; sseq != &seq->sseqs[seq->first_free]; sseq++) {
struct publication *publ = sseq->zone_list;
assert(publ);
do {
struct publication *next =
publ->zone_list_next;
kfree(publ);
publ = next;
}
while (publ != sseq->zone_list);
}
}
} }
kfree(table.types); kfree(table.types);
table.types = NULL; table.types = NULL;
write_unlock_bh(&tipc_nametbl_lock); write_unlock_bh(&tipc_nametbl_lock);
} }
...@@ -61,34 +61,37 @@ struct node *tipc_node_create(u32 addr) ...@@ -61,34 +61,37 @@ struct node *tipc_node_create(u32 addr)
struct node **curr_node; struct node **curr_node;
n_ptr = kmalloc(sizeof(*n_ptr),GFP_ATOMIC); n_ptr = kmalloc(sizeof(*n_ptr),GFP_ATOMIC);
if (n_ptr != NULL) { if (!n_ptr) {
memset(n_ptr, 0, sizeof(*n_ptr)); warn("Node creation failed, no memory\n");
n_ptr->addr = addr; return NULL;
n_ptr->lock = SPIN_LOCK_UNLOCKED; }
INIT_LIST_HEAD(&n_ptr->nsub);
c_ptr = tipc_cltr_find(addr);
c_ptr = tipc_cltr_find(addr); if (!c_ptr) {
if (c_ptr == NULL) c_ptr = tipc_cltr_create(addr);
c_ptr = tipc_cltr_create(addr); }
if (c_ptr != NULL) { if (!c_ptr) {
n_ptr->owner = c_ptr; kfree(n_ptr);
tipc_cltr_attach_node(c_ptr, n_ptr); return NULL;
n_ptr->last_router = -1; }
/* Insert node into ordered list */ memset(n_ptr, 0, sizeof(*n_ptr));
for (curr_node = &tipc_nodes; *curr_node; n_ptr->addr = addr;
curr_node = &(*curr_node)->next) { n_ptr->lock = SPIN_LOCK_UNLOCKED;
if (addr < (*curr_node)->addr) { INIT_LIST_HEAD(&n_ptr->nsub);
n_ptr->next = *curr_node; n_ptr->owner = c_ptr;
break; tipc_cltr_attach_node(c_ptr, n_ptr);
} n_ptr->last_router = -1;
}
(*curr_node) = n_ptr; /* Insert node into ordered list */
} else { for (curr_node = &tipc_nodes; *curr_node;
kfree(n_ptr); curr_node = &(*curr_node)->next) {
n_ptr = NULL; if (addr < (*curr_node)->addr) {
} n_ptr->next = *curr_node;
} break;
}
}
(*curr_node) = n_ptr;
return n_ptr; return n_ptr;
} }
...@@ -122,6 +125,8 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr) ...@@ -122,6 +125,8 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
{ {
struct link **active = &n_ptr->active_links[0]; struct link **active = &n_ptr->active_links[0];
n_ptr->working_links++;
info("Established link <%s> on network plane %c\n", info("Established link <%s> on network plane %c\n",
l_ptr->name, l_ptr->b_ptr->net_plane); l_ptr->name, l_ptr->b_ptr->net_plane);
...@@ -132,7 +137,7 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr) ...@@ -132,7 +137,7 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
return; return;
} }
if (l_ptr->priority < active[0]->priority) { if (l_ptr->priority < active[0]->priority) {
info("Link is standby\n"); info("New link <%s> becomes standby\n", l_ptr->name);
return; return;
} }
tipc_link_send_duplicate(active[0], l_ptr); tipc_link_send_duplicate(active[0], l_ptr);
...@@ -140,8 +145,9 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr) ...@@ -140,8 +145,9 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
active[0] = l_ptr; active[0] = l_ptr;
return; return;
} }
info("Link <%s> on network plane %c becomes standby\n", info("Old link <%s> becomes standby\n", active[0]->name);
active[0]->name, active[0]->b_ptr->net_plane); if (active[1] != active[0])
info("Old link <%s> becomes standby\n", active[1]->name);
active[0] = active[1] = l_ptr; active[0] = active[1] = l_ptr;
} }
...@@ -181,6 +187,8 @@ void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr) ...@@ -181,6 +187,8 @@ void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr)
{ {
struct link **active; struct link **active;
n_ptr->working_links--;
if (!tipc_link_is_active(l_ptr)) { if (!tipc_link_is_active(l_ptr)) {
info("Lost standby link <%s> on network plane %c\n", info("Lost standby link <%s> on network plane %c\n",
l_ptr->name, l_ptr->b_ptr->net_plane); l_ptr->name, l_ptr->b_ptr->net_plane);
...@@ -210,8 +218,7 @@ int tipc_node_has_active_links(struct node *n_ptr) ...@@ -210,8 +218,7 @@ int tipc_node_has_active_links(struct node *n_ptr)
int tipc_node_has_redundant_links(struct node *n_ptr) int tipc_node_has_redundant_links(struct node *n_ptr)
{ {
return (tipc_node_has_active_links(n_ptr) && return (n_ptr->working_links > 1);
(n_ptr->active_links[0] != n_ptr->active_links[1]));
} }
static int tipc_node_has_active_routes(struct node *n_ptr) static int tipc_node_has_active_routes(struct node *n_ptr)
...@@ -234,7 +241,6 @@ struct node *tipc_node_attach_link(struct link *l_ptr) ...@@ -234,7 +241,6 @@ struct node *tipc_node_attach_link(struct link *l_ptr)
u32 bearer_id = l_ptr->b_ptr->identity; u32 bearer_id = l_ptr->b_ptr->identity;
char addr_string[16]; char addr_string[16];
assert(bearer_id < MAX_BEARERS);
if (n_ptr->link_cnt >= 2) { if (n_ptr->link_cnt >= 2) {
char addr_string[16]; char addr_string[16];
...@@ -249,7 +255,7 @@ struct node *tipc_node_attach_link(struct link *l_ptr) ...@@ -249,7 +255,7 @@ struct node *tipc_node_attach_link(struct link *l_ptr)
n_ptr->link_cnt++; n_ptr->link_cnt++;
return n_ptr; return n_ptr;
} }
err("Attempt to establish second link on <%s> to <%s> \n", err("Attempt to establish second link on <%s> to %s \n",
l_ptr->b_ptr->publ.name, l_ptr->b_ptr->publ.name,
addr_string_fill(addr_string, l_ptr->addr)); addr_string_fill(addr_string, l_ptr->addr));
} }
...@@ -314,7 +320,7 @@ static void node_established_contact(struct node *n_ptr) ...@@ -314,7 +320,7 @@ static void node_established_contact(struct node *n_ptr)
struct cluster *c_ptr; struct cluster *c_ptr;
dbg("node_established_contact:-> %x\n", n_ptr->addr); dbg("node_established_contact:-> %x\n", n_ptr->addr);
if (!tipc_node_has_active_routes(n_ptr)) { if (!tipc_node_has_active_routes(n_ptr) && in_own_cluster(n_ptr->addr)) {
tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr); tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
} }
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
* @nsub: list of "node down" subscriptions monitoring node * @nsub: list of "node down" subscriptions monitoring node
* @active_links: pointers to active links to node * @active_links: pointers to active links to node
* @links: pointers to all links to node * @links: pointers to all links to node
* @working_links: number of working links to node (both active and standby)
* @link_cnt: number of links to node * @link_cnt: number of links to node
* @permit_changeover: non-zero if node has redundant links to this system * @permit_changeover: non-zero if node has redundant links to this system
* @routers: bitmap (used for multicluster communication) * @routers: bitmap (used for multicluster communication)
...@@ -76,6 +77,7 @@ struct node { ...@@ -76,6 +77,7 @@ struct node {
struct link *active_links[2]; struct link *active_links[2];
struct link *links[MAX_BEARERS]; struct link *links[MAX_BEARERS];
int link_cnt; int link_cnt;
int working_links;
int permit_changeover; int permit_changeover;
u32 routers[512/32]; u32 routers[512/32];
int last_router; int last_router;
......
...@@ -47,18 +47,19 @@ ...@@ -47,18 +47,19 @@
void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
void *usr_handle, net_ev_handler handle_down) void *usr_handle, net_ev_handler handle_down)
{ {
node_sub->node = NULL; if (addr == tipc_own_addr) {
if (addr == tipc_own_addr) node_sub->node = NULL;
return; return;
if (!tipc_addr_node_valid(addr)) { }
warn("node_subscr with illegal %x\n", addr);
node_sub->node = tipc_node_find(addr);
if (!node_sub->node) {
warn("Node subscription rejected, unknown node 0x%x\n", addr);
return; return;
} }
node_sub->handle_node_down = handle_down; node_sub->handle_node_down = handle_down;
node_sub->usr_handle = usr_handle; node_sub->usr_handle = usr_handle;
node_sub->node = tipc_node_find(addr);
assert(node_sub->node);
tipc_node_lock(node_sub->node); tipc_node_lock(node_sub->node);
list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub); list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub);
tipc_node_unlock(node_sub->node); tipc_node_unlock(node_sub->node);
......
...@@ -168,7 +168,6 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp) ...@@ -168,7 +168,6 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp)
struct port_list *item = dp; struct port_list *item = dp;
int cnt = 0; int cnt = 0;
assert(buf);
msg = buf_msg(buf); msg = buf_msg(buf);
/* Create destination port list, if one wasn't supplied */ /* Create destination port list, if one wasn't supplied */
...@@ -196,7 +195,7 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp) ...@@ -196,7 +195,7 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp)
struct sk_buff *b = skb_clone(buf, GFP_ATOMIC); struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
if (b == NULL) { if (b == NULL) {
warn("Buffer allocation failure\n"); warn("Unable to deliver multicast message(s)\n");
msg_dbg(msg, "LOST:"); msg_dbg(msg, "LOST:");
goto exit; goto exit;
} }
...@@ -228,14 +227,14 @@ u32 tipc_createport_raw(void *usr_handle, ...@@ -228,14 +227,14 @@ u32 tipc_createport_raw(void *usr_handle,
u32 ref; u32 ref;
p_ptr = kmalloc(sizeof(*p_ptr), GFP_ATOMIC); p_ptr = kmalloc(sizeof(*p_ptr), GFP_ATOMIC);
if (p_ptr == NULL) { if (!p_ptr) {
warn("Memory squeeze; failed to create port\n"); warn("Port creation failed, no memory\n");
return 0; return 0;
} }
memset(p_ptr, 0, sizeof(*p_ptr)); memset(p_ptr, 0, sizeof(*p_ptr));
ref = tipc_ref_acquire(p_ptr, &p_ptr->publ.lock); ref = tipc_ref_acquire(p_ptr, &p_ptr->publ.lock);
if (!ref) { if (!ref) {
warn("Reference Table Exhausted\n"); warn("Port creation failed, reference table exhausted\n");
kfree(p_ptr); kfree(p_ptr);
return 0; return 0;
} }
...@@ -810,18 +809,20 @@ static void port_dispatcher_sigh(void *dummy) ...@@ -810,18 +809,20 @@ static void port_dispatcher_sigh(void *dummy)
void *usr_handle; void *usr_handle;
int connected; int connected;
int published; int published;
u32 message_type;
struct sk_buff *next = buf->next; struct sk_buff *next = buf->next;
struct tipc_msg *msg = buf_msg(buf); struct tipc_msg *msg = buf_msg(buf);
u32 dref = msg_destport(msg); u32 dref = msg_destport(msg);
message_type = msg_type(msg);
if (message_type > TIPC_DIRECT_MSG)
goto reject; /* Unsupported message type */
p_ptr = tipc_port_lock(dref); p_ptr = tipc_port_lock(dref);
if (!p_ptr) { if (!p_ptr)
/* Port deleted while msg in queue */ goto reject; /* Port deleted while msg in queue */
tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
buf = next;
continue;
}
orig.ref = msg_origport(msg); orig.ref = msg_origport(msg);
orig.node = msg_orignode(msg); orig.node = msg_orignode(msg);
up_ptr = p_ptr->user_port; up_ptr = p_ptr->user_port;
...@@ -832,7 +833,7 @@ static void port_dispatcher_sigh(void *dummy) ...@@ -832,7 +833,7 @@ static void port_dispatcher_sigh(void *dummy)
if (unlikely(msg_errcode(msg))) if (unlikely(msg_errcode(msg)))
goto err; goto err;
switch (msg_type(msg)) { switch (message_type) {
case TIPC_CONN_MSG:{ case TIPC_CONN_MSG:{
tipc_conn_msg_event cb = up_ptr->conn_msg_cb; tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
...@@ -874,6 +875,7 @@ static void port_dispatcher_sigh(void *dummy) ...@@ -874,6 +875,7 @@ static void port_dispatcher_sigh(void *dummy)
&orig); &orig);
break; break;
} }
case TIPC_MCAST_MSG:
case TIPC_NAMED_MSG:{ case TIPC_NAMED_MSG:{
tipc_named_msg_event cb = up_ptr->named_msg_cb; tipc_named_msg_event cb = up_ptr->named_msg_cb;
...@@ -886,7 +888,8 @@ static void port_dispatcher_sigh(void *dummy) ...@@ -886,7 +888,8 @@ static void port_dispatcher_sigh(void *dummy)
goto reject; goto reject;
dseq.type = msg_nametype(msg); dseq.type = msg_nametype(msg);
dseq.lower = msg_nameinst(msg); dseq.lower = msg_nameinst(msg);
dseq.upper = dseq.lower; dseq.upper = (message_type == TIPC_NAMED_MSG)
? dseq.lower : msg_nameupper(msg);
skb_pull(buf, msg_hdr_sz(msg)); skb_pull(buf, msg_hdr_sz(msg));
cb(usr_handle, dref, &buf, msg_data(msg), cb(usr_handle, dref, &buf, msg_data(msg),
msg_data_sz(msg), msg_importance(msg), msg_data_sz(msg), msg_importance(msg),
...@@ -899,7 +902,7 @@ static void port_dispatcher_sigh(void *dummy) ...@@ -899,7 +902,7 @@ static void port_dispatcher_sigh(void *dummy)
buf = next; buf = next;
continue; continue;
err: err:
switch (msg_type(msg)) { switch (message_type) {
case TIPC_CONN_MSG:{ case TIPC_CONN_MSG:{
tipc_conn_shutdown_event cb = tipc_conn_shutdown_event cb =
...@@ -931,6 +934,7 @@ static void port_dispatcher_sigh(void *dummy) ...@@ -931,6 +934,7 @@ static void port_dispatcher_sigh(void *dummy)
msg_data_sz(msg), msg_errcode(msg), &orig); msg_data_sz(msg), msg_errcode(msg), &orig);
break; break;
} }
case TIPC_MCAST_MSG:
case TIPC_NAMED_MSG:{ case TIPC_NAMED_MSG:{
tipc_named_msg_err_event cb = tipc_named_msg_err_event cb =
up_ptr->named_err_cb; up_ptr->named_err_cb;
...@@ -940,7 +944,8 @@ static void port_dispatcher_sigh(void *dummy) ...@@ -940,7 +944,8 @@ static void port_dispatcher_sigh(void *dummy)
break; break;
dseq.type = msg_nametype(msg); dseq.type = msg_nametype(msg);
dseq.lower = msg_nameinst(msg); dseq.lower = msg_nameinst(msg);
dseq.upper = dseq.lower; dseq.upper = (message_type == TIPC_NAMED_MSG)
? dseq.lower : msg_nameupper(msg);
skb_pull(buf, msg_hdr_sz(msg)); skb_pull(buf, msg_hdr_sz(msg));
cb(usr_handle, dref, &buf, msg_data(msg), cb(usr_handle, dref, &buf, msg_data(msg),
msg_data_sz(msg), msg_errcode(msg), &dseq); msg_data_sz(msg), msg_errcode(msg), &dseq);
...@@ -1054,7 +1059,8 @@ int tipc_createport(u32 user_ref, ...@@ -1054,7 +1059,8 @@ int tipc_createport(u32 user_ref,
u32 ref; u32 ref;
up_ptr = (struct user_port *)kmalloc(sizeof(*up_ptr), GFP_ATOMIC); up_ptr = (struct user_port *)kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
if (up_ptr == NULL) { if (!up_ptr) {
warn("Port creation failed, no memory\n");
return -ENOMEM; return -ENOMEM;
} }
ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance); ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance);
...@@ -1165,8 +1171,6 @@ int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) ...@@ -1165,8 +1171,6 @@ int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
p_ptr = tipc_port_lock(ref); p_ptr = tipc_port_lock(ref);
if (!p_ptr) if (!p_ptr)
return -EINVAL; return -EINVAL;
if (!p_ptr->publ.published)
goto exit;
if (!seq) { if (!seq) {
list_for_each_entry_safe(publ, tpubl, list_for_each_entry_safe(publ, tpubl,
&p_ptr->publications, pport_list) { &p_ptr->publications, pport_list) {
...@@ -1193,7 +1197,6 @@ int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) ...@@ -1193,7 +1197,6 @@ int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
} }
if (list_empty(&p_ptr->publications)) if (list_empty(&p_ptr->publications))
p_ptr->publ.published = 0; p_ptr->publ.published = 0;
exit:
tipc_port_unlock(p_ptr); tipc_port_unlock(p_ptr);
return res; return res;
} }
......
...@@ -127,7 +127,14 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) ...@@ -127,7 +127,14 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
u32 next_plus_upper; u32 next_plus_upper;
u32 reference = 0; u32 reference = 0;
assert(tipc_ref_table.entries && object); if (!object) {
err("Attempt to acquire reference to non-existent object\n");
return 0;
}
if (!tipc_ref_table.entries) {
err("Reference table not found during acquisition attempt\n");
return 0;
}
write_lock_bh(&ref_table_lock); write_lock_bh(&ref_table_lock);
if (tipc_ref_table.first_free) { if (tipc_ref_table.first_free) {
...@@ -162,15 +169,28 @@ void tipc_ref_discard(u32 ref) ...@@ -162,15 +169,28 @@ void tipc_ref_discard(u32 ref)
u32 index; u32 index;
u32 index_mask; u32 index_mask;
assert(tipc_ref_table.entries); if (!ref) {
assert(ref != 0); err("Attempt to discard reference 0\n");
return;
}
if (!tipc_ref_table.entries) {
err("Reference table not found during discard attempt\n");
return;
}
write_lock_bh(&ref_table_lock); write_lock_bh(&ref_table_lock);
index_mask = tipc_ref_table.index_mask; index_mask = tipc_ref_table.index_mask;
index = ref & index_mask; index = ref & index_mask;
entry = &(tipc_ref_table.entries[index]); entry = &(tipc_ref_table.entries[index]);
assert(entry->object != 0);
assert(entry->data.reference == ref); if (!entry->object) {
err("Attempt to discard reference to non-existent object\n");
goto exit;
}
if (entry->data.reference != ref) {
err("Attempt to discard non-existent reference\n");
goto exit;
}
/* mark entry as unused */ /* mark entry as unused */
entry->object = NULL; entry->object = NULL;
...@@ -184,6 +204,7 @@ void tipc_ref_discard(u32 ref) ...@@ -184,6 +204,7 @@ void tipc_ref_discard(u32 ref)
/* increment upper bits of entry to invalidate subsequent references */ /* increment upper bits of entry to invalidate subsequent references */
entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1); entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1);
exit:
write_unlock_bh(&ref_table_lock); write_unlock_bh(&ref_table_lock);
} }
...@@ -169,12 +169,6 @@ static int tipc_create(struct socket *sock, int protocol) ...@@ -169,12 +169,6 @@ static int tipc_create(struct socket *sock, int protocol)
struct sock *sk; struct sock *sk;
u32 ref; u32 ref;
if ((sock->type != SOCK_STREAM) &&
(sock->type != SOCK_SEQPACKET) &&
(sock->type != SOCK_DGRAM) &&
(sock->type != SOCK_RDM))
return -EPROTOTYPE;
if (unlikely(protocol != 0)) if (unlikely(protocol != 0))
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
...@@ -199,6 +193,9 @@ static int tipc_create(struct socket *sock, int protocol) ...@@ -199,6 +193,9 @@ static int tipc_create(struct socket *sock, int protocol)
sock->ops = &msg_ops; sock->ops = &msg_ops;
sock->state = SS_READY; sock->state = SS_READY;
break; break;
default:
tipc_deleteport(ref);
return -EPROTOTYPE;
} }
sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1); sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1);
...@@ -426,7 +423,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) ...@@ -426,7 +423,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr))) if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr)))
return -EFAULT; return -EFAULT;
if ((ntohs(hdr.tcm_type) & 0xC000) & (!capable(CAP_NET_ADMIN))) if ((ntohs(hdr.tcm_type) & 0xC000) && (!capable(CAP_NET_ADMIN)))
return -EACCES; return -EACCES;
return 0; return 0;
...@@ -437,7 +434,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) ...@@ -437,7 +434,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
* @iocb: (unused) * @iocb: (unused)
* @sock: socket structure * @sock: socket structure
* @m: message to send * @m: message to send
* @total_len: (unused) * @total_len: length of message
* *
* Message must have an destination specified explicitly. * Message must have an destination specified explicitly.
* Used for SOCK_RDM and SOCK_DGRAM messages, * Used for SOCK_RDM and SOCK_DGRAM messages,
...@@ -458,7 +455,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, ...@@ -458,7 +455,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
if (unlikely(!dest)) if (unlikely(!dest))
return -EDESTADDRREQ; return -EDESTADDRREQ;
if (unlikely(dest->family != AF_TIPC)) if (unlikely((m->msg_namelen < sizeof(*dest)) ||
(dest->family != AF_TIPC)))
return -EINVAL; return -EINVAL;
needs_conn = (sock->state != SS_READY); needs_conn = (sock->state != SS_READY);
...@@ -470,6 +468,10 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, ...@@ -470,6 +468,10 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
if ((tsock->p->published) || if ((tsock->p->published) ||
((sock->type == SOCK_STREAM) && (total_len != 0))) ((sock->type == SOCK_STREAM) && (total_len != 0)))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (dest->addrtype == TIPC_ADDR_NAME) {
tsock->p->conn_type = dest->addr.name.name.type;
tsock->p->conn_instance = dest->addr.name.name.instance;
}
} }
if (down_interruptible(&tsock->sem)) if (down_interruptible(&tsock->sem))
...@@ -538,7 +540,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, ...@@ -538,7 +540,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
* @iocb: (unused) * @iocb: (unused)
* @sock: socket structure * @sock: socket structure
* @m: message to send * @m: message to send
* @total_len: (unused) * @total_len: length of message
* *
* Used for SOCK_SEQPACKET messages and SOCK_STREAM data. * Used for SOCK_SEQPACKET messages and SOCK_STREAM data.
* *
...@@ -561,15 +563,15 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, ...@@ -561,15 +563,15 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
return -ERESTARTSYS; return -ERESTARTSYS;
} }
if (unlikely(sock->state != SS_CONNECTED)) {
if (sock->state == SS_DISCONNECTING)
res = -EPIPE;
else
res = -ENOTCONN;
goto exit;
}
do { do {
if (unlikely(sock->state != SS_CONNECTED)) {
if (sock->state == SS_DISCONNECTING)
res = -EPIPE;
else
res = -ENOTCONN;
goto exit;
}
res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov); res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov);
if (likely(res != -ELINKCONG)) { if (likely(res != -ELINKCONG)) {
exit: exit:
...@@ -597,7 +599,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, ...@@ -597,7 +599,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
* *
* Used for SOCK_STREAM data. * Used for SOCK_STREAM data.
* *
* Returns the number of bytes sent on success, or errno otherwise * Returns the number of bytes sent on success (or partial success),
* or errno if no data sent
*/ */
...@@ -611,6 +614,7 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, ...@@ -611,6 +614,7 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
char __user *curr_start; char __user *curr_start;
int curr_left; int curr_left;
int bytes_to_send; int bytes_to_send;
int bytes_sent;
int res; int res;
if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE)) if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
...@@ -633,11 +637,11 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, ...@@ -633,11 +637,11 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
* of small iovec entries into send_packet(). * of small iovec entries into send_packet().
*/ */
my_msg = *m; curr_iov = m->msg_iov;
curr_iov = my_msg.msg_iov; curr_iovlen = m->msg_iovlen;
curr_iovlen = my_msg.msg_iovlen;
my_msg.msg_iov = &my_iov; my_msg.msg_iov = &my_iov;
my_msg.msg_iovlen = 1; my_msg.msg_iovlen = 1;
bytes_sent = 0;
while (curr_iovlen--) { while (curr_iovlen--) {
curr_start = curr_iov->iov_base; curr_start = curr_iov->iov_base;
...@@ -648,16 +652,18 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, ...@@ -648,16 +652,18 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
? curr_left : TIPC_MAX_USER_MSG_SIZE; ? curr_left : TIPC_MAX_USER_MSG_SIZE;
my_iov.iov_base = curr_start; my_iov.iov_base = curr_start;
my_iov.iov_len = bytes_to_send; my_iov.iov_len = bytes_to_send;
if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) {
return res; return bytes_sent ? bytes_sent : res;
}
curr_left -= bytes_to_send; curr_left -= bytes_to_send;
curr_start += bytes_to_send; curr_start += bytes_to_send;
bytes_sent += bytes_to_send;
} }
curr_iov++; curr_iov++;
} }
return total_len; return bytes_sent;
} }
/** /**
...@@ -727,6 +733,7 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, ...@@ -727,6 +733,7 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
u32 anc_data[3]; u32 anc_data[3];
u32 err; u32 err;
u32 dest_type; u32 dest_type;
int has_name;
int res; int res;
if (likely(m->msg_controllen == 0)) if (likely(m->msg_controllen == 0))
...@@ -738,10 +745,10 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, ...@@ -738,10 +745,10 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
if (unlikely(err)) { if (unlikely(err)) {
anc_data[0] = err; anc_data[0] = err;
anc_data[1] = msg_data_sz(msg); anc_data[1] = msg_data_sz(msg);
if ((res = put_cmsg(m, SOL_SOCKET, TIPC_ERRINFO, 8, anc_data))) if ((res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data)))
return res; return res;
if (anc_data[1] && if (anc_data[1] &&
(res = put_cmsg(m, SOL_SOCKET, TIPC_RETDATA, anc_data[1], (res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1],
msg_data(msg)))) msg_data(msg))))
return res; return res;
} }
...@@ -751,25 +758,28 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, ...@@ -751,25 +758,28 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG; dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;
switch (dest_type) { switch (dest_type) {
case TIPC_NAMED_MSG: case TIPC_NAMED_MSG:
has_name = 1;
anc_data[0] = msg_nametype(msg); anc_data[0] = msg_nametype(msg);
anc_data[1] = msg_namelower(msg); anc_data[1] = msg_namelower(msg);
anc_data[2] = msg_namelower(msg); anc_data[2] = msg_namelower(msg);
break; break;
case TIPC_MCAST_MSG: case TIPC_MCAST_MSG:
has_name = 1;
anc_data[0] = msg_nametype(msg); anc_data[0] = msg_nametype(msg);
anc_data[1] = msg_namelower(msg); anc_data[1] = msg_namelower(msg);
anc_data[2] = msg_nameupper(msg); anc_data[2] = msg_nameupper(msg);
break; break;
case TIPC_CONN_MSG: case TIPC_CONN_MSG:
has_name = (tport->conn_type != 0);
anc_data[0] = tport->conn_type; anc_data[0] = tport->conn_type;
anc_data[1] = tport->conn_instance; anc_data[1] = tport->conn_instance;
anc_data[2] = tport->conn_instance; anc_data[2] = tport->conn_instance;
break; break;
default: default:
anc_data[0] = 0; has_name = 0;
} }
if (anc_data[0] && if (has_name &&
(res = put_cmsg(m, SOL_SOCKET, TIPC_DESTNAME, 12, anc_data))) (res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data)))
return res; return res;
return 0; return 0;
...@@ -960,7 +970,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, ...@@ -960,7 +970,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
restart: restart:
if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
(flags & MSG_DONTWAIT))) { (flags & MSG_DONTWAIT))) {
res = (sz_copied == 0) ? -EWOULDBLOCK : 0; res = -EWOULDBLOCK;
goto exit; goto exit;
} }
...@@ -1051,7 +1061,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, ...@@ -1051,7 +1061,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
exit: exit:
up(&tsock->sem); up(&tsock->sem);
return res ? res : sz_copied; return sz_copied ? sz_copied : res;
} }
/** /**
...@@ -1236,7 +1246,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, ...@@ -1236,7 +1246,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
if (sock->state == SS_READY) if (sock->state == SS_READY)
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* MOVE THE REST OF THIS ERROR CHECKING TO send_msg()? */ /* Issue Posix-compliant error code if socket is in the wrong state */
if (sock->state == SS_LISTENING) if (sock->state == SS_LISTENING)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (sock->state == SS_CONNECTING) if (sock->state == SS_CONNECTING)
...@@ -1244,13 +1255,20 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, ...@@ -1244,13 +1255,20 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
if (sock->state != SS_UNCONNECTED) if (sock->state != SS_UNCONNECTED)
return -EISCONN; return -EISCONN;
if ((dst->family != AF_TIPC) || /*
((dst->addrtype != TIPC_ADDR_NAME) && (dst->addrtype != TIPC_ADDR_ID))) * Reject connection attempt using multicast address
*
* Note: send_msg() validates the rest of the address fields,
* so there's no need to do it here
*/
if (dst->addrtype == TIPC_ADDR_MCAST)
return -EINVAL; return -EINVAL;
/* Send a 'SYN-' to destination */ /* Send a 'SYN-' to destination */
m.msg_name = dest; m.msg_name = dest;
m.msg_namelen = destlen;
if ((res = send_msg(NULL, sock, &m, 0)) < 0) { if ((res = send_msg(NULL, sock, &m, 0)) < 0) {
sock->state = SS_DISCONNECTING; sock->state = SS_DISCONNECTING;
return res; return res;
...@@ -1269,10 +1287,6 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, ...@@ -1269,10 +1287,6 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
msg = buf_msg(buf); msg = buf_msg(buf);
res = auto_connect(sock, tsock, msg); res = auto_connect(sock, tsock, msg);
if (!res) { if (!res) {
if (dst->addrtype == TIPC_ADDR_NAME) {
tsock->p->conn_type = dst->addr.name.name.type;
tsock->p->conn_instance = dst->addr.name.name.instance;
}
if (!msg_data_sz(msg)) if (!msg_data_sz(msg))
advance_queue(tsock); advance_queue(tsock);
} }
...@@ -1386,7 +1400,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -1386,7 +1400,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags)
/** /**
* shutdown - shutdown socket connection * shutdown - shutdown socket connection
* @sock: socket structure * @sock: socket structure
* @how: direction to close (always treated as read + write) * @how: direction to close (unused; always treated as read + write)
* *
* Terminates connection (if necessary), then purges socket's receive queue. * Terminates connection (if necessary), then purges socket's receive queue.
* *
...@@ -1469,7 +1483,8 @@ static int shutdown(struct socket *sock, int how) ...@@ -1469,7 +1483,8 @@ static int shutdown(struct socket *sock, int how)
* Returns 0 on success, errno otherwise * Returns 0 on success, errno otherwise
*/ */
static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol) static int setsockopt(struct socket *sock,
int lvl, int opt, char __user *ov, int ol)
{ {
struct tipc_sock *tsock = tipc_sk(sock->sk); struct tipc_sock *tsock = tipc_sk(sock->sk);
u32 value; u32 value;
...@@ -1525,7 +1540,8 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol) ...@@ -1525,7 +1540,8 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol)
* Returns 0 on success, errno otherwise * Returns 0 on success, errno otherwise
*/ */
static int getsockopt(struct socket *sock, int lvl, int opt, char *ov, int *ol) static int getsockopt(struct socket *sock,
int lvl, int opt, char __user *ov, int *ol)
{ {
struct tipc_sock *tsock = tipc_sk(sock->sk); struct tipc_sock *tsock = tipc_sk(sock->sk);
int len; int len;
......
...@@ -266,7 +266,8 @@ static void subscr_subscribe(struct tipc_subscr *s, ...@@ -266,7 +266,8 @@ static void subscr_subscribe(struct tipc_subscr *s,
/* Refuse subscription if global limit exceeded */ /* Refuse subscription if global limit exceeded */
if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) { if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
warn("Failed: max %u subscriptions\n", tipc_max_subscriptions); warn("Subscription rejected, subscription limit reached (%u)\n",
tipc_max_subscriptions);
subscr_terminate(subscriber); subscr_terminate(subscriber);
return; return;
} }
...@@ -274,8 +275,8 @@ static void subscr_subscribe(struct tipc_subscr *s, ...@@ -274,8 +275,8 @@ static void subscr_subscribe(struct tipc_subscr *s,
/* Allocate subscription object */ /* Allocate subscription object */
sub = kmalloc(sizeof(*sub), GFP_ATOMIC); sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
if (sub == NULL) { if (!sub) {
warn("Memory squeeze; ignoring subscription\n"); warn("Subscription rejected, no memory\n");
subscr_terminate(subscriber); subscr_terminate(subscriber);
return; return;
} }
...@@ -298,8 +299,7 @@ static void subscr_subscribe(struct tipc_subscr *s, ...@@ -298,8 +299,7 @@ static void subscr_subscribe(struct tipc_subscr *s,
if ((((sub->filter != TIPC_SUB_PORTS) if ((((sub->filter != TIPC_SUB_PORTS)
&& (sub->filter != TIPC_SUB_SERVICE))) && (sub->filter != TIPC_SUB_SERVICE)))
|| (sub->seq.lower > sub->seq.upper)) { || (sub->seq.lower > sub->seq.upper)) {
warn("Rejecting illegal subscription %u,%u,%u\n", warn("Subscription rejected, illegal request\n");
sub->seq.type, sub->seq.lower, sub->seq.upper);
kfree(sub); kfree(sub);
subscr_terminate(subscriber); subscr_terminate(subscriber);
return; return;
...@@ -387,7 +387,7 @@ static void subscr_named_msg_event(void *usr_handle, ...@@ -387,7 +387,7 @@ static void subscr_named_msg_event(void *usr_handle,
dbg("subscr_named_msg_event: orig = %x own = %x,\n", dbg("subscr_named_msg_event: orig = %x own = %x,\n",
orig->node, tipc_own_addr); orig->node, tipc_own_addr);
if (size && (size != sizeof(struct tipc_subscr))) { if (size && (size != sizeof(struct tipc_subscr))) {
warn("Received tipc_subscr of invalid size\n"); warn("Subscriber rejected, invalid subscription size\n");
return; return;
} }
...@@ -395,7 +395,7 @@ static void subscr_named_msg_event(void *usr_handle, ...@@ -395,7 +395,7 @@ static void subscr_named_msg_event(void *usr_handle,
subscriber = kmalloc(sizeof(struct subscriber), GFP_ATOMIC); subscriber = kmalloc(sizeof(struct subscriber), GFP_ATOMIC);
if (subscriber == NULL) { if (subscriber == NULL) {
warn("Memory squeeze; ignoring subscriber setup\n"); warn("Subscriber rejected, no memory\n");
return; return;
} }
memset(subscriber, 0, sizeof(struct subscriber)); memset(subscriber, 0, sizeof(struct subscriber));
...@@ -403,7 +403,7 @@ static void subscr_named_msg_event(void *usr_handle, ...@@ -403,7 +403,7 @@ static void subscr_named_msg_event(void *usr_handle,
INIT_LIST_HEAD(&subscriber->subscriber_list); INIT_LIST_HEAD(&subscriber->subscriber_list);
subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock); subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock);
if (subscriber->ref == 0) { if (subscriber->ref == 0) {
warn("Failed to acquire subscriber reference\n"); warn("Subscriber rejected, reference table exhausted\n");
kfree(subscriber); kfree(subscriber);
return; return;
} }
...@@ -422,7 +422,7 @@ static void subscr_named_msg_event(void *usr_handle, ...@@ -422,7 +422,7 @@ static void subscr_named_msg_event(void *usr_handle,
NULL, NULL,
&subscriber->port_ref); &subscriber->port_ref);
if (subscriber->port_ref == 0) { if (subscriber->port_ref == 0) {
warn("Memory squeeze; failed to create subscription port\n"); warn("Subscriber rejected, unable to create port\n");
tipc_ref_discard(subscriber->ref); tipc_ref_discard(subscriber->ref);
kfree(subscriber); kfree(subscriber);
return; return;
......
...@@ -44,19 +44,24 @@ ...@@ -44,19 +44,24 @@
struct _zone *tipc_zone_create(u32 addr) struct _zone *tipc_zone_create(u32 addr)
{ {
struct _zone *z_ptr = NULL; struct _zone *z_ptr;
u32 z_num; u32 z_num;
if (!tipc_addr_domain_valid(addr)) if (!tipc_addr_domain_valid(addr)) {
err("Zone creation failed, invalid domain 0x%x\n", addr);
return NULL; return NULL;
}
z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC); z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC);
if (z_ptr != NULL) { if (!z_ptr) {
memset(z_ptr, 0, sizeof(*z_ptr)); warn("Zone creation failed, insufficient memory\n");
z_num = tipc_zone(addr); return NULL;
z_ptr->addr = tipc_addr(z_num, 0, 0);
tipc_net.zones[z_num] = z_ptr;
} }
memset(z_ptr, 0, sizeof(*z_ptr));
z_num = tipc_zone(addr);
z_ptr->addr = tipc_addr(z_num, 0, 0);
tipc_net.zones[z_num] = z_ptr;
return z_ptr; return z_ptr;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment