void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info) { struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; struct net_device *dev = skb->dev; struct in6_addr *saddr = &hdr->saddr; struct in6_addr *daddr = &hdr->daddr; struct udphdr *uh = (struct udphdr*)(skb->data+offset); struct sock *sk; int err; sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex); if (sk == NULL) return; if (!icmpv6_err_convert(type, code, &err) && !sk->net_pinfo.af_inet6.recverr) goto out; if (sk->state!=TCP_ESTABLISHED && !sk->net_pinfo.af_inet6.recverr) goto out; if (sk->net_pinfo.af_inet6.recverr) ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); sk->err = err; sk->error_report(sk); out: sock_put(sk); }
void rawv6_err(struct sock *sk, struct sk_buff *skb, struct ipv6hdr *hdr, struct inet6_skb_parm *opt, int type, int code, unsigned char *buff, u32 info) { int err; int harderr; if (buff > skb->tail) return; /* Report error on raw socket, if: 1. User requested recverr. 2. Socket is connected (otherwise the error indication is useless without recverr and error is hard. */ if (!sk->net_pinfo.af_inet6.recverr && sk->state != TCP_ESTABLISHED) return; harderr = icmpv6_err_convert(type, code, &err); if (type == ICMPV6_PKT_TOOBIG) harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO); if (sk->net_pinfo.af_inet6.recverr) ipv6_icmp_error(sk, skb, err, 0, ntohl(info), buff); if (sk->net_pinfo.af_inet6.recverr || harderr) { sk->err = err; sk->error_report(sk); } }