|
@@ -2122,8 +2122,10 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb,
|
|
|
(!sk_conn && msg_connected(hdr)) ||
|
|
|
(!grp && msg_in_group(hdr)))
|
|
|
err = TIPC_ERR_NO_PORT;
|
|
|
- else if (sk_rmem_alloc_get(sk) + skb->truesize >= limit)
|
|
|
+ else if (sk_rmem_alloc_get(sk) + skb->truesize >= limit) {
|
|
|
+ atomic_inc(&sk->sk_drops);
|
|
|
err = TIPC_ERR_OVERLOAD;
|
|
|
+ }
|
|
|
|
|
|
if (unlikely(err)) {
|
|
|
tipc_skb_reject(net, err, skb, xmitq);
|
|
@@ -2202,6 +2204,7 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
|
|
|
|
|
|
/* Overload => reject message back to sender */
|
|
|
onode = tipc_own_addr(sock_net(sk));
|
|
|
+ atomic_inc(&sk->sk_drops);
|
|
|
if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD))
|
|
|
__skb_queue_tail(xmitq, skb);
|
|
|
break;
|
|
@@ -3160,16 +3163,33 @@ msg_full:
|
|
|
return -EMSGSIZE;
|
|
|
}
|
|
|
|
|
|
+static int __tipc_nl_add_sk_info(struct sk_buff *skb, struct tipc_sock
|
|
|
+ *tsk)
|
|
|
+{
|
|
|
+ struct net *net = sock_net(skb->sk);
|
|
|
+ struct tipc_net *tn = tipc_net(net);
|
|
|
+ struct sock *sk = &tsk->sk;
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_SOCK_REF, tsk->portid) ||
|
|
|
+ nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tn->own_addr))
|
|
|
+ return -EMSGSIZE;
|
|
|
+
|
|
|
+ if (tipc_sk_connected(sk)) {
|
|
|
+ if (__tipc_nl_add_sk_con(skb, tsk))
|
|
|
+ return -EMSGSIZE;
|
|
|
+ } else if (!list_empty(&tsk->publications)) {
|
|
|
+ if (nla_put_flag(skb, TIPC_NLA_SOCK_HAS_PUBL))
|
|
|
+ return -EMSGSIZE;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* Caller should hold socket lock for the passed tipc socket. */
|
|
|
static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
|
|
|
struct tipc_sock *tsk)
|
|
|
{
|
|
|
- int err;
|
|
|
- void *hdr;
|
|
|
struct nlattr *attrs;
|
|
|
- struct net *net = sock_net(skb->sk);
|
|
|
- struct tipc_net *tn = net_generic(net, tipc_net_id);
|
|
|
- struct sock *sk = &tsk->sk;
|
|
|
+ void *hdr;
|
|
|
|
|
|
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
|
|
&tipc_genl_family, NLM_F_MULTI, TIPC_NL_SOCK_GET);
|
|
@@ -3179,19 +3199,10 @@ static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
|
|
|
attrs = nla_nest_start(skb, TIPC_NLA_SOCK);
|
|
|
if (!attrs)
|
|
|
goto genlmsg_cancel;
|
|
|
- if (nla_put_u32(skb, TIPC_NLA_SOCK_REF, tsk->portid))
|
|
|
- goto attr_msg_cancel;
|
|
|
- if (nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tn->own_addr))
|
|
|
+
|
|
|
+ if (__tipc_nl_add_sk_info(skb, tsk))
|
|
|
goto attr_msg_cancel;
|
|
|
|
|
|
- if (tipc_sk_connected(sk)) {
|
|
|
- err = __tipc_nl_add_sk_con(skb, tsk);
|
|
|
- if (err)
|
|
|
- goto attr_msg_cancel;
|
|
|
- } else if (!list_empty(&tsk->publications)) {
|
|
|
- if (nla_put_flag(skb, TIPC_NLA_SOCK_HAS_PUBL))
|
|
|
- goto attr_msg_cancel;
|
|
|
- }
|
|
|
nla_nest_end(skb, attrs);
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
|
@@ -3205,16 +3216,19 @@ msg_cancel:
|
|
|
return -EMSGSIZE;
|
|
|
}
|
|
|
|
|
|
-int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
+int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb,
|
|
|
+ int (*skb_handler)(struct sk_buff *skb,
|
|
|
+ struct netlink_callback *cb,
|
|
|
+ struct tipc_sock *tsk))
|
|
|
{
|
|
|
- int err;
|
|
|
- struct tipc_sock *tsk;
|
|
|
- const struct bucket_table *tbl;
|
|
|
- struct rhash_head *pos;
|
|
|
struct net *net = sock_net(skb->sk);
|
|
|
- struct tipc_net *tn = net_generic(net, tipc_net_id);
|
|
|
- u32 tbl_id = cb->args[0];
|
|
|
+ struct tipc_net *tn = tipc_net(net);
|
|
|
+ const struct bucket_table *tbl;
|
|
|
u32 prev_portid = cb->args[1];
|
|
|
+ u32 tbl_id = cb->args[0];
|
|
|
+ struct rhash_head *pos;
|
|
|
+ struct tipc_sock *tsk;
|
|
|
+ int err;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht);
|
|
@@ -3226,12 +3240,13 @@ int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- err = __tipc_nl_add_sk(skb, cb, tsk);
|
|
|
+ err = skb_handler(skb, cb, tsk);
|
|
|
if (err) {
|
|
|
prev_portid = tsk->portid;
|
|
|
spin_unlock_bh(&tsk->sk.sk_lock.slock);
|
|
|
goto out;
|
|
|
}
|
|
|
+
|
|
|
prev_portid = 0;
|
|
|
spin_unlock_bh(&tsk->sk.sk_lock.slock);
|
|
|
}
|
|
@@ -3243,6 +3258,75 @@ out:
|
|
|
|
|
|
return skb->len;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(tipc_nl_sk_walk);
|
|
|
+
|
|
|
+int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct tipc_sock *tsk,
|
|
|
+ u32 sk_filter_state,
|
|
|
+ u64 (*tipc_diag_gen_cookie)(struct sock *sk))
|
|
|
+{
|
|
|
+ struct sock *sk = &tsk->sk;
|
|
|
+ struct nlattr *attrs;
|
|
|
+ struct nlattr *stat;
|
|
|
+
|
|
|
+ /*filter response w.r.t sk_state*/
|
|
|
+ if (!(sk_filter_state & (1 << sk->sk_state)))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ attrs = nla_nest_start(skb, TIPC_NLA_SOCK);
|
|
|
+ if (!attrs)
|
|
|
+ goto msg_cancel;
|
|
|
+
|
|
|
+ if (__tipc_nl_add_sk_info(skb, tsk))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_SOCK_TYPE, (u32)sk->sk_type) ||
|
|
|
+ nla_put_u32(skb, TIPC_NLA_SOCK_TIPC_STATE, (u32)sk->sk_state) ||
|
|
|
+ nla_put_u32(skb, TIPC_NLA_SOCK_INO, sock_i_ino(sk)) ||
|
|
|
+ nla_put_u32(skb, TIPC_NLA_SOCK_UID,
|
|
|
+ from_kuid_munged(sk_user_ns(sk), sock_i_uid(sk))) ||
|
|
|
+ nla_put_u64_64bit(skb, TIPC_NLA_SOCK_COOKIE,
|
|
|
+ tipc_diag_gen_cookie(sk),
|
|
|
+ TIPC_NLA_SOCK_PAD))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+
|
|
|
+ stat = nla_nest_start(skb, TIPC_NLA_SOCK_STAT);
|
|
|
+ if (!stat)
|
|
|
+ goto attr_msg_cancel;
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_SOCK_STAT_RCVQ,
|
|
|
+ skb_queue_len(&sk->sk_receive_queue)) ||
|
|
|
+ nla_put_u32(skb, TIPC_NLA_SOCK_STAT_SENDQ,
|
|
|
+ skb_queue_len(&sk->sk_write_queue)) ||
|
|
|
+ nla_put_u32(skb, TIPC_NLA_SOCK_STAT_DROP,
|
|
|
+ atomic_read(&sk->sk_drops)))
|
|
|
+ goto stat_msg_cancel;
|
|
|
+
|
|
|
+ if (tsk->cong_link_cnt &&
|
|
|
+ nla_put_flag(skb, TIPC_NLA_SOCK_STAT_LINK_CONG))
|
|
|
+ goto stat_msg_cancel;
|
|
|
+
|
|
|
+ if (tsk_conn_cong(tsk) &&
|
|
|
+ nla_put_flag(skb, TIPC_NLA_SOCK_STAT_CONN_CONG))
|
|
|
+ goto stat_msg_cancel;
|
|
|
+
|
|
|
+ nla_nest_end(skb, stat);
|
|
|
+ nla_nest_end(skb, attrs);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+stat_msg_cancel:
|
|
|
+ nla_nest_cancel(skb, stat);
|
|
|
+attr_msg_cancel:
|
|
|
+ nla_nest_cancel(skb, attrs);
|
|
|
+msg_cancel:
|
|
|
+ return -EMSGSIZE;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(tipc_sk_fill_sock_diag);
|
|
|
+
|
|
|
+int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
+{
|
|
|
+ return tipc_nl_sk_walk(skb, cb, __tipc_nl_add_sk);
|
|
|
+}
|
|
|
|
|
|
/* Caller should hold socket lock for the passed tipc socket. */
|
|
|
static int __tipc_nl_add_sk_publ(struct sk_buff *skb,
|