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 *,