|
@@ -377,10 +377,12 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
|
|
|
sin->sin6_family = AF_INET6;
|
|
|
sin->sin6_flowinfo = 0;
|
|
|
sin->sin6_port = 0;
|
|
|
+ if (np->rxopt.all)
|
|
|
+ ip6_datagram_recv_common_ctl(sk, msg, skb);
|
|
|
if (skb->protocol == htons(ETH_P_IPV6)) {
|
|
|
sin->sin6_addr = ipv6_hdr(skb)->saddr;
|
|
|
if (np->rxopt.all)
|
|
|
- ip6_datagram_recv_ctl(sk, msg, skb);
|
|
|
+ ip6_datagram_recv_specific_ctl(sk, msg, skb);
|
|
|
sin->sin6_scope_id =
|
|
|
ipv6_iface_scope_id(&sin->sin6_addr,
|
|
|
IP6CB(skb)->iif);
|
|
@@ -471,20 +473,34 @@ out:
|
|
|
}
|
|
|
|
|
|
|
|
|
-int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
|
|
|
- struct sk_buff *skb)
|
|
|
+void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
|
|
|
+ struct sk_buff *skb)
|
|
|
{
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
- struct inet6_skb_parm *opt = IP6CB(skb);
|
|
|
- unsigned char *nh = skb_network_header(skb);
|
|
|
+ bool is_ipv6 = skb->protocol == htons(ETH_P_IPV6);
|
|
|
|
|
|
if (np->rxopt.bits.rxinfo) {
|
|
|
struct in6_pktinfo src_info;
|
|
|
|
|
|
- src_info.ipi6_ifindex = opt->iif;
|
|
|
- src_info.ipi6_addr = ipv6_hdr(skb)->daddr;
|
|
|
+ if (is_ipv6) {
|
|
|
+ src_info.ipi6_ifindex = IP6CB(skb)->iif;
|
|
|
+ src_info.ipi6_addr = ipv6_hdr(skb)->daddr;
|
|
|
+ } else {
|
|
|
+ src_info.ipi6_ifindex =
|
|
|
+ PKTINFO_SKB_CB(skb)->ipi_ifindex;
|
|
|
+ ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
|
|
|
+ &src_info.ipi6_addr);
|
|
|
+ }
|
|
|
put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
+ struct inet6_skb_parm *opt = IP6CB(skb);
|
|
|
+ unsigned char *nh = skb_network_header(skb);
|
|
|
|
|
|
if (np->rxopt.bits.rxhlim) {
|
|
|
int hlim = ipv6_hdr(skb)->hop_limit;
|
|
@@ -602,7 +618,13 @@ int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
|
|
|
put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6);
|
|
|
}
|
|
|
}
|
|
|
- return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ ip6_datagram_recv_common_ctl(sk, msg, skb);
|
|
|
+ ip6_datagram_recv_specific_ctl(sk, msg, skb);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl);
|
|
|
|