This patch adds an repair mode for netlink sockets. sendmsg queues messages into a receive queue if a socket is in the repair mode. --- include/uapi/linux/netlink.h | 19 ++++++++++------- net/netlink/af_netlink.c | 51 +++++++++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 23 deletions(-)
diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index 3e34b7d..56ddadf 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -101,14 +101,17 @@ struct nlmsgerr { struct nlmsghdr msg; }; -#define NETLINK_ADD_MEMBERSHIP 1 -#define NETLINK_DROP_MEMBERSHIP 2 -#define NETLINK_PKTINFO 3 -#define NETLINK_BROADCAST_ERROR 4 -#define NETLINK_NO_ENOBUFS 5 -#define NETLINK_RX_RING 6 -#define NETLINK_TX_RING 7 -#define NETLINK_LISTEN_ALL_NSID 8 +#define NETLINK_ADD_MEMBERSHIP 1 +#define NETLINK_DROP_MEMBERSHIP 2 +#define NETLINK_PKTINFO 3 +#define NETLINK_BROADCAST_ERROR 4 +#define NETLINK_NO_ENOBUFS 5 +#define NETLINK_RX_RING 6 +#define NETLINK_TX_RING 7 +#define NETLINK_LISTEN_ALL_NSID 8 +#define NETLINK_LIST_MEMBERSHIPS 9 +#define NETLINK_CAP_ACK 10 +#define NETLINK_REPAIR 11 struct nl_pktinfo { __u32 group; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 79526e5..113e2ae 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -83,6 +83,8 @@ struct listeners { #define NETLINK_F_BROADCAST_SEND_ERROR 0x4 #define NETLINK_F_RECV_NO_ENOBUFS 0x8 #define NETLINK_F_LISTEN_ALL_NSID 0x10 +#define NETLINK_F_CAP_ACK 0x20 +#define NETLINK_F_REPAIR 0x40 static inline int netlink_is_kernel(struct sock *sk) { @@ -1744,6 +1746,7 @@ static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb, int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 portid, int nonblock) { + struct netlink_sock *nlk = nlk_sk(ssk); struct sock *sk; int err; long timeo; @@ -1752,19 +1755,24 @@ int netlink_unicast(struct sock *ssk, struct sk_buff *skb, timeo = sock_sndtimeo(ssk, nonblock); retry: - sk = netlink_getsockbyportid(ssk, portid); - if (IS_ERR(sk)) { - kfree_skb(skb); - return PTR_ERR(sk); - } - if (netlink_is_kernel(sk)) - return netlink_unicast_kernel(sk, skb, ssk); + if (nlk->flags & NETLINK_F_REPAIR) { + sk = ssk; + sock_hold(sk); + } else { + sk = netlink_getsockbyportid(ssk, portid); + if (IS_ERR(sk)) { + kfree_skb(skb); + return PTR_ERR(sk); + } + if (netlink_is_kernel(sk)) + return netlink_unicast_kernel(sk, skb, ssk); - if (sk_filter(sk, skb)) { - err = skb->len; - kfree_skb(skb); - sock_put(sk); - return err; + if (sk_filter(sk, skb)) { + err = skb->len; + kfree_skb(skb); + sock_put(sk); + return err; + } } err = netlink_attachskb(sk, skb, &timeo, ssk); @@ -2126,6 +2134,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, return -EFAULT; switch (optname) { + case NETLINK_REPAIR: + if (val) + nlk->flags |= NETLINK_F_REPAIR; + else + nlk->flags &= ~NETLINK_F_REPAIR; + err = 0; + break; case NETLINK_PKTINFO: if (val) nlk->flags |= NETLINK_F_RECV_PKTINFO; @@ -2288,6 +2303,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, int err; struct scm_cookie scm; u32 netlink_skb_flags = 0; + bool repair = nlk->flags & NETLINK_F_REPAIR; if (msg->msg_flags&MSG_OOB) return -EOPNOTSUPP; @@ -2307,7 +2323,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, dst_group = ffs(addr->nl_groups); err = -EPERM; if ((dst_group || dst_portid) && - !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) + !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND && + !repair)) goto out; netlink_skb_flags |= NETLINK_SKB_DST; } else { @@ -2336,7 +2353,11 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, if (skb == NULL) goto out; - NETLINK_CB(skb).portid = nlk->portid; + if (unlikely(repair)) + NETLINK_CB(skb).portid = dst_portid; + else + NETLINK_CB(skb).portid = nlk->portid; + NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).creds = siocb->scm->creds; NETLINK_CB(skb).flags = netlink_skb_flags; @@ -2353,7 +2374,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; } - if (dst_group) { + if (dst_group && !repair) { atomic_inc(&skb->users); netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL); } -- 2.5.5 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel