+ if (sopt->sopt_level != IPPROTO_IPV6) {
+ return EINVAL;
+ }
+
+ switch (sopt->sopt_name) {
+ case IPV6_UNICAST_HOPS:
+ case IPV6_CHECKSUM:
+ case IPV6_V6ONLY:
+ case IPV6_USE_MIN_MTU:
+ case IPV6_RECVRTHDR:
+ case IPV6_RECVPKTINFO:
+ case IPV6_RECVHOPLIMIT:
+ case IPV6_PATHMTU:
+ case IPV6_PKTINFO:
+ case IPV6_HOPLIMIT:
+ case IPV6_HOPOPTS:
+ case IPV6_DSTOPTS:
+ case IPV6_MULTICAST_IF:
+ case IPV6_MULTICAST_HOPS:
+ case IPV6_MULTICAST_LOOP:
+ case IPV6_JOIN_GROUP:
+ case IPV6_LEAVE_GROUP:
+ case IPV6_PORTRANGE:
+ case IPV6_IPSEC_POLICY:
+ case IPV6_RECVTCLASS:
+ case IPV6_TCLASS:
+ case IPV6_2292PKTOPTIONS:
+ case IPV6_2292PKTINFO:
+ case IPV6_2292HOPLIMIT:
+ case IPV6_2292HOPOPTS:
+ case IPV6_2292DSTOPTS:
+ case IPV6_2292RTHDR:
+ case IPV6_BOUND_IF:
+ case IPV6_NO_IFT_CELLULAR:
+
+ return ip6_ctloutput(so, sopt);
+
+ default:
+ return EPERM;
+ }
+}
+
+__private_extern__ int
+icmp6_dgram_send(struct socket *so, int flags, struct mbuf *m,
+ struct sockaddr *nam, struct mbuf *control, struct proc *p)
+{
+#pragma unused(flags, p)
+ int error = 0;
+ struct inpcb *inp = sotoinpcb(so);
+ struct sockaddr_in6 tmp;
+ struct sockaddr_in6 *dst = (struct sockaddr_in6 *)(void *)nam;
+ struct icmp6_hdr *icmp6;
+
+ if (inp == NULL
+#if NECP
+ || (necp_socket_should_use_flow_divert(inp))
+#endif /* NECP */
+ ) {
+ error = (inp == NULL ? EINVAL : EPROTOTYPE);
+ goto bad;
+ }
+
+ if (kauth_cred_issuser(so->so_cred)) {
+ return rip6_output(m, so, SIN6(nam), control, 0);
+ }
+
+ /* always copy sockaddr to avoid overwrites */
+ if (so->so_state & SS_ISCONNECTED) {
+ if (nam != NULL) {
+ error = EISCONN;
+ goto bad;
+ }
+ /* XXX */
+ bzero(&tmp, sizeof(tmp));
+ tmp.sin6_family = AF_INET6;
+ tmp.sin6_len = sizeof(struct sockaddr_in6);
+ bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
+ sizeof(struct in6_addr));
+ dst = &tmp;
+ } else {
+ if (nam == NULL) {
+ error = ENOTCONN;
+ goto bad;
+ }
+ tmp = *(struct sockaddr_in6 *)(void *)nam;
+ dst = &tmp;
+ }