Index: sys/netinet/udp_usrreq.c =================================================================== --- sys/netinet/udp_usrreq.c +++ sys/netinet/udp_usrreq.c @@ -162,7 +162,7 @@ #ifdef INET static void udp_detach(struct socket *so); static int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *, - struct mbuf *, struct thread *); + struct mbuf *, struct thread *, int); #endif static void @@ -1084,7 +1084,7 @@ #ifdef INET static int udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *td) + struct mbuf *control, struct thread *td, int flags) { struct udpiphdr *ui; int len = m->m_pkthdr.len; @@ -1148,6 +1148,60 @@ error = EINVAL; break; } +#ifdef INET6 + if ((flags & PRUS_IPV6) != 0 && + cm->cmsg_level == IPPROTO_IPV6 && + (cm->cmsg_type == IPV6_2292PKTINFO || + cm->cmsg_type == IPV6_PKTINFO)) { + struct ifnet *ifp = NULL; + struct in6_pktinfo *pktinfo; + + if (cm->cmsg_len != + CMSG_LEN(sizeof(struct in6_pktinfo))) { + error = EINVAL; + goto err; + } + + pktinfo = (struct in6_pktinfo *)CMSG_DATA(cm); + if (!IN6_IS_ADDR_V4MAPPED(&pktinfo->ipi6_addr) || + !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) + { + error = EINVAL; + goto err; + } + /* Validate the interface index if specified. */ + if (pktinfo->ipi6_ifindex > V_if_index) { + error = ENXIO; + goto err; + } + if (pktinfo->ipi6_ifindex) { + ifp = ifnet_byindex(pktinfo->ipi6_ifindex); + if (ifp == NULL) { + error = ENXIO; + goto err; + } + } + if (ifp != NULL && + !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { + struct in_addr ia; + + ia.s_addr = + pktinfo->ipi6_addr.s6_addr32[3]; + if (in_ifhasaddr(ifp, ia) == 0) { + error = EADDRNOTAVAIL; + goto err; + } + } + bzero(&src, sizeof(src)); + src.sin_family = AF_INET; + src.sin_len = sizeof(src); + src.sin_port = inp->inp_lport; + src.sin_addr.s_addr = + pktinfo->ipi6_addr.s6_addr32[3]; + continue; + } +#endif + if (cm->cmsg_level != IPPROTO_IP) continue; @@ -1203,6 +1257,9 @@ error = ENOPROTOOPT; break; } +#ifdef INET6 +err: +#endif if (error) break; } @@ -1695,7 +1752,7 @@ inp = sotoinpcb(so); KASSERT(inp != NULL, ("udp_send: inp == NULL")); - return (udp_output(inp, m, addr, control, td)); + return (udp_output(inp, m, addr, control, td, flags)); } #endif /* INET */ Index: sys/netinet6/udp6_usrreq.c =================================================================== --- sys/netinet6/udp6_usrreq.c +++ sys/netinet6/udp6_usrreq.c @@ -784,7 +784,7 @@ in6_sin6_2_sin_in_sock((struct sockaddr *)sin6); pru = inetsw[ip_protox[nxt]].pr_usrreqs; /* addr will just be freed in sendit(). */ - return ((*pru->pru_send)(so, flags_arg, m, + return ((*pru->pru_send)(so, flags_arg | PRUS_IPV6, m, (struct sockaddr *)sin6, control, td)); } } else Index: sys/sys/protosw.h =================================================================== --- sys/sys/protosw.h +++ sys/sys/protosw.h @@ -210,6 +210,7 @@ #define PRUS_EOF 0x2 #define PRUS_MORETOCOME 0x4 #define PRUS_NOTREADY 0x8 +#define PRUS_IPV6 0x10 int (*pru_ready)(struct socket *so, struct mbuf *m, int count); int (*pru_sense)(struct socket *so, struct stat *sb); int (*pru_shutdown)(struct socket *so);