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;
|
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,
|
int sock_cmsg_send(struct sock *sk, struct msghdr *msg,
|
||||||
struct sockcm_cookie *sockc);
|
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);
|
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,
|
int sock_cmsg_send(struct sock *sk, struct msghdr *msg,
|
||||||
struct sockcm_cookie *sockc)
|
struct sockcm_cookie *sockc)
|
||||||
{
|
{
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
for_each_cmsghdr(cmsg, msg) {
|
for_each_cmsghdr(cmsg, msg) {
|
||||||
if (!CMSG_OK(msg, cmsg))
|
if (!CMSG_OK(msg, cmsg))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (cmsg->cmsg_level != SOL_SOCKET)
|
if (cmsg->cmsg_level != SOL_SOCKET)
|
||||||
continue;
|
continue;
|
||||||
switch (cmsg->cmsg_type) {
|
ret = __sock_cmsg_send(sk, msg, cmsg, sockc);
|
||||||
case SO_MARK:
|
if (ret)
|
||||||
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
return ret;
|
||||||
return -EPERM;
|
|
||||||
if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32)))
|
|
||||||
return -EINVAL;
|
|
||||||
sockc->mark = *(u32 *)CMSG_DATA(cmsg);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user