|
@@ -186,7 +186,8 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
|
|
|
}
|
|
|
EXPORT_SYMBOL(ip_cmsg_recv);
|
|
|
|
|
|
-int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
|
|
|
+int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc,
|
|
|
+ bool allow_ipv6)
|
|
|
{
|
|
|
int err, val;
|
|
|
struct cmsghdr *cmsg;
|
|
@@ -194,6 +195,22 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
|
|
|
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
|
|
if (!CMSG_OK(msg, cmsg))
|
|
|
return -EINVAL;
|
|
|
+#if defined(CONFIG_IPV6)
|
|
|
+ if (allow_ipv6 &&
|
|
|
+ cmsg->cmsg_level == SOL_IPV6 &&
|
|
|
+ cmsg->cmsg_type == IPV6_PKTINFO) {
|
|
|
+ struct in6_pktinfo *src_info;
|
|
|
+
|
|
|
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(*src_info)))
|
|
|
+ return -EINVAL;
|
|
|
+ src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
|
|
|
+ if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
|
|
|
+ return -EINVAL;
|
|
|
+ ipc->oif = src_info->ipi6_ifindex;
|
|
|
+ ipc->addr = src_info->ipi6_addr.s6_addr32[3];
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+#endif
|
|
|
if (cmsg->cmsg_level != SOL_IP)
|
|
|
continue;
|
|
|
switch (cmsg->cmsg_type) {
|