Hello -

This diff splits the ctloutput functions into getopt/setopt, which could
offer more fine-grained locking.  It also removes some indentation and
imo is easier to read.

Thoughts?

Index: net/rtsock.c
===================================================================
RCS file: /cvs/src/sys/net/rtsock.c,v
retrieving revision 1.279
diff -u -p -r1.279 rtsock.c
--- net/rtsock.c        10 Jul 2018 20:28:34 -0000      1.279
+++ net/rtsock.c        18 Oct 2018 15:26:28 -0000
@@ -110,6 +110,8 @@ void        rcb_unref(void *, void *);
 int    route_output(struct mbuf *, struct socket *, struct sockaddr *,
            struct mbuf *);
 int    route_ctloutput(int, struct socket *, int, int, struct mbuf *);
+int    route_getopt(struct socket *, int, int, struct mbuf *);
+int    route_setopt(struct socket *, int, int, struct mbuf *);
 int    route_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
            struct mbuf *, struct proc *);
 void   route_input(struct mbuf *m0, struct socket *, sa_family_t);
@@ -358,69 +360,98 @@ int
 route_ctloutput(int op, struct socket *so, int level, int optname,
     struct mbuf *m)
 {
+       int error;
+
+       switch (op) {
+       case PRCO_SETOPT:
+               error = route_setopt(so, level, optname, m);
+               break;
+       case PRCO_GETOPT:
+               error = route_getopt(so, level, optname, m);
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       return error;
+}
+
+int
+route_setopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
        struct rtpcb *rop = sotortpcb(so);
        int error = 0;
        unsigned int tid, prio;
 
        if (level != AF_ROUTE)
-               return (EINVAL);
+               return EINVAL;
 
-       switch (op) {
-       case PRCO_SETOPT:
-               switch (optname) {
-               case ROUTE_MSGFILTER:
-                       if (m == NULL || m->m_len != sizeof(unsigned int))
-                               error = EINVAL;
-                       else
-                               rop->rop_msgfilter = *mtod(m, unsigned int *);
-                       break;
-               case ROUTE_TABLEFILTER:
-                       if (m == NULL || m->m_len != sizeof(unsigned int)) {
-                               error = EINVAL;
-                               break;
-                       }
-                       tid = *mtod(m, unsigned int *);
-                       if (tid != RTABLE_ANY && !rtable_exists(tid))
-                               error = ENOENT;
-                       else
-                               rop->rop_rtableid = tid;
-                       break;
-               case ROUTE_PRIOFILTER:
-                       if (m == NULL || m->m_len != sizeof(unsigned int)) {
-                               error = EINVAL;
-                               break;
-                       }
-                       prio = *mtod(m, unsigned int *);
-                       if (prio > RTP_MAX)
-                               error = EINVAL;
-                       else
-                               rop->rop_priority = prio;
-                       break;
-               default:
-                       error = ENOPROTOOPT;
+       switch (optname) {
+       case ROUTE_MSGFILTER:
+               if (m == NULL || m->m_len != sizeof(unsigned int))
+                       error = EINVAL;
+               else
+                       rop->rop_msgfilter = *mtod(m, unsigned int *);
+               break;
+       case ROUTE_TABLEFILTER:
+               if (m == NULL || m->m_len != sizeof(unsigned int)) {
+                       error = EINVAL;
                        break;
                }
+               tid = *mtod(m, unsigned int *);
+               if (tid != RTABLE_ANY && !rtable_exists(tid))
+                       error = ENOENT;
+               else
+                       rop->rop_rtableid = tid;
                break;
-       case PRCO_GETOPT:
-               switch (optname) {
-               case ROUTE_MSGFILTER:
-                       m->m_len = sizeof(unsigned int);
-                       *mtod(m, unsigned int *) = rop->rop_msgfilter;
-                       break;
-               case ROUTE_TABLEFILTER:
-                       m->m_len = sizeof(unsigned int);
-                       *mtod(m, unsigned int *) = rop->rop_rtableid;
-                       break;
-               case ROUTE_PRIOFILTER:
-                       m->m_len = sizeof(unsigned int);
-                       *mtod(m, unsigned int *) = rop->rop_priority;
-                       break;
-               default:
-                       error = ENOPROTOOPT;
+       case ROUTE_PRIOFILTER:
+               if (m == NULL || m->m_len != sizeof(unsigned int)) {
+                       error = EINVAL;
                        break;
                }
+               prio = *mtod(m, unsigned int *);
+               if (prio > RTP_MAX)
+                       error = EINVAL;
+               else
+                       rop->rop_priority = prio;
+               break;
+       default:
+               error = ENOPROTOOPT;
+               break;
        }
-       return (error);
+
+       return error;
+}
+
+int
+route_getopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
+       struct rtpcb *rop = sotortpcb(so);
+       int error = 0;
+
+       if (level != AF_ROUTE)
+               return EINVAL;
+
+       switch (optname) {
+       case ROUTE_MSGFILTER:
+               m->m_len = sizeof(unsigned int);
+               *mtod(m, unsigned int *) = rop->rop_msgfilter;
+               break;
+       case ROUTE_TABLEFILTER:
+               m->m_len = sizeof(unsigned int);
+               *mtod(m, unsigned int *) = rop->rop_rtableid;
+               break;
+       case ROUTE_PRIOFILTER:
+               m->m_len = sizeof(unsigned int);
+               *mtod(m, unsigned int *) = rop->rop_priority;
+               break;
+       default:
+               error = ENOPROTOOPT;
+               break;
+       }
+       
+       return error;
 }
 
 void
Index: netinet6/icmp6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/icmp6.c,v
retrieving revision 1.226
diff -u -p -r1.226 icmp6.c
--- netinet6/icmp6.c    5 Sep 2018 09:47:18 -0000       1.226
+++ netinet6/icmp6.c    18 Oct 2018 15:26:28 -0000
@@ -1675,66 +1675,79 @@ int
 icmp6_ctloutput(int op, struct socket *so, int level, int optname,
     struct mbuf *m)
 {
-       int error = 0;
+       int error;
+
+       switch (op) {
+       case PRCO_SETOPT:
+               error = icmp6_setopt(so, level, optname, m);
+               break;
+       case PRCO_GETOPT:
+               error = icmp6_getopt(so, level, optname, m);
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       return error;
+}
+
+int
+icmp6_setopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
        struct inpcb *in6p = sotoinpcb(so);
+       struct icmp6_filter *p;
+       int error = 0;
 
        if (level != IPPROTO_ICMPV6)
                return EINVAL;
 
-       switch (op) {
-       case PRCO_SETOPT:
-               switch (optname) {
-               case ICMP6_FILTER:
-                   {
-                       struct icmp6_filter *p;
-
-                       if (m == NULL || m->m_len != sizeof(*p)) {
-                               error = EMSGSIZE;
-                               break;
-                       }
-                       p = mtod(m, struct icmp6_filter *);
-                       if (!p || !in6p->inp_icmp6filt) {
-                               error = EINVAL;
-                               break;
-                       }
-                       bcopy(p, in6p->inp_icmp6filt,
-                               sizeof(struct icmp6_filter));
-                       error = 0;
+       switch (optname) {
+       case ICMP6_FILTER:
+               if (m == NULL || m->m_len != sizeof(*p)) {
+                       error = EMSGSIZE;
                        break;
-                   }
-
-               default:
-                       error = ENOPROTOOPT;
+               }
+               p = mtod(m, struct icmp6_filter *);
+               if (!p || !in6p->inp_icmp6filt) {
+                       error = EINVAL;
                        break;
                }
+               bcopy(p, in6p->inp_icmp6filt,
+                       sizeof(struct icmp6_filter));
+               break;
+       default:
+               error = ENOPROTOOPT;
                break;
+       }
 
-       case PRCO_GETOPT:
-               switch (optname) {
-               case ICMP6_FILTER:
-                   {
-                       struct icmp6_filter *p;
-
-                       if (!in6p->inp_icmp6filt) {
-                               error = EINVAL;
-                               break;
-                       }
-                       m->m_len = sizeof(struct icmp6_filter);
-                       p = mtod(m, struct icmp6_filter *);
-                       bcopy(in6p->inp_icmp6filt, p,
-                               sizeof(struct icmp6_filter));
-                       error = 0;
-                       break;
-                   }
+       return error;
+}
+
+int
+icmp6_getopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
+       struct inpcb *in6p = sotoinpcb(so);
+       struct icmp6_filter *p;
+       int error = 0;
 
-               default:
-                       error = ENOPROTOOPT;
+       switch (optname) {
+       case ICMP6_FILTER:
+               if (!in6p->inp_icmp6filt) {
+                       error = EINVAL;
                        break;
                }
+               m->m_len = sizeof(struct icmp6_filter);
+               p = mtod(m, struct icmp6_filter *);
+               bcopy(in6p->inp_icmp6filt, p,
+                       sizeof(struct icmp6_filter));
+               break;
+       default:
+               error = ENOPROTOOPT;
                break;
        }
 
-       return (error);
+       return error;
 }
 
 /*
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.239
diff -u -p -r1.239 ip6_output.c
--- netinet6/ip6_output.c       28 Aug 2018 15:15:02 -0000      1.239
+++ netinet6/ip6_output.c       18 Oct 2018 15:26:28 -0000
@@ -121,6 +121,8 @@ int ip6_getpcbopt(struct ip6_pktopts *, 
 int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, int, int, int);
 int ip6_setmoptions(int, struct ip6_moptions **, struct mbuf *, unsigned int);
 int ip6_getmoptions(int, struct ip6_moptions *, struct mbuf *);
+int ip6_raw_getopt(struct socket *, int, int, struct mbuf *);
+int ip6_raw_setopt(struct socket *, int, int, struct mbuf *);
 int ip6_copyexthdr(struct mbuf **, caddr_t, int);
 int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int,
        struct ip6_frag **);
@@ -1047,8 +1049,27 @@ int
 ip6_ctloutput(int op, struct socket *so, int level, int optname,
     struct mbuf *m)
 {
-       int privileged, optdatalen, uproto;
-       void *optdata;
+       int error;
+
+       switch (op) {
+       case PRCO_SETOPT:
+               error = ip6_setopt(so, level, optname, m);
+               break;
+       case PRCO_GETOPT:
+               error = ip6_getopt(so, level, optname, m);
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       return error;
+}
+
+int
+ip6_setopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
+       int privileged, uproto;
        struct inpcb *inp = sotoinpcb(so);
        int error, optval;
        struct proc *p = curproc; /* For IPsec and rdomain */
@@ -1062,63 +1083,61 @@ ip6_ctloutput(int op, struct socket *so,
        if (level != IPPROTO_IPV6)
                return (EINVAL);
 
-       switch (op) {
-       case PRCO_SETOPT:
+       switch (optname) {
+       /*
+        * Use of some Hop-by-Hop options or some
+        * Destination options, might require special
+        * privilege.  That is, normal applications
+        * (without special privilege) might be forbidden
+        * from setting certain options in outgoing packets,
+        * and might never see certain options in received
+        * packets. [RFC 2292 Section 6]
+        * KAME specific note:
+        *  KAME prevents non-privileged users from sending or
+        *  receiving ANY hbh/dst options in order to avoid
+        *  overhead of parsing options in the kernel.
+        */
+       case IPV6_RECVHOPOPTS:
+       case IPV6_RECVDSTOPTS:
+               if (!privileged) {
+                       error = EPERM;
+                       break;
+               }
+               /* FALLTHROUGH */
+       case IPV6_UNICAST_HOPS:
+       case IPV6_MINHOPCOUNT:
+       case IPV6_HOPLIMIT:
+
+       case IPV6_RECVPKTINFO:
+       case IPV6_RECVHOPLIMIT:
+       case IPV6_RECVRTHDR:
+       case IPV6_RECVPATHMTU:
+       case IPV6_RECVTCLASS:
+       case IPV6_V6ONLY:
+       case IPV6_AUTOFLOWLABEL:
+       case IPV6_RECVDSTPORT:
+               if (m == NULL || m->m_len != sizeof(int)) {
+                       error = EINVAL;
+                       break;
+               }
+               optval = *mtod(m, int *);
                switch (optname) {
-               /*
-                * Use of some Hop-by-Hop options or some
-                * Destination options, might require special
-                * privilege.  That is, normal applications
-                * (without special privilege) might be forbidden
-                * from setting certain options in outgoing packets,
-                * and might never see certain options in received
-                * packets. [RFC 2292 Section 6]
-                * KAME specific note:
-                *  KAME prevents non-privileged users from sending or
-                *  receiving ANY hbh/dst options in order to avoid
-                *  overhead of parsing options in the kernel.
-                */
-               case IPV6_RECVHOPOPTS:
-               case IPV6_RECVDSTOPTS:
-                       if (!privileged) {
-                               error = EPERM;
-                               break;
-                       }
-                       /* FALLTHROUGH */
-               case IPV6_UNICAST_HOPS:
-               case IPV6_MINHOPCOUNT:
-               case IPV6_HOPLIMIT:
 
-               case IPV6_RECVPKTINFO:
-               case IPV6_RECVHOPLIMIT:
-               case IPV6_RECVRTHDR:
-               case IPV6_RECVPATHMTU:
-               case IPV6_RECVTCLASS:
-               case IPV6_V6ONLY:
-               case IPV6_AUTOFLOWLABEL:
-               case IPV6_RECVDSTPORT:
-                       if (m == NULL || m->m_len != sizeof(int)) {
+               case IPV6_UNICAST_HOPS:
+                       if (optval < -1 || optval >= 256)
                                error = EINVAL;
-                               break;
+                       else {
+                               /* -1 = kernel default */
+                               inp->inp_hops = optval;
                        }
-                       optval = *mtod(m, int *);
-                       switch (optname) {
-
-                       case IPV6_UNICAST_HOPS:
-                               if (optval < -1 || optval >= 256)
-                                       error = EINVAL;
-                               else {
-                                       /* -1 = kernel default */
-                                       inp->inp_hops = optval;
-                               }
-                               break;
+                       break;
 
-                       case IPV6_MINHOPCOUNT:
-                               if (optval < 0 || optval > 255)
-                                       error = EINVAL;
-                               else
-                                       inp->inp_ip6_minhlim = optval;
-                               break;
+               case IPV6_MINHOPCOUNT:
+                       if (optval < 0 || optval > 255)
+                               error = EINVAL;
+                       else
+                               inp->inp_ip6_minhlim = optval;
+                       break;
 
 #define OPTSET(bit) \
 do { \
@@ -1129,479 +1148,512 @@ do { \
 } while (/*CONSTCOND*/ 0)
 #define OPTBIT(bit) (inp->inp_flags & (bit) ? 1 : 0)
 
-                       case IPV6_RECVPKTINFO:
-                               OPTSET(IN6P_PKTINFO);
-                               break;
-
-                       case IPV6_HOPLIMIT:
-                       {
-                               struct ip6_pktopts **optp;
-
-                               optp = &inp->inp_outputopts6;
-                               error = ip6_pcbopt(IPV6_HOPLIMIT,
-                                                  (u_char *)&optval,
-                                                  sizeof(optval),
-                                                  optp,
-                                                  privileged, uproto);
-                               break;
-                       }
+               case IPV6_RECVPKTINFO:
+                       OPTSET(IN6P_PKTINFO);
+                       break;
 
-                       case IPV6_RECVHOPLIMIT:
-                               OPTSET(IN6P_HOPLIMIT);
-                               break;
+               case IPV6_HOPLIMIT:
+               {
+                       struct ip6_pktopts **optp;
 
-                       case IPV6_RECVHOPOPTS:
-                               OPTSET(IN6P_HOPOPTS);
-                               break;
+                       optp = &inp->inp_outputopts6;
+                       error = ip6_pcbopt(IPV6_HOPLIMIT,
+                                          (u_char *)&optval,
+                                          sizeof(optval),
+                                          optp,
+                                          privileged, uproto);
+                       break;
+               }
 
-                       case IPV6_RECVDSTOPTS:
-                               OPTSET(IN6P_DSTOPTS);
-                               break;
+               case IPV6_RECVHOPLIMIT:
+                       OPTSET(IN6P_HOPLIMIT);
+                       break;
 
-                       case IPV6_RECVRTHDR:
-                               OPTSET(IN6P_RTHDR);
-                               break;
+               case IPV6_RECVHOPOPTS:
+                       OPTSET(IN6P_HOPOPTS);
+                       break;
 
-                       case IPV6_RECVPATHMTU:
-                               /*
-                                * We ignore this option for TCP
-                                * sockets.
-                                * (RFC3542 leaves this case
-                                * unspecified.)
-                                */
-                               if (uproto != IPPROTO_TCP)
-                                       OPTSET(IN6P_MTU);
-                               break;
+               case IPV6_RECVDSTOPTS:
+                       OPTSET(IN6P_DSTOPTS);
+                       break;
 
-                       case IPV6_V6ONLY:
-                               /*
-                                * make setsockopt(IPV6_V6ONLY)
-                                * available only prior to bind(2).
-                                * see ipng mailing list, Jun 22 2001.
-                                */
-                               if (inp->inp_lport ||
-                                   !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) 
{
-                                       error = EINVAL;
-                                       break;
-                               }
-                               /* No support for IPv4-mapped addresses. */
-                               if (!optval)
-                                       error = EINVAL;
-                               else
-                                       error = 0;
-                               break;
-                       case IPV6_RECVTCLASS:
-                               OPTSET(IN6P_TCLASS);
-                               break;
-                       case IPV6_AUTOFLOWLABEL:
-                               OPTSET(IN6P_AUTOFLOWLABEL);
-                               break;
+               case IPV6_RECVRTHDR:
+                       OPTSET(IN6P_RTHDR);
+                       break;
 
-                       case IPV6_RECVDSTPORT:
-                               OPTSET(IN6P_RECVDSTPORT);
-                               break;
-                       }
+               case IPV6_RECVPATHMTU:
+                       /*
+                        * We ignore this option for TCP
+                        * sockets.
+                        * (RFC3542 leaves this case
+                        * unspecified.)
+                        */
+                       if (uproto != IPPROTO_TCP)
+                               OPTSET(IN6P_MTU);
                        break;
 
-               case IPV6_TCLASS:
-               case IPV6_DONTFRAG:
-               case IPV6_USE_MIN_MTU:
-                       if (m == NULL || m->m_len != sizeof(optval)) {
+               case IPV6_V6ONLY:
+                       /*
+                        * make setsockopt(IPV6_V6ONLY)
+                        * available only prior to bind(2).
+                        * see ipng mailing list, Jun 22 2001.
+                        */
+                       if (inp->inp_lport ||
+                           !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
                                error = EINVAL;
                                break;
                        }
-                       optval = *mtod(m, int *);
-                       {
-                               struct ip6_pktopts **optp;
-                               optp = &inp->inp_outputopts6;
-                               error = ip6_pcbopt(optname,
-                                                  (u_char *)&optval,
-                                                  sizeof(optval),
-                                                  optp,
-                                                  privileged, uproto);
-                               break;
-                       }
+                       /* No support for IPv4-mapped addresses. */
+                       if (!optval)
+                               error = EINVAL;
+                       else
+                               error = 0;
+                       break;
+               case IPV6_RECVTCLASS:
+                       OPTSET(IN6P_TCLASS);
+                       break;
+               case IPV6_AUTOFLOWLABEL:
+                       OPTSET(IN6P_AUTOFLOWLABEL);
+                       break;
+
+               case IPV6_RECVDSTPORT:
+                       OPTSET(IN6P_RECVDSTPORT);
+                       break;
+               }
+               break;
 
-               case IPV6_PKTINFO:
-               case IPV6_HOPOPTS:
-               case IPV6_RTHDR:
-               case IPV6_DSTOPTS:
-               case IPV6_RTHDRDSTOPTS:
+       case IPV6_TCLASS:
+       case IPV6_DONTFRAG:
+       case IPV6_USE_MIN_MTU:
+               if (m == NULL || m->m_len != sizeof(optval)) {
+                       error = EINVAL;
+                       break;
+               }
+               optval = *mtod(m, int *);
                {
-                       /* new advanced API (RFC3542) */
-                       u_char *optbuf;
-                       int optbuflen;
                        struct ip6_pktopts **optp;
-
-                       if (m && m->m_next) {
-                               error = EINVAL; /* XXX */
-                               break;
-                       }
-                       if (m) {
-                               optbuf = mtod(m, u_char *);
-                               optbuflen = m->m_len;
-                       } else {
-                               optbuf = NULL;
-                               optbuflen = 0;
-                       }
                        optp = &inp->inp_outputopts6;
                        error = ip6_pcbopt(optname,
-                                          optbuf, optbuflen,
-                                          optp, privileged, uproto);
+                                          (u_char *)&optval,
+                                          sizeof(optval),
+                                          optp,
+                                          privileged, uproto);
                        break;
                }
-#undef OPTSET
 
-               case IPV6_MULTICAST_IF:
-               case IPV6_MULTICAST_HOPS:
-               case IPV6_MULTICAST_LOOP:
-               case IPV6_JOIN_GROUP:
-               case IPV6_LEAVE_GROUP:
-                       error = ip6_setmoptions(optname,
-                                               &inp->inp_moptions6,
-                                               m, inp->inp_rtableid);
+       case IPV6_PKTINFO:
+       case IPV6_HOPOPTS:
+       case IPV6_RTHDR:
+       case IPV6_DSTOPTS:
+       case IPV6_RTHDRDSTOPTS:
+       {
+               /* new advanced API (RFC3542) */
+               u_char *optbuf;
+               int optbuflen;
+               struct ip6_pktopts **optp;
+
+               if (m && m->m_next) {
+                       error = EINVAL; /* XXX */
                        break;
+               }
+               if (m) {
+                       optbuf = mtod(m, u_char *);
+                       optbuflen = m->m_len;
+               } else {
+                       optbuf = NULL;
+                       optbuflen = 0;
+               }
+               optp = &inp->inp_outputopts6;
+               error = ip6_pcbopt(optname,
+                                  optbuf, optbuflen,
+                                  optp, privileged, uproto);
+               break;
+       }
+#undef OPTSET
 
-               case IPV6_PORTRANGE:
-                       if (m == NULL || m->m_len != sizeof(int)) {
-                               error = EINVAL;
-                               break;
-                       }
-                       optval = *mtod(m, int *);
+       case IPV6_MULTICAST_IF:
+       case IPV6_MULTICAST_HOPS:
+       case IPV6_MULTICAST_LOOP:
+       case IPV6_JOIN_GROUP:
+       case IPV6_LEAVE_GROUP:
+               error = ip6_setmoptions(optname,
+                                       &inp->inp_moptions6,
+                                       m, inp->inp_rtableid);
+               break;
 
-                       switch (optval) {
-                       case IPV6_PORTRANGE_DEFAULT:
-                               inp->inp_flags &= ~(IN6P_LOWPORT);
-                               inp->inp_flags &= ~(IN6P_HIGHPORT);
-                               break;
+       case IPV6_PORTRANGE:
+               if (m == NULL || m->m_len != sizeof(int)) {
+                       error = EINVAL;
+                       break;
+               }
+               optval = *mtod(m, int *);
 
-                       case IPV6_PORTRANGE_HIGH:
-                               inp->inp_flags &= ~(IN6P_LOWPORT);
-                               inp->inp_flags |= IN6P_HIGHPORT;
-                               break;
+               switch (optval) {
+               case IPV6_PORTRANGE_DEFAULT:
+                       inp->inp_flags &= ~(IN6P_LOWPORT);
+                       inp->inp_flags &= ~(IN6P_HIGHPORT);
+                       break;
 
-                       case IPV6_PORTRANGE_LOW:
-                               inp->inp_flags &= ~(IN6P_HIGHPORT);
-                               inp->inp_flags |= IN6P_LOWPORT;
-                               break;
+               case IPV6_PORTRANGE_HIGH:
+                       inp->inp_flags &= ~(IN6P_LOWPORT);
+                       inp->inp_flags |= IN6P_HIGHPORT;
+                       break;
 
-                       default:
-                               error = EINVAL;
-                               break;
-                       }
+               case IPV6_PORTRANGE_LOW:
+                       inp->inp_flags &= ~(IN6P_HIGHPORT);
+                       inp->inp_flags |= IN6P_LOWPORT;
                        break;
 
-               case IPSEC6_OUTSA:
+               default:
                        error = EINVAL;
                        break;
+               }
+               break;
 
-               case IPV6_AUTH_LEVEL:
-               case IPV6_ESP_TRANS_LEVEL:
-               case IPV6_ESP_NETWORK_LEVEL:
-               case IPV6_IPCOMP_LEVEL:
+       case IPSEC6_OUTSA:
+               error = EINVAL;
+               break;
+
+       case IPV6_AUTH_LEVEL:
+       case IPV6_ESP_TRANS_LEVEL:
+       case IPV6_ESP_NETWORK_LEVEL:
+       case IPV6_IPCOMP_LEVEL:
 #ifndef IPSEC
-                       error = EINVAL;
+               error = EINVAL;
 #else
-                       if (m == NULL || m->m_len != sizeof(int)) {
-                               error = EINVAL;
-                               break;
-                       }
-                       optval = *mtod(m, int *);
+               if (m == NULL || m->m_len != sizeof(int)) {
+                       error = EINVAL;
+                       break;
+               }
+               optval = *mtod(m, int *);
 
-                       if (optval < IPSEC_LEVEL_BYPASS ||
-                           optval > IPSEC_LEVEL_UNIQUE) {
-                               error = EINVAL;
-                               break;
-                       }
+               if (optval < IPSEC_LEVEL_BYPASS ||
+                   optval > IPSEC_LEVEL_UNIQUE) {
+                       error = EINVAL;
+                       break;
+               }
 
-                       switch (optname) {
-                       case IPV6_AUTH_LEVEL:
-                               if (optval < IPSEC_AUTH_LEVEL_DEFAULT &&
-                                   suser(p)) {
-                                       error = EACCES;
-                                       break;
-                               }
-                               inp->inp_seclevel[SL_AUTH] = optval;
+               switch (optname) {
+               case IPV6_AUTH_LEVEL:
+                       if (optval < IPSEC_AUTH_LEVEL_DEFAULT &&
+                           suser(p)) {
+                               error = EACCES;
                                break;
+                       }
+                       inp->inp_seclevel[SL_AUTH] = optval;
+                       break;
 
-                       case IPV6_ESP_TRANS_LEVEL:
-                               if (optval < IPSEC_ESP_TRANS_LEVEL_DEFAULT &&
-                                   suser(p)) {
-                                       error = EACCES;
-                                       break;
-                               }
-                               inp->inp_seclevel[SL_ESP_TRANS] = optval;
+               case IPV6_ESP_TRANS_LEVEL:
+                       if (optval < IPSEC_ESP_TRANS_LEVEL_DEFAULT &&
+                           suser(p)) {
+                               error = EACCES;
                                break;
+                       }
+                       inp->inp_seclevel[SL_ESP_TRANS] = optval;
+                       break;
 
-                       case IPV6_ESP_NETWORK_LEVEL:
-                               if (optval < IPSEC_ESP_NETWORK_LEVEL_DEFAULT &&
-                                   suser(p)) {
-                                       error = EACCES;
-                                       break;
-                               }
-                               inp->inp_seclevel[SL_ESP_NETWORK] = optval;
+               case IPV6_ESP_NETWORK_LEVEL:
+                       if (optval < IPSEC_ESP_NETWORK_LEVEL_DEFAULT &&
+                           suser(p)) {
+                               error = EACCES;
                                break;
+                       }
+                       inp->inp_seclevel[SL_ESP_NETWORK] = optval;
+                       break;
 
-                       case IPV6_IPCOMP_LEVEL:
-                               if (optval < IPSEC_IPCOMP_LEVEL_DEFAULT &&
-                                   suser(p)) {
-                                       error = EACCES;
-                                       break;
-                               }
-                               inp->inp_seclevel[SL_IPCOMP] = optval;
+               case IPV6_IPCOMP_LEVEL:
+                       if (optval < IPSEC_IPCOMP_LEVEL_DEFAULT &&
+                           suser(p)) {
+                               error = EACCES;
                                break;
                        }
+                       inp->inp_seclevel[SL_IPCOMP] = optval;
+                       break;
+               }
 #endif
+               break;
+       case SO_RTABLE:
+               if (m == NULL || m->m_len < sizeof(u_int)) {
+                       error = EINVAL;
                        break;
-               case SO_RTABLE:
-                       if (m == NULL || m->m_len < sizeof(u_int)) {
-                               error = EINVAL;
-                               break;
-                       }
-                       rtid = *mtod(m, u_int *);
-                       if (inp->inp_rtableid == rtid)
-                               break;
-                       /* needs privileges to switch when already set */
-                       if (p->p_p->ps_rtableid != rtid &&
-                           p->p_p->ps_rtableid != 0 &&
-                           (error = suser(p)) != 0)
-                               break;
-                       /* table must exist */
-                       if (!rtable_exists(rtid)) {
-                               error = EINVAL;
-                               break;
-                       }
-                       if (inp->inp_lport) {
-                               error = EBUSY;
-                               break;
-                       }
-                       inp->inp_rtableid = rtid;
-                       in_pcbrehash(inp);
+               }
+               rtid = *mtod(m, u_int *);
+               if (inp->inp_rtableid == rtid)
                        break;
-               case IPV6_PIPEX:
-                       if (m != NULL && m->m_len == sizeof(int))
-                               inp->inp_pipex = *mtod(m, int *);
-                       else
-                               error = EINVAL;
+               /* needs privileges to switch when already set */
+               if (p->p_p->ps_rtableid != rtid &&
+                   p->p_p->ps_rtableid != 0 &&
+                   (error = suser(p)) != 0)
                        break;
-
-               default:
-                       error = ENOPROTOOPT;
+               /* table must exist */
+               if (!rtable_exists(rtid)) {
+                       error = EINVAL;
+                       break;
+               }
+               if (inp->inp_lport) {
+                       error = EBUSY;
                        break;
                }
+               inp->inp_rtableid = rtid;
+               in_pcbrehash(inp);
+               break;
+       case IPV6_PIPEX:
+               if (m != NULL && m->m_len == sizeof(int))
+                       inp->inp_pipex = *mtod(m, int *);
+               else
+                       error = EINVAL;
                break;
 
-       case PRCO_GETOPT:
-               switch (optname) {
+       default:
+               error = ENOPROTOOPT;
+               break;
+       }
 
-               case IPV6_RECVHOPOPTS:
-               case IPV6_RECVDSTOPTS:
-               case IPV6_UNICAST_HOPS:
-               case IPV6_MINHOPCOUNT:
-               case IPV6_RECVPKTINFO:
-               case IPV6_RECVHOPLIMIT:
-               case IPV6_RECVRTHDR:
-               case IPV6_RECVPATHMTU:
+       return error;
+}
 
-               case IPV6_V6ONLY:
-               case IPV6_PORTRANGE:
-               case IPV6_RECVTCLASS:
-               case IPV6_AUTOFLOWLABEL:
-               case IPV6_RECVDSTPORT:
-                       switch (optname) {
+int
+ip6_getopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
+        int optdatalen;
+        void *optdata;
+        struct inpcb *inp = sotoinpcb(so);
+        int error, optval;
 
-                       case IPV6_RECVHOPOPTS:
-                               optval = OPTBIT(IN6P_HOPOPTS);
-                               break;
+        error = optval = 0;
 
-                       case IPV6_RECVDSTOPTS:
-                               optval = OPTBIT(IN6P_DSTOPTS);
-                               break;
+       if (level != IPPROTO_IPV6)
+               return (EINVAL);
 
-                       case IPV6_UNICAST_HOPS:
-                               optval = inp->inp_hops;
-                               break;
+       switch (optname) {
 
-                       case IPV6_MINHOPCOUNT:
-                               optval = inp->inp_ip6_minhlim;
-                               break;
+       case IPV6_RECVHOPOPTS:
+       case IPV6_RECVDSTOPTS:
+       case IPV6_UNICAST_HOPS:
+       case IPV6_MINHOPCOUNT:
+       case IPV6_RECVPKTINFO:
+       case IPV6_RECVHOPLIMIT:
+       case IPV6_RECVRTHDR:
+       case IPV6_RECVPATHMTU:
+
+       case IPV6_V6ONLY:
+       case IPV6_PORTRANGE:
+       case IPV6_RECVTCLASS:
+       case IPV6_AUTOFLOWLABEL:
+       case IPV6_RECVDSTPORT:
+               switch (optname) {
 
-                       case IPV6_RECVPKTINFO:
-                               optval = OPTBIT(IN6P_PKTINFO);
-                               break;
+               case IPV6_RECVHOPOPTS:
+                       optval = OPTBIT(IN6P_HOPOPTS);
+                       break;
 
-                       case IPV6_RECVHOPLIMIT:
-                               optval = OPTBIT(IN6P_HOPLIMIT);
-                               break;
+               case IPV6_RECVDSTOPTS:
+                       optval = OPTBIT(IN6P_DSTOPTS);
+                       break;
 
-                       case IPV6_RECVRTHDR:
-                               optval = OPTBIT(IN6P_RTHDR);
-                               break;
+               case IPV6_UNICAST_HOPS:
+                       optval = inp->inp_hops;
+                       break;
 
-                       case IPV6_RECVPATHMTU:
-                               optval = OPTBIT(IN6P_MTU);
-                               break;
+               case IPV6_MINHOPCOUNT:
+                       optval = inp->inp_ip6_minhlim;
+                       break;
 
-                       case IPV6_V6ONLY:
-                               optval = 1;
-                               break;
+               case IPV6_RECVPKTINFO:
+                       optval = OPTBIT(IN6P_PKTINFO);
+                       break;
 
-                       case IPV6_PORTRANGE:
-                           {
-                               int flags;
-                               flags = inp->inp_flags;
-                               if (flags & IN6P_HIGHPORT)
-                                       optval = IPV6_PORTRANGE_HIGH;
-                               else if (flags & IN6P_LOWPORT)
-                                       optval = IPV6_PORTRANGE_LOW;
-                               else
-                                       optval = 0;
-                               break;
-                           }
-                       case IPV6_RECVTCLASS:
-                               optval = OPTBIT(IN6P_TCLASS);
-                               break;
+               case IPV6_RECVHOPLIMIT:
+                       optval = OPTBIT(IN6P_HOPLIMIT);
+                       break;
 
-                       case IPV6_AUTOFLOWLABEL:
-                               optval = OPTBIT(IN6P_AUTOFLOWLABEL);
-                               break;
+               case IPV6_RECVRTHDR:
+                       optval = OPTBIT(IN6P_RTHDR);
+                       break;
 
-                       case IPV6_RECVDSTPORT:
-                               optval = OPTBIT(IN6P_RECVDSTPORT);
-                               break;
-                       }
-                       if (error)
-                               break;
-                       m->m_len = sizeof(int);
-                       *mtod(m, int *) = optval;
+               case IPV6_RECVPATHMTU:
+                       optval = OPTBIT(IN6P_MTU);
                        break;
 
-               case IPV6_PATHMTU:
-               {
-                       u_long pmtu = 0;
-                       struct ip6_mtuinfo mtuinfo;
-                       struct ifnet *ifp;
-                       struct rtentry *rt;
-
-                       if (!(so->so_state & SS_ISCONNECTED))
-                               return (ENOTCONN);
-
-                       rt = in_pcbrtentry(inp);
-                       if (!rtisvalid(rt))
-                               return (EHOSTUNREACH);
+               case IPV6_V6ONLY:
+                       optval = 1;
+                       break;
 
-                       ifp = if_get(rt->rt_ifidx);
-                       if (ifp == NULL)
-                               return (EHOSTUNREACH);
-                       /*
-                        * XXX: we dot not consider the case of source
-                        * routing, or optional information to specify
-                        * the outgoing interface.
-                        */
-                       error = ip6_getpmtu(rt, ifp, &pmtu);
-                       if_put(ifp);
-                       if (error)
-                               break;
-                       if (pmtu > IPV6_MAXPACKET)
-                               pmtu = IPV6_MAXPACKET;
+               case IPV6_PORTRANGE:
+                   {
+                       int flags;
+                       flags = inp->inp_flags;
+                       if (flags & IN6P_HIGHPORT)
+                               optval = IPV6_PORTRANGE_HIGH;
+                       else if (flags & IN6P_LOWPORT)
+                               optval = IPV6_PORTRANGE_LOW;
+                       else
+                               optval = 0;
+                       break;
+                   }
+               case IPV6_RECVTCLASS:
+                       optval = OPTBIT(IN6P_TCLASS);
+                       break;
 
-                       bzero(&mtuinfo, sizeof(mtuinfo));
-                       mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
-                       optdata = (void *)&mtuinfo;
-                       optdatalen = sizeof(mtuinfo);
-                       if (optdatalen > MCLBYTES)
-                               return (EMSGSIZE); /* XXX */
-                       if (optdatalen > MLEN)
-                               MCLGET(m, M_WAIT);
-                       m->m_len = optdatalen;
-                       bcopy(optdata, mtod(m, void *), optdatalen);
+               case IPV6_AUTOFLOWLABEL:
+                       optval = OPTBIT(IN6P_AUTOFLOWLABEL);
                        break;
-               }
 
-               case IPV6_PKTINFO:
-               case IPV6_HOPOPTS:
-               case IPV6_RTHDR:
-               case IPV6_DSTOPTS:
-               case IPV6_RTHDRDSTOPTS:
-               case IPV6_TCLASS:
-               case IPV6_DONTFRAG:
-               case IPV6_USE_MIN_MTU:
-                       error = ip6_getpcbopt(inp->inp_outputopts6,
-                           optname, m);
-                       break;
-
-               case IPV6_MULTICAST_IF:
-               case IPV6_MULTICAST_HOPS:
-               case IPV6_MULTICAST_LOOP:
-               case IPV6_JOIN_GROUP:
-               case IPV6_LEAVE_GROUP:
-                       error = ip6_getmoptions(optname,
-                           inp->inp_moptions6, m);
+               case IPV6_RECVDSTPORT:
+                       optval = OPTBIT(IN6P_RECVDSTPORT);
+                       break;
+               }
+               if (error)
                        break;
+               m->m_len = sizeof(int);
+               *mtod(m, int *) = optval;
+               break;
 
-               case IPSEC6_OUTSA:
-                       error = EINVAL;
+       case IPV6_PATHMTU:
+       {
+               u_long pmtu = 0;
+               struct ip6_mtuinfo mtuinfo;
+               struct ifnet *ifp;
+               struct rtentry *rt;
+
+               if (!(so->so_state & SS_ISCONNECTED))
+                       return (ENOTCONN);
+
+               rt = in_pcbrtentry(inp);
+               if (!rtisvalid(rt))
+                       return (EHOSTUNREACH);
+
+               ifp = if_get(rt->rt_ifidx);
+               if (ifp == NULL)
+                       return (EHOSTUNREACH);
+               /*
+                * XXX: we dot not consider the case of source
+                * routing, or optional information to specify
+                * the outgoing interface.
+                */
+               error = ip6_getpmtu(rt, ifp, &pmtu);
+               if_put(ifp);
+               if (error)
                        break;
+               if (pmtu > IPV6_MAXPACKET)
+                       pmtu = IPV6_MAXPACKET;
 
-               case IPV6_AUTH_LEVEL:
-               case IPV6_ESP_TRANS_LEVEL:
-               case IPV6_ESP_NETWORK_LEVEL:
-               case IPV6_IPCOMP_LEVEL:
-#ifndef IPSEC
-                       m->m_len = sizeof(int);
-                       *mtod(m, int *) = IPSEC_LEVEL_NONE;
-#else
-                       m->m_len = sizeof(int);
-                       switch (optname) {
-                       case IPV6_AUTH_LEVEL:
-                               optval = inp->inp_seclevel[SL_AUTH];
-                               break;
+               bzero(&mtuinfo, sizeof(mtuinfo));
+               mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
+               optdata = (void *)&mtuinfo;
+               optdatalen = sizeof(mtuinfo);
+               if (optdatalen > MCLBYTES)
+                       return (EMSGSIZE); /* XXX */
+               if (optdatalen > MLEN)
+                       MCLGET(m, M_WAIT);
+               m->m_len = optdatalen;
+               bcopy(optdata, mtod(m, void *), optdatalen);
+               break;
+       }
 
-                       case IPV6_ESP_TRANS_LEVEL:
-                               optval =
-                                   inp->inp_seclevel[SL_ESP_TRANS];
-                               break;
+       case IPV6_PKTINFO:
+       case IPV6_HOPOPTS:
+       case IPV6_RTHDR:
+       case IPV6_DSTOPTS:
+       case IPV6_RTHDRDSTOPTS:
+       case IPV6_TCLASS:
+       case IPV6_DONTFRAG:
+       case IPV6_USE_MIN_MTU:
+               error = ip6_getpcbopt(inp->inp_outputopts6,
+                   optname, m);
+               break;
 
-                       case IPV6_ESP_NETWORK_LEVEL:
-                               optval =
-                                   inp->inp_seclevel[SL_ESP_NETWORK];
-                               break;
+       case IPV6_MULTICAST_IF:
+       case IPV6_MULTICAST_HOPS:
+       case IPV6_MULTICAST_LOOP:
+       case IPV6_JOIN_GROUP:
+       case IPV6_LEAVE_GROUP:
+               error = ip6_getmoptions(optname,
+                   inp->inp_moptions6, m);
+               break;
 
-                       case IPV6_IPCOMP_LEVEL:
-                               optval = inp->inp_seclevel[SL_IPCOMP];
-                               break;
-                       }
-                       *mtod(m, int *) = optval;
-#endif
+       case IPSEC6_OUTSA:
+               error = EINVAL;
+               break;
+
+       case IPV6_AUTH_LEVEL:
+       case IPV6_ESP_TRANS_LEVEL:
+       case IPV6_ESP_NETWORK_LEVEL:
+       case IPV6_IPCOMP_LEVEL:
+#ifndef IPSEC
+               m->m_len = sizeof(int);
+               *mtod(m, int *) = IPSEC_LEVEL_NONE;
+#else
+               m->m_len = sizeof(int);
+               switch (optname) {
+               case IPV6_AUTH_LEVEL:
+                       optval = inp->inp_seclevel[SL_AUTH];
                        break;
-               case SO_RTABLE:
-                       m->m_len = sizeof(u_int);
-                       *mtod(m, u_int *) = optval;
-                       break;
-               case IPV6_PIPEX:
-                       m->m_len = sizeof(int);
-                       *mtod(m, int *) = optval;
+
+               case IPV6_ESP_TRANS_LEVEL:
+                       optval =
+                           inp->inp_seclevel[SL_ESP_TRANS];
                        break;
 
-               default:
-                       error = ENOPROTOOPT;
+               case IPV6_ESP_NETWORK_LEVEL:
+                       optval =
+                           inp->inp_seclevel[SL_ESP_NETWORK];
+                       break;
+
+               case IPV6_IPCOMP_LEVEL:
+                       optval = inp->inp_seclevel[SL_IPCOMP];
                        break;
                }
+               *mtod(m, int *) = optval;
+#endif
+               break;
+       case SO_RTABLE:
+               m->m_len = sizeof(u_int);
+               *mtod(m, u_int *) = optval;
+               break;
+       case IPV6_PIPEX:
+               m->m_len = sizeof(int);
+               *mtod(m, int *) = optval;
+               break;
+
+       default:
+               error = ENOPROTOOPT;
                break;
        }
-       return (error);
+       
+       return error;
 }
 
 int
 ip6_raw_ctloutput(int op, struct socket *so, int level, int optname,
     struct mbuf *m)
 {
-       int error = 0, optval;
-       const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
+       int error;
+
+       switch (op) {
+       case PRCO_SETOPT:
+               error = ip6_raw_setopt(so, level, optname, m);
+               break;
+       case PRCO_GETOPT:
+               error = ip6_raw_getopt(so, level, optname, m);
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       return error;
+}
+
+int
+ip6_raw_setopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
        struct inpcb *inp = sotoinpcb(so);
+       const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
+       int error = 0, optval;
 
        if (level != IPPROTO_IPV6)
-               return (EINVAL);
+               return EINVAL;
 
        switch (optname) {
        case IPV6_CHECKSUM:
@@ -1613,45 +1665,54 @@ ip6_raw_ctloutput(int op, struct socket 
                 * for an ICMPv6 socket will fail."
                 * The current behavior does not meet RFC3542.
                 */
-               switch (op) {
-               case PRCO_SETOPT:
-                       if (m == NULL || m->m_len != sizeof(int)) {
-                               error = EINVAL;
-                               break;
-                       }
-                       optval = *mtod(m, int *);
-                       if ((optval % 2) != 0) {
-                               /* the API assumes even offset values */
-                               error = EINVAL;
-                       } else if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 
{
-                               if (optval != icmp6off)
-                                       error = EINVAL;
-                       } else
-                               inp->inp_cksum6 = optval;
-                       break;
-
-               case PRCO_GETOPT:
-                       if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
-                               optval = icmp6off;
-                       else
-                               optval = inp->inp_cksum6;
-
-                       m->m_len = sizeof(int);
-                       *mtod(m, int *) = optval;
-                       break;
-
-               default:
+               if (m == NULL || m->m_len != sizeof(int)) {
                        error = EINVAL;
                        break;
                }
+               optval = *mtod(m, int *);
+               if ((optval % 2) != 0) {
+                       /* the API assumes even offset values */
+                       error = EINVAL;
+               } else if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
+                       if (optval != icmp6off)
+                               error = EINVAL;
+               } else
+                       inp->inp_cksum6 = optval;
+               break;
+       default:
+               error = ENOPROTOOPT;
                break;
+       }
+
+       return error;
+}
+
+int
+ip6_raw_getopt(struct socket *so, int level, int optname, struct mbuf *m)
+{
+       struct inpcb *inp = sotoinpcb(so);
+       const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
+       int error = 0, optval;
 
+       if (level != IPPROTO_IPV6)
+               return EINVAL;
+
+       switch (optname) {
+       case IPV6_CHECKSUM:
+               if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
+                       optval = icmp6off;
+               else
+                       optval = inp->inp_cksum6;
+
+               m->m_len = sizeof(int);
+               *mtod(m, int *) = optval;
+               break;
        default:
                error = ENOPROTOOPT;
                break;
        }
 
-       return (error);
+       return error;
 }
 
 /*
Index: netinet6/ip6_var.h
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_var.h,v
retrieving revision 1.84
diff -u -p -r1.84 ip6_var.h
--- netinet6/ip6_var.h  10 Oct 2018 11:46:59 -0000      1.84
+++ netinet6/ip6_var.h  18 Oct 2018 15:26:28 -0000
@@ -299,6 +299,8 @@ struct in6pcb;
 struct inpcb;
 
 int    icmp6_ctloutput(int, struct socket *, int, int, struct mbuf *);
+int    icmp6_getopt(struct socket *, int, int, struct mbuf *);
+int    icmp6_setopt(struct socket *, int, int, struct mbuf *);
 
 void   ip6_init(void);
 void   ip6intr(void);
@@ -322,6 +324,8 @@ int ip6_output(struct mbuf *, struct ip6
            struct ip6_moptions *, struct inpcb *);
 int    ip6_fragment(struct mbuf *, int, u_char, u_long);
 int    ip6_ctloutput(int, struct socket *, int, int, struct mbuf *);
+int    ip6_getopt(struct socket *, int, int, struct mbuf *);
+int    ip6_setopt(struct socket *, int, int, struct mbuf *);
 int    ip6_raw_ctloutput(int, struct socket *, int, int, struct mbuf *);
 void   ip6_initpktopts(struct ip6_pktopts *);
 int    ip6_setpktopts(struct mbuf *, struct ip6_pktopts *,

Reply via email to