sock: break up sock_cmsg_snd into __sock_cmsg_snd and loop
To process cmsg's of the SOL_SOCKET level in addition to cmsgs of another level, protocols can call sock_cmsg_send(). This causes a double walk on the cmsghdr list, one for SOL_SOCKET and one for the other level. Extract the inner demultiplex logic from the loop that walks the list, to allow having this called directly from a walker in the protocol specific code. Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
833716e0ed
commit
39771b127b
|
@ -1420,6 +1420,8 @@ struct sockcm_cookie {
|
|||
u32 mark;
|
||||
};
|
||||
|
||||
int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg,
|
||||
struct sockcm_cookie *sockc);
|
||||
int sock_cmsg_send(struct sock *sk, struct msghdr *msg,
|
||||
struct sockcm_cookie *sockc);
|
||||
|
||||
|
|
|
@ -1866,27 +1866,38 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
|
|||
}
|
||||
EXPORT_SYMBOL(sock_alloc_send_skb);
|
||||
|
||||
int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg,
|
||||
struct sockcm_cookie *sockc)
|
||||
{
|
||||
switch (cmsg->cmsg_type) {
|
||||
case SO_MARK:
|
||||
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32)))
|
||||
return -EINVAL;
|
||||
sockc->mark = *(u32 *)CMSG_DATA(cmsg);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(__sock_cmsg_send);
|
||||
|
||||
int sock_cmsg_send(struct sock *sk, struct msghdr *msg,
|
||||
struct sockcm_cookie *sockc)
|
||||
{
|
||||
struct cmsghdr *cmsg;
|
||||
int ret;
|
||||
|
||||
for_each_cmsghdr(cmsg, msg) {
|
||||
if (!CMSG_OK(msg, cmsg))
|
||||
return -EINVAL;
|
||||
if (cmsg->cmsg_level != SOL_SOCKET)
|
||||
continue;
|
||||
switch (cmsg->cmsg_type) {
|
||||
case SO_MARK:
|
||||
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32)))
|
||||
return -EINVAL;
|
||||
sockc->mark = *(u32 *)CMSG_DATA(cmsg);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = __sock_cmsg_send(sk, msg, cmsg, sockc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue