Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_output.c
Show First 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
static MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options"); | static MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options"); | ||||
static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **, | static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **, | ||||
struct ucred *, int); | struct ucred *, int); | ||||
static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *, | static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *, | ||||
struct socket *, struct sockopt *); | struct socket *, struct sockopt *); | ||||
static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *); | static int ip6_getpcbopt(struct inpcb *, int, struct sockopt *); | ||||
static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, | static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, | ||||
struct ucred *, int, int, int); | struct ucred *, int, int, int); | ||||
static int ip6_copyexthdr(struct mbuf **, caddr_t, int); | static int ip6_copyexthdr(struct mbuf **, caddr_t, int); | ||||
static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int, | static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int, | ||||
struct ip6_frag **); | struct ip6_frag **); | ||||
static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t); | static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t); | ||||
static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *); | static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *); | ||||
▲ Show 20 Lines • Show All 1,346 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
error = soopt_getm(sopt, &m); /* XXX */ | error = soopt_getm(sopt, &m); /* XXX */ | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
error = soopt_mcopyin(sopt, m); /* XXX */ | error = soopt_mcopyin(sopt, m); /* XXX */ | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
INP_WLOCK(in6p); | |||||
error = ip6_pcbopts(&in6p->in6p_outputopts, | error = ip6_pcbopts(&in6p->in6p_outputopts, | ||||
m, so, sopt); | m, so, sopt); | ||||
INP_WUNLOCK(in6p); | |||||
m_freem(m); /* XXX */ | m_freem(m); /* XXX */ | ||||
break; | break; | ||||
} | } | ||||
/* | /* | ||||
* Use of some Hop-by-Hop options or some | * Use of some Hop-by-Hop options or some | ||||
* Destination options, might require special | * Destination options, might require special | ||||
* privilege. That is, normal applications | * privilege. That is, normal applications | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | do { \ | ||||
if (optval) \ | if (optval) \ | ||||
in6p->inp_flags |= (bit); \ | in6p->inp_flags |= (bit); \ | ||||
else \ | else \ | ||||
in6p->inp_flags &= ~(bit); \ | in6p->inp_flags &= ~(bit); \ | ||||
INP_WUNLOCK(in6p); \ | INP_WUNLOCK(in6p); \ | ||||
} while (/*CONSTCOND*/ 0) | } while (/*CONSTCOND*/ 0) | ||||
#define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0) | #define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0) | ||||
#define OPTSET2(bit, val) do { \ | #define OPTSET2_N(bit, val) do { \ | ||||
INP_WLOCK(in6p); \ | |||||
if (val) \ | if (val) \ | ||||
in6p->inp_flags2 |= bit; \ | in6p->inp_flags2 |= bit; \ | ||||
else \ | else \ | ||||
in6p->inp_flags2 &= ~bit; \ | in6p->inp_flags2 &= ~bit; \ | ||||
} while (0) | |||||
#define OPTSET2(bit, val) do { \ | |||||
INP_WLOCK(in6p); \ | |||||
OPTSET2_N(bit, val); \ | |||||
INP_WUNLOCK(in6p); \ | INP_WUNLOCK(in6p); \ | ||||
} while (0) | } while (0) | ||||
#define OPTBIT2(bit) (in6p->inp_flags2 & (bit) ? 1 : 0) | #define OPTBIT2(bit) (in6p->inp_flags2 & (bit) ? 1 : 0) | ||||
#define OPTSET2292_EXCLUSIVE(bit) \ | |||||
do { \ | |||||
INP_WLOCK(in6p); \ | |||||
if (OPTBIT(IN6P_RFC2292)) { \ | |||||
error = EINVAL; \ | |||||
} else { \ | |||||
if (optval) \ | |||||
in6p->inp_flags |= (bit); \ | |||||
else \ | |||||
in6p->inp_flags &= ~(bit); \ | |||||
} \ | |||||
INP_WUNLOCK(in6p); \ | |||||
} while (/*CONSTCOND*/ 0) | |||||
case IPV6_RECVPKTINFO: | case IPV6_RECVPKTINFO: | ||||
/* cannot mix with RFC2292 */ | OPTSET2292_EXCLUSIVE(IN6P_PKTINFO); | ||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
error = EINVAL; | |||||
break; | break; | ||||
} | |||||
OPTSET(IN6P_PKTINFO); | |||||
break; | |||||
case IPV6_HOPLIMIT: | case IPV6_HOPLIMIT: | ||||
{ | { | ||||
struct ip6_pktopts **optp; | struct ip6_pktopts **optp; | ||||
/* cannot mix with RFC2292 */ | /* cannot mix with RFC2292 */ | ||||
if (OPTBIT(IN6P_RFC2292)) { | if (OPTBIT(IN6P_RFC2292)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
INP_WLOCK(in6p); | |||||
optp = &in6p->in6p_outputopts; | optp = &in6p->in6p_outputopts; | ||||
error = ip6_pcbopt(IPV6_HOPLIMIT, | error = ip6_pcbopt(IPV6_HOPLIMIT, | ||||
(u_char *)&optval, sizeof(optval), | (u_char *)&optval, sizeof(optval), | ||||
optp, (td != NULL) ? td->td_ucred : | optp, (td != NULL) ? td->td_ucred : | ||||
NULL, uproto); | NULL, uproto); | ||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
case IPV6_RECVHOPLIMIT: | case IPV6_RECVHOPLIMIT: | ||||
/* cannot mix with RFC2292 */ | OPTSET2292_EXCLUSIVE(IN6P_HOPLIMIT); | ||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
error = EINVAL; | |||||
break; | break; | ||||
} | |||||
OPTSET(IN6P_HOPLIMIT); | |||||
break; | |||||
case IPV6_RECVHOPOPTS: | case IPV6_RECVHOPOPTS: | ||||
/* cannot mix with RFC2292 */ | OPTSET2292_EXCLUSIVE(IN6P_HOPOPTS); | ||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
error = EINVAL; | |||||
break; | break; | ||||
} | |||||
OPTSET(IN6P_HOPOPTS); | |||||
break; | |||||
case IPV6_RECVDSTOPTS: | case IPV6_RECVDSTOPTS: | ||||
/* cannot mix with RFC2292 */ | OPTSET2292_EXCLUSIVE(IN6P_DSTOPTS); | ||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
error = EINVAL; | |||||
break; | break; | ||||
} | |||||
OPTSET(IN6P_DSTOPTS); | |||||
break; | |||||
case IPV6_RECVRTHDRDSTOPTS: | case IPV6_RECVRTHDRDSTOPTS: | ||||
/* cannot mix with RFC2292 */ | OPTSET2292_EXCLUSIVE(IN6P_RTHDRDSTOPTS); | ||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
error = EINVAL; | |||||
break; | break; | ||||
} | |||||
OPTSET(IN6P_RTHDRDSTOPTS); | |||||
break; | |||||
case IPV6_RECVRTHDR: | case IPV6_RECVRTHDR: | ||||
/* cannot mix with RFC2292 */ | OPTSET2292_EXCLUSIVE(IN6P_RTHDR); | ||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
error = EINVAL; | |||||
break; | break; | ||||
} | |||||
OPTSET(IN6P_RTHDR); | |||||
break; | |||||
case IPV6_RECVPATHMTU: | case IPV6_RECVPATHMTU: | ||||
/* | /* | ||||
* We ignore this option for TCP | * We ignore this option for TCP | ||||
* sockets. | * sockets. | ||||
* (RFC3542 leaves this case | * (RFC3542 leaves this case | ||||
* unspecified.) | * unspecified.) | ||||
*/ | */ | ||||
Show All 12 Lines | |||||
#endif | #endif | ||||
case IPV6_V6ONLY: | case IPV6_V6ONLY: | ||||
/* | /* | ||||
* make setsockopt(IPV6_V6ONLY) | * make setsockopt(IPV6_V6ONLY) | ||||
* available only prior to bind(2). | * available only prior to bind(2). | ||||
* see ipng mailing list, Jun 22 2001. | * see ipng mailing list, Jun 22 2001. | ||||
*/ | */ | ||||
INP_WLOCK(in6p); | |||||
if (in6p->inp_lport || | if (in6p->inp_lport || | ||||
!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { | !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { | ||||
INP_WUNLOCK(in6p); | |||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
OPTSET(IN6P_IPV6_V6ONLY); | OPTSET(IN6P_IPV6_V6ONLY); | ||||
if (optval) | if (optval) | ||||
in6p->inp_vflag &= ~INP_IPV4; | in6p->inp_vflag &= ~INP_IPV4; | ||||
else | else | ||||
in6p->inp_vflag |= INP_IPV4; | in6p->inp_vflag |= INP_IPV4; | ||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
case IPV6_RECVTCLASS: | case IPV6_RECVTCLASS: | ||||
/* cannot mix with RFC2292 XXX */ | /* cannot mix with RFC2292 XXX */ | ||||
if (OPTBIT(IN6P_RFC2292)) { | OPTSET2292_EXCLUSIVE(IN6P_TCLASS); | ||||
error = EINVAL; | |||||
break; | break; | ||||
} | |||||
OPTSET(IN6P_TCLASS); | |||||
break; | |||||
case IPV6_AUTOFLOWLABEL: | case IPV6_AUTOFLOWLABEL: | ||||
OPTSET(IN6P_AUTOFLOWLABEL); | OPTSET(IN6P_AUTOFLOWLABEL); | ||||
break; | break; | ||||
case IPV6_ORIGDSTADDR: | case IPV6_ORIGDSTADDR: | ||||
OPTSET2(INP_ORIGDSTADDR, optval); | OPTSET2(INP_ORIGDSTADDR, optval); | ||||
break; | break; | ||||
case IPV6_BINDANY: | case IPV6_BINDANY: | ||||
OPTSET(INP_BINDANY); | OPTSET(INP_BINDANY); | ||||
break; | break; | ||||
case IPV6_BINDMULTI: | case IPV6_BINDMULTI: | ||||
OPTSET2(INP_BINDMULTI, optval); | OPTSET2(INP_BINDMULTI, optval); | ||||
break; | break; | ||||
#ifdef RSS | #ifdef RSS | ||||
case IPV6_RSS_LISTEN_BUCKET: | case IPV6_RSS_LISTEN_BUCKET: | ||||
if ((optval >= 0) && | if ((optval >= 0) && | ||||
(optval < rss_getnumbuckets())) { | (optval < rss_getnumbuckets())) { | ||||
INP_WLOCK(in6p); | |||||
in6p->inp_rss_listen_bucket = optval; | in6p->inp_rss_listen_bucket = optval; | ||||
OPTSET2(INP_RSS_BUCKET_SET, 1); | OPTSET2_N(INP_RSS_BUCKET_SET, 1); | ||||
INP_WUNLOCK(in6p); | |||||
} else { | } else { | ||||
error = EINVAL; | error = EINVAL; | ||||
} | } | ||||
break; | break; | ||||
#endif | #endif | ||||
} | } | ||||
break; | break; | ||||
case IPV6_TCLASS: | case IPV6_TCLASS: | ||||
case IPV6_DONTFRAG: | case IPV6_DONTFRAG: | ||||
case IPV6_USE_MIN_MTU: | case IPV6_USE_MIN_MTU: | ||||
case IPV6_PREFER_TEMPADDR: | case IPV6_PREFER_TEMPADDR: | ||||
if (optlen != sizeof(optval)) { | if (optlen != sizeof(optval)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
error = sooptcopyin(sopt, &optval, | error = sooptcopyin(sopt, &optval, | ||||
sizeof optval, sizeof optval); | sizeof optval, sizeof optval); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
{ | { | ||||
struct ip6_pktopts **optp; | struct ip6_pktopts **optp; | ||||
INP_WLOCK(in6p); | |||||
optp = &in6p->in6p_outputopts; | optp = &in6p->in6p_outputopts; | ||||
error = ip6_pcbopt(optname, | error = ip6_pcbopt(optname, | ||||
(u_char *)&optval, sizeof(optval), | (u_char *)&optval, sizeof(optval), | ||||
optp, (td != NULL) ? td->td_ucred : | optp, (td != NULL) ? td->td_ucred : | ||||
NULL, uproto); | NULL, uproto); | ||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
case IPV6_2292PKTINFO: | case IPV6_2292PKTINFO: | ||||
case IPV6_2292HOPLIMIT: | case IPV6_2292HOPLIMIT: | ||||
case IPV6_2292HOPOPTS: | case IPV6_2292HOPOPTS: | ||||
case IPV6_2292DSTOPTS: | case IPV6_2292DSTOPTS: | ||||
case IPV6_2292RTHDR: | case IPV6_2292RTHDR: | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
case IPV6_NEXTHOP: | case IPV6_NEXTHOP: | ||||
{ | { | ||||
/* new advanced API (RFC3542) */ | /* new advanced API (RFC3542) */ | ||||
u_char *optbuf; | u_char *optbuf; | ||||
u_char optbuf_storage[MCLBYTES]; | u_char optbuf_storage[MCLBYTES]; | ||||
int optlen; | int optlen; | ||||
struct ip6_pktopts **optp; | struct ip6_pktopts **optp; | ||||
/* cannot mix with RFC2292 */ | |||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
/* | /* | ||||
* We only ensure valsize is not too large | * We only ensure valsize is not too large | ||||
* here. Further validation will be done | * here. Further validation will be done | ||||
* later. | * later. | ||||
*/ | */ | ||||
error = sooptcopyin(sopt, optbuf_storage, | error = sooptcopyin(sopt, optbuf_storage, | ||||
sizeof(optbuf_storage), 0); | sizeof(optbuf_storage), 0); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
INP_WLOCK(in6p); | |||||
/* cannot mix with RFC2292 */ | |||||
if (OPTBIT(IN6P_RFC2292)) { | |||||
INP_WUNLOCK(in6p); | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
optlen = sopt->sopt_valsize; | optlen = sopt->sopt_valsize; | ||||
optbuf = optbuf_storage; | optbuf = optbuf_storage; | ||||
optp = &in6p->in6p_outputopts; | optp = &in6p->in6p_outputopts; | ||||
error = ip6_pcbopt(optname, optbuf, optlen, | error = ip6_pcbopt(optname, optbuf, optlen, | ||||
optp, (td != NULL) ? td->td_ucred : NULL, | optp, (td != NULL) ? td->td_ucred : NULL, | ||||
uproto); | uproto); | ||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
#undef OPTSET | #undef OPTSET | ||||
case IPV6_MULTICAST_IF: | case IPV6_MULTICAST_IF: | ||||
case IPV6_MULTICAST_HOPS: | case IPV6_MULTICAST_HOPS: | ||||
case IPV6_MULTICAST_LOOP: | case IPV6_MULTICAST_LOOP: | ||||
case IPV6_JOIN_GROUP: | case IPV6_JOIN_GROUP: | ||||
Show All 36 Lines | #undef OPTSET | ||||
break; | break; | ||||
} | } | ||||
INP_WUNLOCK(in6p); | INP_WUNLOCK(in6p); | ||||
break; | break; | ||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
case IPV6_IPSEC_POLICY: | case IPV6_IPSEC_POLICY: | ||||
if (IPSEC_ENABLED(ipv6)) { | if (IPSEC_ENABLED(ipv6)) { | ||||
INP_WLOCK(in6p); | |||||
error = IPSEC_PCBCTL(ipv6, in6p, sopt); | error = IPSEC_PCBCTL(ipv6, in6p, sopt); | ||||
if (!error) | |||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
default: | default: | ||||
error = ENOPROTOOPT; | error = ENOPROTOOPT; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | #endif | ||||
optval = in6p->inp_flowtype; | optval = in6p->inp_flowtype; | ||||
break; | break; | ||||
case IPV6_RECVFLOWID: | case IPV6_RECVFLOWID: | ||||
optval = OPTBIT2(INP_RECVFLOWID); | optval = OPTBIT2(INP_RECVFLOWID); | ||||
break; | break; | ||||
#ifdef RSS | #ifdef RSS | ||||
case IPV6_RSSBUCKETID: | case IPV6_RSSBUCKETID: | ||||
INP_RLOCK(in6p); | |||||
retval = | retval = | ||||
rss_hash2bucket(in6p->inp_flowid, | rss_hash2bucket(in6p->inp_flowid, | ||||
in6p->inp_flowtype, | in6p->inp_flowtype, | ||||
&rss_bucket); | &rss_bucket); | ||||
INP_RUNLOCK(in6p); | |||||
if (retval == 0) | if (retval == 0) | ||||
optval = rss_bucket; | optval = rss_bucket; | ||||
else | else | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
case IPV6_RECVRSSBUCKETID: | case IPV6_RECVRSSBUCKETID: | ||||
optval = OPTBIT2(INP_RECVRSSBUCKETID); | optval = OPTBIT2(INP_RECVRSSBUCKETID); | ||||
break; | break; | ||||
#endif | #endif | ||||
case IPV6_BINDMULTI: | case IPV6_BINDMULTI: | ||||
optval = OPTBIT2(INP_BINDMULTI); | optval = OPTBIT2(INP_BINDMULTI); | ||||
break; | break; | ||||
} | } | ||||
if (error) | |||||
break; | |||||
error = sooptcopyout(sopt, &optval, | error = sooptcopyout(sopt, &optval, | ||||
sizeof optval); | sizeof optval); | ||||
break; | return (error); | ||||
case IPV6_PATHMTU: | case IPV6_PATHMTU: | ||||
{ | { | ||||
u_long pmtu = 0; | u_long pmtu = 0; | ||||
struct ip6_mtuinfo mtuinfo; | struct ip6_mtuinfo mtuinfo; | ||||
struct in6_addr addr; | |||||
if (!(so->so_state & SS_ISCONNECTED)) | if (!(so->so_state & SS_ISCONNECTED)) | ||||
return (ENOTCONN); | return (ENOTCONN); | ||||
/* | /* | ||||
* XXX: we dot not consider the case of source | * XXX: we dot not consider the case of source | ||||
* routing, or optional information to specify | * routing, or optional information to specify | ||||
* the outgoing interface. | * the outgoing interface. | ||||
* Copy faddr out of in6p to avoid holding lock | |||||
* on inp during route lookup. | |||||
*/ | */ | ||||
INP_RLOCK(in6p); | |||||
bcopy(&in6p->in6p_faddr, &addr, sizeof(addr)); | |||||
ae: What is the purpose of this bzero? | |||||
Not Done Inline ActionsAbsolutely pointless, I will remove it. jason_eggnet.com: Absolutely pointless, I will remove it. | |||||
INP_RUNLOCK(in6p); | |||||
error = ip6_getpmtu_ctl(so->so_fibnum, | error = ip6_getpmtu_ctl(so->so_fibnum, | ||||
&in6p->in6p_faddr, &pmtu); | &addr, &pmtu); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
if (pmtu > IPV6_MAXPACKET) | if (pmtu > IPV6_MAXPACKET) | ||||
pmtu = IPV6_MAXPACKET; | pmtu = IPV6_MAXPACKET; | ||||
bzero(&mtuinfo, sizeof(mtuinfo)); | bzero(&mtuinfo, sizeof(mtuinfo)); | ||||
mtuinfo.ip6m_mtu = (u_int32_t)pmtu; | mtuinfo.ip6m_mtu = (u_int32_t)pmtu; | ||||
optdata = (void *)&mtuinfo; | optdata = (void *)&mtuinfo; | ||||
Show All 33 Lines | #endif | ||||
case IPV6_RTHDR: | case IPV6_RTHDR: | ||||
case IPV6_DSTOPTS: | case IPV6_DSTOPTS: | ||||
case IPV6_RTHDRDSTOPTS: | case IPV6_RTHDRDSTOPTS: | ||||
case IPV6_NEXTHOP: | case IPV6_NEXTHOP: | ||||
case IPV6_TCLASS: | case IPV6_TCLASS: | ||||
case IPV6_DONTFRAG: | case IPV6_DONTFRAG: | ||||
case IPV6_USE_MIN_MTU: | case IPV6_USE_MIN_MTU: | ||||
case IPV6_PREFER_TEMPADDR: | case IPV6_PREFER_TEMPADDR: | ||||
error = ip6_getpcbopt(in6p->in6p_outputopts, | error = ip6_getpcbopt(in6p, optname, sopt); | ||||
optname, sopt); | |||||
break; | break; | ||||
case IPV6_MULTICAST_IF: | case IPV6_MULTICAST_IF: | ||||
case IPV6_MULTICAST_HOPS: | case IPV6_MULTICAST_HOPS: | ||||
case IPV6_MULTICAST_LOOP: | case IPV6_MULTICAST_LOOP: | ||||
case IPV6_MSFILTER: | case IPV6_MSFILTER: | ||||
error = ip6_getmoptions(in6p, sopt); | error = ip6_getmoptions(in6p, sopt); | ||||
break; | break; | ||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
case IPV6_IPSEC_POLICY: | case IPV6_IPSEC_POLICY: | ||||
if (IPSEC_ENABLED(ipv6)) { | if (IPSEC_ENABLED(ipv6)) { | ||||
INP_RLOCK(in6p); | |||||
error = IPSEC_PCBCTL(ipv6, in6p, sopt); | error = IPSEC_PCBCTL(ipv6, in6p, sopt); | ||||
INP_RUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
default: | default: | ||||
error = ENOPROTOOPT; | error = ENOPROTOOPT; | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, | ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, | ||||
struct socket *so, struct sockopt *sopt) | struct socket *so, struct sockopt *sopt) | ||||
{ | { | ||||
struct ip6_pktopts *opt = *pktopt; | struct ip6_pktopts *opt = *pktopt; | ||||
int error = 0; | int error = 0; | ||||
struct thread *td = sopt->sopt_td; | struct thread *td = sopt->sopt_td; | ||||
INP_WLOCK_ASSERT(sotoinpcb(so)); | |||||
/* turn off any old options. */ | /* turn off any old options. */ | ||||
if (opt) { | if (opt) { | ||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
if (opt->ip6po_pktinfo || opt->ip6po_nexthop || | if (opt->ip6po_pktinfo || opt->ip6po_nexthop || | ||||
opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 || | opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 || | ||||
opt->ip6po_rhinfo.ip6po_rhi_rthdr) | opt->ip6po_rhinfo.ip6po_rhi_rthdr) | ||||
printf("ip6_pcbopts: all specified options are cleared.\n"); | printf("ip6_pcbopts: all specified options are cleared.\n"); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | *pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT, | ||||
M_WAITOK); | M_WAITOK); | ||||
ip6_initpktopts(*pktopt); | ip6_initpktopts(*pktopt); | ||||
} | } | ||||
opt = *pktopt; | opt = *pktopt; | ||||
return (ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto)); | return (ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto)); | ||||
} | } | ||||
#define GET_PKTOPT_VAR(field, lenexpr) do { \ | |||||
if (pktopt && pktopt->field) { \ | |||||
INP_RUNLOCK(in6p); \ | |||||
optdata = malloc(sopt->sopt_valsize, M_TEMP, M_WAITOK); \ | |||||
malloc_optdata = true; \ | |||||
INP_RLOCK(in6p); \ | |||||
if (in6p->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { \ | |||||
INP_RUNLOCK(in6p); \ | |||||
free(optdata, M_TEMP); \ | |||||
return (ECONNRESET); \ | |||||
} \ | |||||
pktopt = in6p->in6p_outputopts; \ | |||||
if (pktopt && pktopt->field) { \ | |||||
optdatalen = min(lenexpr, sopt->sopt_valsize); \ | |||||
bcopy(&pktopt->field, optdata, optdatalen); \ | |||||
} else { \ | |||||
free(optdata, M_TEMP); \ | |||||
optdata = NULL; \ | |||||
malloc_optdata = false; \ | |||||
} \ | |||||
} \ | |||||
} while(0) | |||||
#define GET_PKTOPT_EXT_HDR(field) GET_PKTOPT_VAR(field, \ | |||||
(((struct ip6_ext *)pktopt->field)->ip6e_len + 1) << 3) | |||||
#define GET_PKTOPT_SOCKADDR(field) GET_PKTOPT_VAR(field, \ | |||||
pktopt->field->sa_len) | |||||
static int | static int | ||||
ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt) | ip6_getpcbopt(struct inpcb *in6p, int optname, struct sockopt *sopt) | ||||
{ | { | ||||
void *optdata = NULL; | void *optdata = NULL; | ||||
bool malloc_optdata = false; | |||||
int optdatalen = 0; | int optdatalen = 0; | ||||
struct ip6_ext *ip6e; | |||||
int error = 0; | int error = 0; | ||||
struct in6_pktinfo null_pktinfo; | struct in6_pktinfo null_pktinfo; | ||||
int deftclass = 0, on; | int deftclass = 0, on; | ||||
int defminmtu = IP6PO_MINMTU_MCASTONLY; | int defminmtu = IP6PO_MINMTU_MCASTONLY; | ||||
int defpreftemp = IP6PO_TEMPADDR_SYSTEM; | int defpreftemp = IP6PO_TEMPADDR_SYSTEM; | ||||
struct ip6_pktopts *pktopt; | |||||
INP_RLOCK(in6p); | |||||
pktopt = in6p->in6p_outputopts; | |||||
switch (optname) { | switch (optname) { | ||||
case IPV6_PKTINFO: | case IPV6_PKTINFO: | ||||
optdata = (void *)&null_pktinfo; | optdata = (void *)&null_pktinfo; | ||||
if (pktopt && pktopt->ip6po_pktinfo) { | if (pktopt && pktopt->ip6po_pktinfo) { | ||||
bcopy(pktopt->ip6po_pktinfo, &null_pktinfo, | bcopy(pktopt->ip6po_pktinfo, &null_pktinfo, | ||||
sizeof(null_pktinfo)); | sizeof(null_pktinfo)); | ||||
in6_clearscope(&null_pktinfo.ipi6_addr); | in6_clearscope(&null_pktinfo.ipi6_addr); | ||||
} else { | } else { | ||||
/* XXX: we don't have to do this every time... */ | /* XXX: we don't have to do this every time... */ | ||||
bzero(&null_pktinfo, sizeof(null_pktinfo)); | bzero(&null_pktinfo, sizeof(null_pktinfo)); | ||||
} | } | ||||
optdatalen = sizeof(struct in6_pktinfo); | optdatalen = sizeof(struct in6_pktinfo); | ||||
break; | break; | ||||
case IPV6_TCLASS: | case IPV6_TCLASS: | ||||
if (pktopt && pktopt->ip6po_tclass >= 0) | if (pktopt && pktopt->ip6po_tclass >= 0) | ||||
optdata = (void *)&pktopt->ip6po_tclass; | deftclass = pktopt->ip6po_tclass; | ||||
else | |||||
optdata = (void *)&deftclass; | optdata = (void *)&deftclass; | ||||
optdatalen = sizeof(int); | optdatalen = sizeof(int); | ||||
break; | break; | ||||
case IPV6_HOPOPTS: | case IPV6_HOPOPTS: | ||||
if (pktopt && pktopt->ip6po_hbh) { | GET_PKTOPT_EXT_HDR(ip6po_hbh); | ||||
optdata = (void *)pktopt->ip6po_hbh; | |||||
ip6e = (struct ip6_ext *)pktopt->ip6po_hbh; | |||||
optdatalen = (ip6e->ip6e_len + 1) << 3; | |||||
} | |||||
break; | break; | ||||
case IPV6_RTHDR: | case IPV6_RTHDR: | ||||
if (pktopt && pktopt->ip6po_rthdr) { | GET_PKTOPT_EXT_HDR(ip6po_rthdr); | ||||
optdata = (void *)pktopt->ip6po_rthdr; | |||||
ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr; | |||||
optdatalen = (ip6e->ip6e_len + 1) << 3; | |||||
} | |||||
break; | break; | ||||
case IPV6_RTHDRDSTOPTS: | case IPV6_RTHDRDSTOPTS: | ||||
if (pktopt && pktopt->ip6po_dest1) { | GET_PKTOPT_EXT_HDR(ip6po_dest1); | ||||
optdata = (void *)pktopt->ip6po_dest1; | |||||
ip6e = (struct ip6_ext *)pktopt->ip6po_dest1; | |||||
optdatalen = (ip6e->ip6e_len + 1) << 3; | |||||
} | |||||
break; | break; | ||||
case IPV6_DSTOPTS: | case IPV6_DSTOPTS: | ||||
if (pktopt && pktopt->ip6po_dest2) { | GET_PKTOPT_EXT_HDR(ip6po_dest2); | ||||
optdata = (void *)pktopt->ip6po_dest2; | |||||
ip6e = (struct ip6_ext *)pktopt->ip6po_dest2; | |||||
optdatalen = (ip6e->ip6e_len + 1) << 3; | |||||
} | |||||
break; | break; | ||||
case IPV6_NEXTHOP: | case IPV6_NEXTHOP: | ||||
if (pktopt && pktopt->ip6po_nexthop) { | GET_PKTOPT_SOCKADDR(ip6po_nexthop); | ||||
optdata = (void *)pktopt->ip6po_nexthop; | |||||
optdatalen = pktopt->ip6po_nexthop->sa_len; | |||||
} | |||||
break; | break; | ||||
case IPV6_USE_MIN_MTU: | case IPV6_USE_MIN_MTU: | ||||
if (pktopt) | if (pktopt) | ||||
optdata = (void *)&pktopt->ip6po_minmtu; | defminmtu = pktopt->ip6po_minmtu; | ||||
else | |||||
optdata = (void *)&defminmtu; | optdata = (void *)&defminmtu; | ||||
optdatalen = sizeof(int); | optdatalen = sizeof(int); | ||||
break; | break; | ||||
case IPV6_DONTFRAG: | case IPV6_DONTFRAG: | ||||
if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG)) | if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG)) | ||||
on = 1; | on = 1; | ||||
else | else | ||||
on = 0; | on = 0; | ||||
optdata = (void *)&on; | optdata = (void *)&on; | ||||
optdatalen = sizeof(on); | optdatalen = sizeof(on); | ||||
break; | break; | ||||
case IPV6_PREFER_TEMPADDR: | case IPV6_PREFER_TEMPADDR: | ||||
if (pktopt) | if (pktopt) | ||||
optdata = (void *)&pktopt->ip6po_prefer_tempaddr; | defpreftemp = pktopt->ip6po_prefer_tempaddr; | ||||
else | |||||
optdata = (void *)&defpreftemp; | optdata = (void *)&defpreftemp; | ||||
optdatalen = sizeof(int); | optdatalen = sizeof(int); | ||||
break; | break; | ||||
default: /* should not happen */ | default: /* should not happen */ | ||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
panic("ip6_getpcbopt: unexpected option\n"); | panic("ip6_getpcbopt: unexpected option\n"); | ||||
#endif | #endif | ||||
INP_RUNLOCK(in6p); | |||||
return (ENOPROTOOPT); | return (ENOPROTOOPT); | ||||
} | } | ||||
INP_RUNLOCK(in6p); | |||||
error = sooptcopyout(sopt, optdata, optdatalen); | error = sooptcopyout(sopt, optdata, optdatalen); | ||||
if (malloc_optdata) | |||||
free(optdata, M_TEMP); | |||||
Not Done Inline ActionsI think it is not safe enough. Some of options use on-stack variable copies, but other do not. And it is possible to do dereference of already freed memory after INP_RUNLOCK(). ae: I think it is not safe enough. Some of options use on-stack variable copies, but other do not. | |||||
Not Done Inline ActionsWill fix this. jason_eggnet.com: Will fix this. | |||||
return (error); | return (error); | ||||
} | } | ||||
void | void | ||||
ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname) | ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname) | ||||
{ | { | ||||
if (pktopt == NULL) | if (pktopt == NULL) | ||||
▲ Show 20 Lines • Show All 667 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Compute IPv6 extension header length. | * Compute IPv6 extension header length. | ||||
*/ | */ | ||||
int | int | ||||
ip6_optlen(struct inpcb *in6p) | ip6_optlen(struct inpcb *in6p) | ||||
{ | { | ||||
int len; | int len; | ||||
INP_WLOCK_ASSERT(in6p); | |||||
if (!in6p->in6p_outputopts) | if (!in6p->in6p_outputopts) | ||||
return 0; | return 0; | ||||
len = 0; | len = 0; | ||||
#define elen(x) \ | #define elen(x) \ | ||||
(((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0) | (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0) | ||||
Show All 9 Lines |
What is the purpose of this bzero?