Commit c1448791 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: (36 commits)
  [Bluetooth] Fix HID disconnect NULL pointer dereference
  [Bluetooth] Add missing entry for Nokia DTL-4 PCMCIA card
  [Bluetooth] Add support for newer ANYCOM USB dongles
  [NET]: Can use __get_cpu_var() instead of per_cpu() in loopback driver.
  [IPV4] inet_peer: Group together avl_left, avl_right, v4daddr to speedup lookups on some CPUS
  [TCP]: One NET_INC_STATS() could be NET_INC_STATS_BH in tcp_v4_err()
  [NETFILTER]: Missing check for CAP_NET_ADMIN in iptables compat layer
  [NETPOLL]: initialize skb for UDP
  [IPV6]: Fix route.c warnings when multiple tables are disabled.
  [TG3]: Bump driver version and release date.
  [TG3]: Add lower bound checks for tx ring size.
  [TG3]: Fix set ring params tx ring size implementation
  [NET]: reduce per cpu ram used for loopback stats
  [IPv6] route: Fix prohibit and blackhole routing decision
  [DECNET]: Fix input routing bug
  [TCP]: Bound TSO defer time
  [IPv4] fib: Remove unused fib_config members
  [IPV6]: Always copy rt->u.dst.error when copying a rt6_info.
  [IPV6]: Make IPV6_SUBTREES depend on IPV6_MULTIPLE_TABLES.
  [IPV6]: Clean up BACKTRACK().
  ...
parents ac4e0aba 7b19ffc4
......@@ -711,6 +711,7 @@ static void dtl1_release(struct pcmcia_device *link)
static struct pcmcia_device_id dtl1_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3),
PCMCIA_DEVICE_NULL
......
......@@ -118,6 +118,9 @@ static struct usb_device_id blacklist_ids[] = {
/* IBM/Lenovo ThinkPad with Broadcom chip */
{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
/* ANYCOM Bluetooth USB-200 and USB-250 */
{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
......
......@@ -58,7 +58,11 @@
#include <linux/tcp.h>
#include <linux/percpu.h>
static DEFINE_PER_CPU(struct net_device_stats, loopback_stats);
struct pcpu_lstats {
unsigned long packets;
unsigned long bytes;
};
static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
......@@ -128,7 +132,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
*/
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_device_stats *lb_stats;
struct pcpu_lstats *lb_stats;
skb_orphan(skb);
......@@ -149,16 +153,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
dev->last_rx = jiffies;
lb_stats = &per_cpu(loopback_stats, get_cpu());
lb_stats->rx_bytes += skb->len;
lb_stats->tx_bytes = lb_stats->rx_bytes;
lb_stats->rx_packets++;
lb_stats->tx_packets = lb_stats->rx_packets;
put_cpu();
/* it's OK to use __get_cpu_var() because BHs are off */
lb_stats = &__get_cpu_var(pcpu_lstats);
lb_stats->bytes += skb->len;
lb_stats->packets++;
netif_rx(skb);
return(0);
return 0;
}
static struct net_device_stats loopback_stats;
......@@ -166,20 +168,21 @@ static struct net_device_stats loopback_stats;
static struct net_device_stats *get_stats(struct net_device *dev)
{
struct net_device_stats *stats = &loopback_stats;
unsigned long bytes = 0;
unsigned long packets = 0;
int i;
memset(stats, 0, sizeof(struct net_device_stats));
for_each_possible_cpu(i) {
struct net_device_stats *lb_stats;
const struct pcpu_lstats *lb_stats;
lb_stats = &per_cpu(loopback_stats, i);
stats->rx_bytes += lb_stats->rx_bytes;
stats->tx_bytes += lb_stats->tx_bytes;
stats->rx_packets += lb_stats->rx_packets;
stats->tx_packets += lb_stats->tx_packets;
lb_stats = &per_cpu(pcpu_lstats, i);
bytes += lb_stats->bytes;
packets += lb_stats->packets;
}
stats->rx_packets = packets;
stats->tx_packets = packets;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;
return stats;
}
......
......@@ -68,8 +68,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "3.66"
#define DRV_MODULE_RELDATE "September 23, 2006"
#define DRV_MODULE_VERSION "3.67"
#define DRV_MODULE_RELDATE "October 18, 2006"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
......@@ -129,7 +129,7 @@
#define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64)
/* minimum number of free TX descriptors required to wake up TX process */
#define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4)
#define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4)
/* number of ETHTOOL_GSTATS u64's */
#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64))
......@@ -3075,10 +3075,10 @@ static void tg3_tx(struct tg3 *tp)
smp_mb();
if (unlikely(netif_queue_stopped(tp->dev) &&
(tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))) {
(tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) {
netif_tx_lock(tp->dev);
if (netif_queue_stopped(tp->dev) &&
(tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))
(tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))
netif_wake_queue(tp->dev);
netif_tx_unlock(tp->dev);
}
......@@ -3928,7 +3928,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
tp->tx_prod = entry;
if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
netif_stop_queue(dev);
if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
netif_wake_queue(tp->dev);
}
......@@ -4143,7 +4143,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
tp->tx_prod = entry;
if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
netif_stop_queue(dev);
if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
netif_wake_queue(tp->dev);
}
......@@ -8106,7 +8106,10 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1))
(ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
(ering->tx_pending <= MAX_SKB_FRAGS) ||
((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) &&
(ering->tx_pending <= (MAX_SKB_FRAGS * 3))))
return -EINVAL;
if (netif_running(dev)) {
......
......@@ -342,6 +342,8 @@ struct tcp_sock {
unsigned long last_synq_overflow;
__u32 tso_deferred;
/* Receiver side RTT estimation */
struct {
__u32 rtt;
......
......@@ -129,6 +129,7 @@ static inline unsigned int tipc_node(__u32 addr)
#define TIPC_SUB_PORTS 0x01 /* filter for port availability */
#define TIPC_SUB_SERVICE 0x02 /* filter for service availability */
#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */
#if 0
/* The following filter options are not currently implemented */
#define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */
......
......@@ -17,14 +17,15 @@
struct inet_peer
{
/* group together avl_left,avl_right,v4daddr to speedup lookups */
struct inet_peer *avl_left, *avl_right;
__be32 v4daddr; /* peer's address */
__u16 avl_height;
__u16 ip_id_count; /* IP ID for the next packet */
struct inet_peer *unused_next, **unused_prevp;
__u32 dtime; /* the time of last use of not
* referenced entries */
atomic_t refcnt;
__be32 v4daddr; /* peer's address */
__u16 avl_height;
__u16 ip_id_count; /* IP ID for the next packet */
atomic_t rid; /* Frag reception counter */
__u32 tcp_ts;
unsigned long tcp_ts_stamp;
......
......@@ -36,13 +36,6 @@ struct route_info {
#define RT6_LOOKUP_F_REACHABLE 0x2
#define RT6_LOOKUP_F_HAS_SADDR 0x4
struct pol_chain {
int type;
int priority;
struct fib6_node *rules;
struct pol_chain *next;
};
extern struct rt6_info ip6_null_entry;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
......
......@@ -21,17 +21,14 @@
#include <net/fib_rules.h>
struct fib_config {
u8 fc_family;
u8 fc_dst_len;
u8 fc_src_len;
u8 fc_tos;
u8 fc_protocol;
u8 fc_scope;
u8 fc_type;
/* 1 byte unused */
/* 3 bytes unused */
u32 fc_table;
__be32 fc_dst;
__be32 fc_src;
__be32 fc_gw;
int fc_oif;
u32 fc_flags;
......
......@@ -507,12 +507,10 @@ static int hidp_session(void *arg)
hidp_del_timer(session);
if (intr_sk->sk_state != BT_CONNECTED)
wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ);
fput(session->intr_sock->file);
wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ);
wait_event_timeout(*(ctrl_sk->sk_sleep),
(ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
fput(session->ctrl_sock->file);
......
......@@ -335,13 +335,13 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
memcpy(skb->data, msg, len);
skb->len += len;
udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
skb->h.uh = udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
udph->check = 0;
iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
skb->nh.iph = iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
/* iph->version = 4; iph->ihl = 5; */
put_unaligned(0x45, (unsigned char *)iph);
......@@ -357,8 +357,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
eth->h_proto = htons(ETH_P_IP);
skb->mac.raw = skb->data;
skb->protocol = eth->h_proto = htons(ETH_P_IP);
memcpy(eth->h_source, np->local_mac, 6);
memcpy(eth->h_dest, np->remote_mac, 6);
......
......@@ -1275,7 +1275,6 @@ static int dn_route_input_slow(struct sk_buff *skb)
goto e_inval;
res.type = RTN_LOCAL;
flags |= RTCF_DIRECTSRC;
} else {
__le16 src_map = fl.fld_src;
free_res = 1;
......@@ -1346,7 +1345,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
goto make_route;
/* Packet was intra-ethernet, so we know its on-link */
if (cb->rt_flags | DN_RT_F_IE) {
if (cb->rt_flags & DN_RT_F_IE) {
gateway = cb->src;
flags |= RTCF_DIRECTSRC;
goto make_route;
......
......@@ -482,9 +482,7 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
memset(cfg, 0, sizeof(*cfg));
rtm = nlmsg_data(nlh);
cfg->fc_family = rtm->rtm_family;
cfg->fc_dst_len = rtm->rtm_dst_len;
cfg->fc_src_len = rtm->rtm_src_len;
cfg->fc_tos = rtm->rtm_tos;
cfg->fc_table = rtm->rtm_table;
cfg->fc_protocol = rtm->rtm_protocol;
......@@ -501,9 +499,6 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
case RTA_DST:
cfg->fc_dst = nla_get_be32(attr);
break;
case RTA_SRC:
cfg->fc_src = nla_get_be32(attr);
break;
case RTA_OIF:
cfg->fc_oif = nla_get_u32(attr);
break;
......
......@@ -1932,6 +1932,9 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{
int ret;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
switch (cmd) {
case IPT_SO_GET_INFO:
ret = get_info(user, len, 1);
......
......@@ -373,7 +373,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
seq = ntohl(th->seq);
if (sk->sk_state != TCP_LISTEN &&
!between(seq, tp->snd_una, tp->snd_nxt)) {
NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS);
NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
goto out;
}
......
......@@ -1096,10 +1096,14 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
u32 send_win, cong_win, limit, in_flight;
if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
return 0;
goto send_now;
if (icsk->icsk_ca_state != TCP_CA_Open)
return 0;
goto send_now;
/* Defer for less than two clock ticks. */
if (!tp->tso_deferred && ((jiffies<<1)>>1) - (tp->tso_deferred>>1) > 1)
goto send_now;
in_flight = tcp_packets_in_flight(tp);
......@@ -1115,7 +1119,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
/* If a full-sized TSO skb can be sent, do it. */
if (limit >= 65536)
return 0;
goto send_now;
if (sysctl_tcp_tso_win_divisor) {
u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
......@@ -1125,7 +1129,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
*/
chunk /= sysctl_tcp_tso_win_divisor;
if (limit >= chunk)
return 0;
goto send_now;
} else {
/* Different approach, try not to defer past a single
* ACK. Receiver should ACK every other full sized
......@@ -1133,11 +1137,17 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
* then send now.
*/
if (limit > tcp_max_burst(tp) * tp->mss_cache)
return 0;
goto send_now;
}
/* Ok, it looks like it is advisable to defer. */
tp->tso_deferred = 1 | (jiffies<<1);
return 1;
send_now:
tp->tso_deferred = 0;
return 0;
}
/* Create a new MTU probe if we are ready.
......
......@@ -175,9 +175,16 @@ config IPV6_TUNNEL
If unsure, say N.
config IPV6_MULTIPLE_TABLES
bool "IPv6: Multiple Routing Tables"
depends on IPV6 && EXPERIMENTAL
select FIB_RULES
---help---
Support multiple routing tables.
config IPV6_SUBTREES
bool "IPv6: source address based routing"
depends on IPV6 && EXPERIMENTAL
depends on IPV6_MULTIPLE_TABLES
---help---
Enable routing by source address or prefix.
......@@ -189,13 +196,6 @@ config IPV6_SUBTREES
If unsure, say N.
config IPV6_MULTIPLE_TABLES
bool "IPv6: Multiple Routing Tables"
depends on IPV6 && EXPERIMENTAL
select FIB_RULES
---help---
Support multiple routing tables.
config IPV6_ROUTE_FWMARK
bool "IPv6: use netfilter MARK value as routing key"
depends on IPV6_MULTIPLE_TABLES && NETFILTER
......
......@@ -141,6 +141,10 @@ struct rt6_info ip6_null_entry = {
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct sk_buff *skb);
static int ip6_pkt_blk_hole(struct sk_buff *skb);
struct rt6_info ip6_prohibit_entry = {
.u = {
.dst = {
......@@ -150,8 +154,8 @@ struct rt6_info ip6_prohibit_entry = {
.obsolete = -1,
.error = -EACCES,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
.input = ip6_pkt_discard,
.output = ip6_pkt_discard_out,
.input = ip6_pkt_prohibit,
.output = ip6_pkt_prohibit_out,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_prohibit_entry,
}
......@@ -170,8 +174,8 @@ struct rt6_info ip6_blk_hole_entry = {
.obsolete = -1,
.error = -EINVAL,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
.input = ip6_pkt_discard,
.output = ip6_pkt_discard_out,
.input = ip6_pkt_blk_hole,
.output = ip6_pkt_blk_hole,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_blk_hole_entry,
}
......@@ -484,7 +488,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
do { \
if (rt == &ip6_null_entry) { \
struct fib6_node *pn; \
while (fn) { \
while (1) { \
if (fn->fn_flags & RTN_TL_ROOT) \
goto out; \
pn = fn->parent; \
......@@ -618,8 +622,6 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
rt->rt6i_dst.plen = 128;
rt->rt6i_flags |= RTF_CACHE;
if (rt->rt6i_flags & RTF_REJECT)
rt->u.dst.error = ort->u.dst.error;
rt->u.dst.flags |= DST_HOST;
rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
}
......@@ -1540,6 +1542,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
rt->u.dst.output = ort->u.dst.output;
memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
rt->u.dst.error = ort->u.dst.error;
rt->u.dst.dev = ort->u.dst.dev;
if (rt->u.dst.dev)
dev_hold(rt->u.dst.dev);
......@@ -1743,24 +1746,50 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
* Drop the packet on the floor
*/
static int ip6_pkt_discard(struct sk_buff *skb)
static inline int ip6_pkt_drop(struct sk_buff *skb, int code)
{
int type = ipv6_addr_type(&skb->nh.ipv6h->daddr);
if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED)
IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev);
kfree_skb(skb);
return 0;
}
static int ip6_pkt_discard(struct sk_buff *skb)
{
return ip6_pkt_drop(skb, ICMPV6_NOROUTE);
}
static int ip6_pkt_discard_out(struct sk_buff *skb)
{
skb->dev = skb->dst->dev;
return ip6_pkt_discard(skb);
}
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
static int ip6_pkt_prohibit(struct sk_buff *skb)
{
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED);
}
static int ip6_pkt_prohibit_out(struct sk_buff *skb)
{
skb->dev = skb->dst->dev;
return ip6_pkt_prohibit(skb);
}
static int ip6_pkt_blk_hole(struct sk_buff *skb)
{
kfree_skb(skb);
return 0;
}
#endif
/*
* Allocate a dst for local (unicast / anycast) address.
*/
......
......@@ -25,12 +25,14 @@
static struct dst_ops xfrm6_dst_ops;
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
{
int err = 0;
*dst = (struct xfrm_dst*)ip6_route_output(NULL, fl);
if (!*dst)
err = -ENETUNREACH;
struct dst_entry *dst = ip6_route_output(NULL, fl);
int err = dst->error;
if (!err)
*xdst = (struct xfrm_dst *) dst;
else
dst_release(dst);
return err;
}
......
......@@ -215,17 +215,17 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
}
dst = ip6_route_output(NULL, &fl);
if (dst) {
if (!dst->error) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
SCTP_DEBUG_PRINTK(
"rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
} else {
SCTP_DEBUG_PRINTK("NO ROUTE\n");
return dst;
}
return dst;
SCTP_DEBUG_PRINTK("NO ROUTE\n");
dst_release(dst);
return NULL;
}
/* Returns the number of consecutive initial bits that match in the 2 ipv6
......
......@@ -821,7 +821,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
* addrs is a pointer to an array of one or more socket addresses. Each
* address is contained in its appropriate structure (i.e. struct
* sockaddr_in or struct sockaddr_in6) the family of the address type
* must be used to distengish the address length (note that this
* must be used to distinguish the address length (note that this
* representation is termed a "packed array" of addresses). The caller
* specifies the number of addresses in the array with addrcnt.
*
......
......@@ -2,7 +2,7 @@
* net/tipc/bearer.c: TIPC bearer code
*
* Copyright (c) 1996-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -191,14 +191,14 @@ void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
if ((i < media_count) && (m_ptr->addr2str != NULL)) {
char addr_str[MAX_ADDR_STR];
tipc_printf(pb, "%s(%s) ", m_ptr->name,
tipc_printf(pb, "%s(%s)", m_ptr->name,
m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
} else {
unchar *addr = (unchar *)&a->dev_addr;
tipc_printf(pb, "UNKNOWN(%u):", media_type);
tipc_printf(pb, "UNKNOWN(%u)", media_type);
for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
tipc_printf(pb, "%02x ", addr[i]);
tipc_printf(pb, "-%02x", addr[i]);
}
}
}
......
......@@ -2,7 +2,7 @@
* net/tipc/config.c: TIPC configuration management code
*
* Copyright (c) 2002-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -613,7 +613,8 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
break;
default:
rep_tlv_buf = NULL;
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (unknown command)");
break;
}
......
......@@ -57,7 +57,7 @@ void tipc_socket_stop(void);
int tipc_netlink_start(void);
void tipc_netlink_stop(void);
#define TIPC_MOD_VER "1.6.1"
#define TIPC_MOD_VER "1.6.2"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
......@@ -90,7 +90,7 @@ int tipc_random;
atomic_t tipc_user_count = ATOMIC_INIT(0);
const char tipc_alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
/* configurable TIPC parameters */
......
......@@ -65,7 +65,7 @@
#define assert(i) BUG_ON(!(i))
struct tipc_msg;
extern struct print_buf *TIPC_CONS, *TIPC_LOG;
extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG;
extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *);
void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*);
void tipc_printf(struct print_buf *, const char *fmt, ...);
......@@ -83,9 +83,9 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
#define dbg(fmt, arg...) do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
/*
......@@ -94,11 +94,11 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
* here, or on a per .c file basis, by redefining these symbols. The following
* print buffer options are available:
*
* NULL : Output to null print buffer (i.e. print nowhere)
* TIPC_CONS : Output to system console
* TIPC_LOG : Output to TIPC log buffer
* &buf : Output to user-defined buffer (struct print_buf *)
* TIPC_TEE(&buf_a,&buf_b) : Output to two print buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG) )
* TIPC_NULL : null buffer (i.e. print nowhere)
* TIPC_CONS : system console
* TIPC_LOG : TIPC log buffer
* &buf : user-defined buffer (struct print_buf *)
* TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG))
*/
#ifndef TIPC_OUTPUT
......@@ -106,7 +106,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#endif
#ifndef DBG_OUTPUT
#define DBG_OUTPUT NULL
#define DBG_OUTPUT TIPC_NULL
#endif
#else
......@@ -136,7 +136,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#define TIPC_OUTPUT TIPC_CONS
#undef DBG_OUTPUT
#define DBG_OUTPUT NULL
#define DBG_OUTPUT TIPC_NULL
#endif
......@@ -275,11 +275,15 @@ static inline void k_term_timer(struct timer_list *timer)
/*
* TIPC message buffer code
*
* TIPC message buffer headroom leaves room for 14 byte Ethernet header,
* TIPC message buffer headroom reserves space for a link-level header
* (in case the message is sent off-node),
* while ensuring TIPC header is word aligned for quicker access
*
* The largest header currently supported is 18 bytes, which is used when
* the standard 14 byte Ethernet header has 4 added bytes for VLAN info
*/
#define BUF_HEADROOM 16u
#define BUF_HEADROOM 20u
struct tipc_skb_cb {
void *handle;
......
/*
* net/tipc/dbg.c: TIPC print buffer routines for debuggign
* net/tipc/dbg.c: TIPC print buffer routines for debugging
*
* Copyright (c) 1996-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -38,11 +38,12 @@
#include "config.h"
#include "dbg.h"
#define MAX_STRING 512
static char print_string[MAX_STRING];
static char print_string[TIPC_PB_MAX_STR];
static DEFINE_SPINLOCK(print_lock);
static struct print_buf null_buf = { NULL, 0, NULL, NULL };
struct print_buf *TIPC_NULL = &null_buf;
static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
struct print_buf *TIPC_CONS = &cons_buf;
......@@ -62,68 +63,83 @@ struct print_buf *TIPC_LOG = &log_buf;
/*
* Locking policy when using print buffers.
*
* 1) Routines of the form printbuf_XXX() rely on the caller to prevent
* simultaneous use of the print buffer(s) being manipulated.
* 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
* 'print_string' and to protect its print buffer(s).
* 3) TIPC_TEE() uses 'print_lock' to protect its print buffer(s).
* 4) Routines of the form log_XXX() uses 'print_lock' to protect TIPC_LOG.
* The following routines use 'print_lock' for protection:
* 1) tipc_printf() - to protect its print buffer(s) and 'print_string'
* 2) TIPC_TEE() - to protect its print buffer(s)
* 3) tipc_dump() - to protect its print buffer(s) and 'print_string'
* 4) tipc_log_XXX() - to protect TIPC_LOG
*
* All routines of the form tipc_printbuf_XXX() rely on the caller to prevent
* simultaneous use of the print buffer(s) being manipulated.
*/
/**
* tipc_printbuf_init - initialize print buffer to empty
* @pb: pointer to print buffer structure
* @raw: pointer to character array used by print buffer
* @size: size of character array
*
* Makes the print buffer a null device that discards anything written to it
* if the character array is too small (or absent).
*/
void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 sz)
void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
{
if (!pb || !raw || (sz < (MAX_STRING + 1)))
return;
pb->crs = pb->buf = raw;
pb->size = sz;
pb->buf = raw;
pb->crs = raw;
pb->size = size;
pb->next = NULL;
pb->buf[0] = 0;
pb->buf[sz-1] = ~0;
if (size < TIPC_PB_MIN_SIZE) {
pb->buf = NULL;
} else if (raw) {
pb->buf[0] = 0;
pb->buf[size-1] = ~0;
}
}
/**
* tipc_printbuf_reset - reinitialize print buffer to empty state
* @pb: pointer to print buffer structure
*/
void tipc_printbuf_reset(struct print_buf *pb)
{
if (pb && pb->buf)
tipc_printbuf_init(pb, pb->buf, pb->size);
tipc_printbuf_init(pb, pb->buf, pb->size);
}
/**
* tipc_printbuf_empty - test if print buffer is in empty state
* @pb: pointer to print buffer structure
*
* Returns non-zero if print buffer is empty.
*/
int tipc_printbuf_empty(struct print_buf *pb)
{
return (!pb || !pb->buf || (pb->crs == pb->buf));
return (!pb->buf || (pb->crs == pb->buf));
}
/**
* tipc_printbuf_validate - check for print buffer overflow
* @pb: pointer to print buffer structure
*
* Verifies that a print buffer has captured all data written to it.
* If data has been lost, linearize buffer and prepend an error message
*
* Returns length of print buffer data string (including trailing NULL)
* Returns length of print buffer data string (including trailing NUL)
*/
int tipc_printbuf_validate(struct print_buf *pb)
{
char *err = " *** PRINT BUFFER WRAPPED AROUND ***\n";
char *err = "\n\n*** PRINT BUFFER OVERFLOW ***\n\n";
char *cp_buf;
struct print_buf cb;
if (!pb || !pb->buf)
if (!pb->buf)
return 0;
if (pb->buf[pb->size - 1] == '\0') {
if (pb->buf[pb->size - 1] == 0) {
cp_buf = kmalloc(pb->size, GFP_ATOMIC);
if (cp_buf != NULL){
tipc_printbuf_init(&cb, cp_buf, pb->size);
......@@ -141,6 +157,8 @@ int tipc_printbuf_validate(struct print_buf *pb)
/**
* tipc_printbuf_move - move print buffer contents to another print buffer
* @pb_to: pointer to destination print buffer structure
* @pb_from: pointer to source print buffer structure
*
* Current contents of destination print buffer (if any) are discarded.
* Source print buffer becomes empty if a successful move occurs.
......@@ -152,21 +170,22 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
/* Handle the cases where contents can't be moved */
if (!pb_to || !pb_to->buf)
if (!pb_to->buf)
return;
if (!pb_from || !pb_from->buf) {
if (!pb_from->buf) {
tipc_printbuf_reset(pb_to);
return;
}
if (pb_to->size < pb_from->size) {
tipc_printbuf_reset(pb_to);
tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***");
return;
}
/* Copy data from char after cursor to end (if used) */
len = pb_from->buf + pb_from->size - pb_from->crs - 2;
if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
strcpy(pb_to->buf, pb_from->crs + 1);
......@@ -175,6 +194,7 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
pb_to->crs = pb_to->buf;
/* Copy data from start to cursor (always) */
len = pb_from->crs - pb_from->buf;
strcpy(pb_to->crs, pb_from->buf);
pb_to->crs += len;
......@@ -184,6 +204,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
/**
* tipc_printf - append formatted output to print buffer chain
* @pb: pointer to chain of print buffers (may be NULL)
* @fmt: formatted info to be printed
*/
void tipc_printf(struct print_buf *pb, const char *fmt, ...)
......@@ -195,8 +217,8 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
spin_lock_bh(&print_lock);
FORMAT(print_string, chars_to_add, fmt);
if (chars_to_add >= MAX_STRING)
strcpy(print_string, "*** STRING TOO LONG ***");
if (chars_to_add >= TIPC_PB_MAX_STR)
strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
while (pb) {
if (pb == TIPC_CONS)
......@@ -206,6 +228,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
if (chars_to_add <= chars_left) {
strcpy(pb->crs, print_string);
pb->crs += chars_to_add;
} else if (chars_to_add >= (pb->size - 1)) {
strcpy(pb->buf, print_string + chars_to_add + 1
- pb->size);
pb->crs = pb->buf + pb->size - 1;
} else {
strcpy(pb->buf, print_string + chars_left);
save_char = print_string[chars_left];
......@@ -224,6 +250,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
/**
* TIPC_TEE - perform next output operation on both print buffers
* @b0: pointer to chain of print buffers (may be NULL)
* @b1: pointer to print buffer to add to chain
*
* Returns pointer to print buffer chain.
*/
struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
......@@ -232,8 +262,6 @@ struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
if (!b0 || (b0 == b1))
return b1;
if (!b1)
return b0;
spin_lock_bh(&print_lock);
while (pb->next) {
......@@ -256,7 +284,7 @@ static void print_to_console(char *crs, int len)
int rest = len;
while (rest > 0) {
int sz = rest < MAX_STRING ? rest : MAX_STRING;
int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR;
char c = crs[sz];
crs[sz] = 0;
......@@ -275,36 +303,48 @@ static void printbuf_dump(struct print_buf *pb)
{
int len;
if (!pb->buf) {
printk("*** PRINT BUFFER NOT ALLOCATED ***");
return;
}
/* Dump print buffer from char after cursor to end (if used) */
len = pb->buf + pb->size - pb->crs - 2;
if ((pb->buf[pb->size - 1] == 0) && (len > 0))
print_to_console(pb->crs + 1, len);
/* Dump print buffer from start to cursor (always) */
len = pb->crs - pb->buf;
print_to_console(pb->buf, len);
}
/**
* tipc_dump - dump non-console print buffer(s) to console
* @pb: pointer to chain of print buffers
*/
void tipc_dump(struct print_buf *pb, const char *fmt, ...)
{
struct print_buf *pb_next;
int len;
spin_lock_bh(&print_lock);
FORMAT(TIPC_CONS->buf, len, fmt);
printk(TIPC_CONS->buf);
FORMAT(print_string, len, fmt);
printk(print_string);
for (; pb; pb = pb->next) {
if (pb == TIPC_CONS)
continue;
printk("\n---- Start of dump,%s log ----\n\n",
(pb == TIPC_LOG) ? "global" : "local");
printbuf_dump(pb);
tipc_printbuf_reset(pb);
printk("\n-------- End of dump --------\n");
if (pb != TIPC_CONS) {
printk("\n---- Start of %s log dump ----\n\n",
(pb == TIPC_LOG) ? "global" : "local");
printbuf_dump(pb);
tipc_printbuf_reset(pb);
printk("\n---- End of dump ----\n");
}
pb_next = pb->next;
pb->next = NULL;
pb = pb_next;
}
spin_unlock_bh(&print_lock);
}
......@@ -324,7 +364,8 @@ void tipc_log_stop(void)
}
/**
* tipc_log_reinit - set TIPC log print buffer to specified size
* tipc_log_reinit - (re)initialize TIPC log print buffer
* @log_size: print buffer size to use
*/
void tipc_log_reinit(int log_size)
......@@ -332,10 +373,11 @@ void tipc_log_reinit(int log_size)
tipc_log_stop();
if (log_size) {
if (log_size <= MAX_STRING)
log_size = MAX_STRING + 1;
if (log_size < TIPC_PB_MIN_SIZE)
log_size = TIPC_PB_MIN_SIZE;
spin_lock_bh(&print_lock);
tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
log_size);
spin_unlock_bh(&print_lock);
}
}
......
......@@ -2,7 +2,7 @@
* net/tipc/dbg.h: Include file for TIPC print buffer routines
*
* Copyright (c) 1997-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -37,6 +37,14 @@
#ifndef _TIPC_DBG_H
#define _TIPC_DBG_H
/**
* struct print_buf - TIPC print buffer structure
* @buf: pointer to character array containing print buffer contents
* @size: size of character array
* @crs: pointer to first unused space in character array (i.e. final NUL)
* @next: used to link print buffers when printing to more than one at a time
*/
struct print_buf {
char *buf;
u32 size;
......@@ -44,7 +52,10 @@ struct print_buf {
struct print_buf *next;
};
void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 sz);
#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */
#define TIPC_PB_MAX_STR 512 /* max printable string (with trailing NUL) */
void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 size);
void tipc_printbuf_reset(struct print_buf *pb);
int tipc_printbuf_empty(struct print_buf *pb);
int tipc_printbuf_validate(struct print_buf *pb);
......
......@@ -131,6 +131,28 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,
return buf;
}
/**
* disc_dupl_alert - issue node address duplication alert
* @b_ptr: pointer to bearer detecting duplication
* @node_addr: duplicated node address
* @media_addr: media address advertised by duplicated node
*/
static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
struct tipc_media_addr *media_addr)
{
char node_addr_str[16];
char media_addr_str[64];
struct print_buf pb;
addr_string_fill(node_addr_str, node_addr);
tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str));
tipc_media_addr_printf(&pb, media_addr);
tipc_printbuf_validate(&pb);
warn("Duplicate %s using %s seen on <%s>\n",
node_addr_str, media_addr_str, b_ptr->publ.name);
}
/**
* tipc_disc_recv_msg - handle incoming link setup message (request or response)
* @buf: buffer containing message
......@@ -157,8 +179,11 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
return;
if (!tipc_addr_node_valid(orig))
return;
if (orig == tipc_own_addr)
if (orig == tipc_own_addr) {
if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr)))
disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
return;
}
if (!in_scope(dest, tipc_own_addr))
return;
if (is_slave(tipc_own_addr) && is_slave(orig))
......@@ -170,7 +195,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
struct sk_buff *rbuf;
struct tipc_media_addr *addr;
struct node *n_ptr = tipc_node_find(orig);
int link_up;
int link_fully_up;
dbg(" in own cluster\n");
if (n_ptr == NULL) {
n_ptr = tipc_node_create(orig);
......@@ -190,14 +216,19 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
}
addr = &link->media_addr;
if (memcmp(addr, &media_addr, sizeof(*addr))) {
if (tipc_link_is_up(link) || (!link->started)) {
disc_dupl_alert(b_ptr, orig, &media_addr);
spin_unlock_bh(&n_ptr->lock);
return;
}
warn("Resetting link <%s>, peer interface address changed\n",
link->name);
memcpy(addr, &media_addr, sizeof(*addr));
tipc_link_reset(link);
}
link_up = tipc_link_is_up(link);
link_fully_up = (link->state == WORKING_WORKING);
spin_unlock_bh(&n_ptr->lock);
if ((type == DSC_RESP_MSG) || link_up)
if ((type == DSC_RESP_MSG) || link_fully_up)
return;
rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
if (rbuf != NULL) {
......
......@@ -132,7 +132,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
* allow the output from multiple links to be intermixed. For this reason
* routines of the form "dbg_link_XXX()" have been created that will capture
* debug info into a link's personal print buffer, which can then be dumped
* into the TIPC system log (LOG) upon request.
* into the TIPC system log (TIPC_LOG) upon request.
*
* To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
* of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0,
......@@ -141,7 +141,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
* when there is only a single link in the system being debugged.
*
* Notes:
* - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
* - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE
* - "l_ptr" must be valid when using dbg_link_XXX() macros
*/
......@@ -159,13 +159,13 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
static void dbg_print_link(struct link *l_ptr, const char *str)
{
if (DBG_OUTPUT)
if (DBG_OUTPUT != TIPC_NULL)
link_print(l_ptr, DBG_OUTPUT, str);
}
static void dbg_print_buf_chain(struct sk_buff *root_buf)
{
if (DBG_OUTPUT) {
if (DBG_OUTPUT != TIPC_NULL) {
struct sk_buff *buf = root_buf;
while (buf) {
......
......@@ -122,7 +122,7 @@ void tipc_named_publish(struct publication *publ)
struct sk_buff *buf;
struct distr_item *item;
list_add(&publ->local_list, &publ_root);
list_add_tail(&publ->local_list, &publ_root);
publ_cnt++;
buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
......
......@@ -648,7 +648,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network address)");
if (!tipc_nodes)
if (tipc_mode != TIPC_NET_MODE)
return tipc_cfg_reply_none();
/* Get space for all unicast links + multicast link */
......
......@@ -505,8 +505,13 @@ static void port_timeout(unsigned long ref)
struct port *p_ptr = tipc_port_lock(ref);
struct sk_buff *buf = NULL;
if (!p_ptr || !p_ptr->publ.connected)
if (!p_ptr)
return;
if (!p_ptr->publ.connected) {
tipc_port_unlock(p_ptr);
return;
}
/* Last probe answered ? */
if (p_ptr->probing_state == PROBING) {
......
......@@ -2,7 +2,7 @@
* net/tipc/socket.c: TIPC socket API
*
* Copyright (c) 2001-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -629,6 +629,9 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
return -ENOTCONN;
}
if (unlikely(m->msg_name))
return -EISCONN;
/*
* Send each iovec entry using one or more messages
*
......@@ -641,6 +644,8 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
curr_iovlen = m->msg_iovlen;
my_msg.msg_iov = &my_iov;
my_msg.msg_iovlen = 1;
my_msg.msg_flags = m->msg_flags;
my_msg.msg_name = NULL;
bytes_sent = 0;
while (curr_iovlen--) {
......@@ -1203,7 +1208,8 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
atomic_inc(&tipc_queue_size);
skb_queue_tail(&sock->sk->sk_receive_queue, buf);
wake_up_interruptible(sock->sk->sk_sleep);
if (waitqueue_active(sock->sk->sk_sleep))
wake_up_interruptible(sock->sk->sk_sleep);
return TIPC_OK;
}
......@@ -1218,7 +1224,8 @@ static void wakeupdispatch(struct tipc_port *tport)
{
struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
wake_up_interruptible(tsock->sk.sk_sleep);
if (waitqueue_active(tsock->sk.sk_sleep))
wake_up_interruptible(tsock->sk.sk_sleep);
}
/**
......
......@@ -155,7 +155,7 @@ void tipc_subscr_report_overlap(struct subscription *sub,
sub->seq.upper, found_lower, found_upper);
if (!tipc_subscr_overlap(sub, found_lower, found_upper))
return;
if (!must && (sub->filter != TIPC_SUB_PORTS))
if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
}
......@@ -176,6 +176,13 @@ static void subscr_timeout(struct subscription *sub)
if (subscriber == NULL)
return;
/* Validate timeout (in case subscription is being cancelled) */
if (sub->timeout == TIPC_WAIT_FOREVER) {
tipc_ref_unlock(subscriber_ref);
return;
}
/* Unlink subscription from name table */
tipc_nametbl_unsubscribe(sub);
......@@ -198,6 +205,20 @@ static void subscr_timeout(struct subscription *sub)
atomic_dec(&topsrv.subscription_count);
}
/**
* subscr_del - delete a subscription within a subscription list
*
* Called with subscriber locked.
*/
static void subscr_del(struct subscription *sub)
{
tipc_nametbl_unsubscribe(sub);
list_del(&sub->subscription_list);
kfree(sub);
atomic_dec(&topsrv.subscription_count);
}
/**
* subscr_terminate - terminate communication with a subscriber
*
......@@ -227,12 +248,9 @@ static void subscr_terminate(struct subscriber *subscriber)
k_cancel_timer(&sub->timer);
k_term_timer(&sub->timer);
}
tipc_nametbl_unsubscribe(sub);
list_del(&sub->subscription_list);
dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
kfree(sub);
atomic_dec(&topsrv.subscription_count);
subscr_del(sub);
}
/* Sever connection to subscriber */
......@@ -252,6 +270,49 @@ static void subscr_terminate(struct subscriber *subscriber)
kfree(subscriber);
}
/**
* subscr_cancel - handle subscription cancellation request
*
* Called with subscriber locked. Routine must temporarily release this lock
* to enable the subscription timeout routine to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
*
* Note that fields of 's' use subscriber's endianness!
*/
static void subscr_cancel(struct tipc_subscr *s,
struct subscriber *subscriber)
{
struct subscription *sub;
struct subscription *sub_temp;
int found = 0;
/* Find first matching subscription, exit if not found */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
subscription_list) {
if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
found = 1;
break;
}
}
if (!found)
return;
/* Cancel subscription timer (if used), then delete subscription */
if (sub->timeout != TIPC_WAIT_FOREVER) {
sub->timeout = TIPC_WAIT_FOREVER;
spin_unlock_bh(subscriber->lock);
k_cancel_timer(&sub->timer);
k_term_timer(&sub->timer);
spin_lock_bh(subscriber->lock);
}
dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
subscr_del(sub);
}
/**
* subscr_subscribe - create subscription for subscriber
*
......@@ -263,6 +324,21 @@ static void subscr_subscribe(struct tipc_subscr *s,
{
struct subscription *sub;
/* Determine/update subscriber's endianness */
if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
subscriber->swap = 0;
else
subscriber->swap = 1;
/* Detect & process a subscription cancellation request */
if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
subscr_cancel(s, subscriber);
return;
}
/* Refuse subscription if global limit exceeded */
if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
......@@ -281,13 +357,6 @@ static void subscr_subscribe(struct tipc_subscr *s,
return;
}
/* Determine/update subscriber's endianness */
if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
subscriber->swap = 0;
else
subscriber->swap = 1;
/* Initialize subscription object */
memset(sub, 0, sizeof(*sub));
......@@ -296,8 +365,8 @@ static void subscr_subscribe(struct tipc_subscr *s,
sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
sub->timeout = htohl(s->timeout, subscriber->swap);
sub->filter = htohl(s->filter, subscriber->swap);
if ((((sub->filter != TIPC_SUB_PORTS)
&& (sub->filter != TIPC_SUB_SERVICE)))
if ((!(sub->filter & TIPC_SUB_PORTS)
== !(sub->filter & TIPC_SUB_SERVICE))
|| (sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
......
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