[NETLINK]: Use group numbers instead of bitmasks internally Using the group number allows increasing the number of groups without beeing limited by the size of the bitmask. It introduces one limitation for netlink users: messages can't be broadcasted to multiple groups anymore, however this feature was never used inside the kernel.
Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]> --- commit ea41e53e0de17bc1079aab5f5342485532473f19 tree a9bebd307d68f591be4f7e95b5e4380bea216634 parent d4bee7f6d8cfb6458de0f700c115f87bda9c1448 author Patrick McHardy <[EMAIL PROTECTED]> Mon, 15 Aug 2005 02:04:57 +0200 committer Patrick McHardy <[EMAIL PROTECTED]> Mon, 15 Aug 2005 02:04:57 +0200 include/linux/netlink.h | 2 +- net/netlink/af_netlink.c | 35 ++++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -107,7 +107,7 @@ struct netlink_skb_parms struct ucred creds; /* Skb credentials */ __u32 pid; __u32 dst_pid; - __u32 dst_groups; + __u32 dst_group; kernel_cap_t eff_cap; __u32 loginuid; /* Login (audit) uid */ }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -67,7 +67,7 @@ struct netlink_sock { u32 pid; unsigned int groups; u32 dst_pid; - unsigned int dst_groups; + u32 dst_group; unsigned long state; wait_queue_head_t wait; struct netlink_callback *cb; @@ -116,6 +116,11 @@ static atomic_t nl_table_users = ATOMIC_ static struct notifier_block *netlink_chain; +static u32 netlink_group_mask(u32 group) +{ + return group ? 1 << (group - 1) : 0; +} + static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid) { return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask]; @@ -533,7 +538,7 @@ static int netlink_connect(struct socket if (addr->sa_family == AF_UNSPEC) { sk->sk_state = NETLINK_UNCONNECTED; nlk->dst_pid = 0; - nlk->dst_groups = 0; + nlk->dst_group = 0; return 0; } if (addr->sa_family != AF_NETLINK) @@ -549,7 +554,7 @@ static int netlink_connect(struct socket if (err == 0) { sk->sk_state = NETLINK_CONNECTED; nlk->dst_pid = nladdr->nl_pid; - nlk->dst_groups = nladdr->nl_groups; + nlk->dst_group = ffs(nladdr->nl_groups); } return err; @@ -567,10 +572,10 @@ static int netlink_getname(struct socket if (peer) { nladdr->nl_pid = nlk->dst_pid; - nladdr->nl_groups = nlk->dst_groups; + nladdr->nl_groups = netlink_group_mask(nlk->dst_group); } else { nladdr->nl_pid = nlk->pid; - nladdr->nl_groups = nlk->groups; + nladdr->nl_groups = nlk->groups; } return 0; } @@ -771,7 +776,7 @@ static inline int do_one_broadcast(struc if (p->exclude_sk == sk) goto out; - if (nlk->pid == p->pid || !(nlk->groups & p->group)) + if (nlk->pid == p->pid || !(nlk->groups & netlink_group_mask(p->group))) goto out; if (p->failure) { @@ -867,7 +872,7 @@ static inline int do_one_set_err(struct if (sk == p->exclude_sk) goto out; - if (nlk->pid == p->pid || !(nlk->groups & p->group)) + if (nlk->pid == p->pid || !(nlk->groups & netlink_group_mask(p->group))) goto out; sk->sk_err = p->code; @@ -913,7 +918,7 @@ static int netlink_sendmsg(struct kiocb struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *addr=msg->msg_name; u32 dst_pid; - u32 dst_groups; + u32 dst_group; struct sk_buff *skb; int err; struct scm_cookie scm; @@ -931,12 +936,12 @@ static int netlink_sendmsg(struct kiocb if (addr->nl_family != AF_NETLINK) return -EINVAL; dst_pid = addr->nl_pid; - dst_groups = addr->nl_groups; - if (dst_groups && !netlink_capable(sock, NL_NONROOT_SEND)) + dst_group = ffs(addr->nl_groups); + if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND)) return -EPERM; } else { dst_pid = nlk->dst_pid; - dst_groups = nlk->dst_groups; + dst_group = nlk->dst_group; } if (!nlk->pid) { @@ -955,7 +960,7 @@ static int netlink_sendmsg(struct kiocb NETLINK_CB(skb).pid = nlk->pid; NETLINK_CB(skb).dst_pid = dst_pid; - NETLINK_CB(skb).dst_groups = dst_groups; + NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); @@ -977,9 +982,9 @@ static int netlink_sendmsg(struct kiocb goto out; } - if (dst_groups) { + if (dst_group) { atomic_inc(&skb->users); - netlink_broadcast(sk, skb, dst_pid, dst_groups, GFP_KERNEL); + netlink_broadcast(sk, skb, dst_pid, dst_group, GFP_KERNEL); } err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); @@ -1025,7 +1030,7 @@ static int netlink_recvmsg(struct kiocb addr->nl_family = AF_NETLINK; addr->nl_pad = 0; addr->nl_pid = NETLINK_CB(skb).pid; - addr->nl_groups = NETLINK_CB(skb).dst_groups; + addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group); msg->msg_namelen = sizeof(*addr); }