Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_output.c
Show First 20 Lines • Show All 1,490 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 53 Lines • ▼ Show 20 Lines | #endif | ||||
break; | break; | ||||
switch (optname) { | switch (optname) { | ||||
case IPV6_UNICAST_HOPS: | case IPV6_UNICAST_HOPS: | ||||
if (optval < -1 || optval >= 256) | if (optval < -1 || optval >= 256) | ||||
error = EINVAL; | error = EINVAL; | ||||
else { | else { | ||||
/* -1 = kernel default */ | /* -1 = kernel default */ | ||||
INP_WLOCK(in6p); | |||||
in6p->in6p_hops = optval; | in6p->in6p_hops = optval; | ||||
if ((in6p->inp_vflag & | if ((in6p->inp_vflag & | ||||
INP_IPV4) != 0) | INP_IPV4) != 0) | ||||
in6p->inp_ip_ttl = optval; | in6p->inp_ip_ttl = optval; | ||||
INP_WUNLOCK(in6p); | |||||
} | } | ||||
break; | break; | ||||
#define OPTSET(bit) \ | #define OPTSET_N(bit) \ | ||||
do { \ | do { \ | ||||
INP_WLOCK(in6p); \ | |||||
if (optval) \ | if (optval) \ | ||||
in6p->inp_flags |= (bit); \ | in6p->inp_flags |= (bit); \ | ||||
else \ | else \ | ||||
in6p->inp_flags &= ~(bit); \ | in6p->inp_flags &= ~(bit); \ | ||||
} while (/*CONSTCOND*/ 0) | |||||
#define OPTSET(bit) \ | |||||
do { \ | |||||
INP_WLOCK(in6p); \ | |||||
OPTSET_N(bit); \ | |||||
INP_WUNLOCK(in6p); \ | INP_WUNLOCK(in6p); \ | ||||
} while (/*CONSTCOND*/ 0) | } while (/*CONSTCOND*/ 0) | ||||
#define OPTSET2292(bit) \ | #define OPTSET2292(bit) \ | ||||
do { \ | do { \ | ||||
INP_WLOCK(in6p); \ | INP_WLOCK(in6p); \ | ||||
in6p->inp_flags |= IN6P_RFC2292; \ | in6p->inp_flags |= IN6P_RFC2292; \ | ||||
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)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
OPTSET(IN6P_IPV6_V6ONLY); | OPTSET_N(IN6P_IPV6_V6ONLY); | ||||
/* optclear vflag */ | |||||
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)) { | |||||
error = EINVAL; | |||||
INP_WUNLOCK(in6p); | |||||
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); | ||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
default: | default: | ||||
error = ENOPROTOOPT; | error = ENOPROTOOPT; | ||||
break; | break; | ||||
Show All 36 Lines | #endif | ||||
case IPV6_FLOWID: | case IPV6_FLOWID: | ||||
case IPV6_FLOWTYPE: | case IPV6_FLOWTYPE: | ||||
case IPV6_RECVFLOWID: | case IPV6_RECVFLOWID: | ||||
#ifdef RSS | #ifdef RSS | ||||
case IPV6_RSSBUCKETID: | case IPV6_RSSBUCKETID: | ||||
case IPV6_RECVRSSBUCKETID: | case IPV6_RECVRSSBUCKETID: | ||||
#endif | #endif | ||||
case IPV6_BINDMULTI: | case IPV6_BINDMULTI: | ||||
INP_WLOCK(in6p); | |||||
switch (optname) { | switch (optname) { | ||||
case IPV6_RECVHOPOPTS: | case IPV6_RECVHOPOPTS: | ||||
optval = OPTBIT(IN6P_HOPOPTS); | optval = OPTBIT(IN6P_HOPOPTS); | ||||
break; | break; | ||||
case IPV6_RECVDSTOPTS: | case IPV6_RECVDSTOPTS: | ||||
optval = OPTBIT(IN6P_DSTOPTS); | optval = OPTBIT(IN6P_DSTOPTS); | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | #ifdef RSS | ||||
break; | break; | ||||
#endif | #endif | ||||
case IPV6_BINDMULTI: | case IPV6_BINDMULTI: | ||||
optval = OPTBIT2(INP_BINDMULTI); | optval = OPTBIT2(INP_BINDMULTI); | ||||
break; | break; | ||||
} | } | ||||
INP_WUNLOCK(in6p); | |||||
if (error) | if (error) | ||||
break; | break; | ||||
error = sooptcopyout(sopt, &optval, | error = sooptcopyout(sopt, &optval, | ||||
sizeof optval); | sizeof optval); | ||||
break; | break; | ||||
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_WLOCK(in6p); | |||||
bzero(&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. | |||||
bcopy(&in6p->in6p_faddr, &addr, sizeof(addr)); | |||||
INP_WUNLOCK(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; | ||||
optdatalen = sizeof(mtuinfo); | optdatalen = sizeof(mtuinfo); | ||||
error = sooptcopyout(sopt, optdata, | error = sooptcopyout(sopt, optdata, | ||||
optdatalen); | optdatalen); | ||||
break; | break; | ||||
} | } | ||||
case IPV6_2292PKTINFO: | case IPV6_2292PKTINFO: | ||||
case IPV6_2292HOPLIMIT: | case IPV6_2292HOPLIMIT: | ||||
case IPV6_2292HOPOPTS: | case IPV6_2292HOPOPTS: | ||||
case IPV6_2292RTHDR: | case IPV6_2292RTHDR: | ||||
case IPV6_2292DSTOPTS: | case IPV6_2292DSTOPTS: | ||||
INP_WLOCK(in6p); | |||||
switch (optname) { | switch (optname) { | ||||
case IPV6_2292PKTINFO: | case IPV6_2292PKTINFO: | ||||
optval = OPTBIT(IN6P_PKTINFO); | optval = OPTBIT(IN6P_PKTINFO); | ||||
break; | break; | ||||
case IPV6_2292HOPLIMIT: | case IPV6_2292HOPLIMIT: | ||||
optval = OPTBIT(IN6P_HOPLIMIT); | optval = OPTBIT(IN6P_HOPLIMIT); | ||||
break; | break; | ||||
case IPV6_2292HOPOPTS: | case IPV6_2292HOPOPTS: | ||||
optval = OPTBIT(IN6P_HOPOPTS); | optval = OPTBIT(IN6P_HOPOPTS); | ||||
break; | break; | ||||
case IPV6_2292RTHDR: | case IPV6_2292RTHDR: | ||||
optval = OPTBIT(IN6P_RTHDR); | optval = OPTBIT(IN6P_RTHDR); | ||||
break; | break; | ||||
case IPV6_2292DSTOPTS: | case IPV6_2292DSTOPTS: | ||||
optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); | optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); | ||||
break; | break; | ||||
} | } | ||||
INP_WUNLOCK(in6p); | |||||
error = sooptcopyout(sopt, &optval, | error = sooptcopyout(sopt, &optval, | ||||
sizeof optval); | sizeof optval); | ||||
break; | break; | ||||
case IPV6_PKTINFO: | case IPV6_PKTINFO: | ||||
case IPV6_HOPOPTS: | case IPV6_HOPOPTS: | ||||
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: | ||||
INP_WLOCK(in6p); | |||||
error = ip6_getpcbopt(in6p->in6p_outputopts, | error = ip6_getpcbopt(in6p->in6p_outputopts, | ||||
optname, sopt); | optname, sopt); | ||||
INP_WUNLOCK(in6p); | |||||
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_WLOCK(in6p); | |||||
error = IPSEC_PCBCTL(ipv6, in6p, sopt); | error = IPSEC_PCBCTL(ipv6, in6p, sopt); | ||||
INP_WUNLOCK(in6p); | |||||
break; | break; | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
default: | default: | ||||
error = ENOPROTOOPT; | error = ENOPROTOOPT; | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | case SOPT_SET: | ||||
break; | break; | ||||
if ((optval % 2) != 0) { | if ((optval % 2) != 0) { | ||||
/* the API assumes even offset values */ | /* the API assumes even offset values */ | ||||
error = EINVAL; | error = EINVAL; | ||||
} else if (so->so_proto->pr_protocol == | } else if (so->so_proto->pr_protocol == | ||||
IPPROTO_ICMPV6) { | IPPROTO_ICMPV6) { | ||||
if (optval != icmp6off) | if (optval != icmp6off) | ||||
error = EINVAL; | error = EINVAL; | ||||
} else | } else { | ||||
INP_WLOCK(in6p); | |||||
in6p->in6p_cksum = optval; | in6p->in6p_cksum = optval; | ||||
INP_WUNLOCK(in6p); | |||||
} | |||||
break; | break; | ||||
case SOPT_GET: | case SOPT_GET: | ||||
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) | if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) | ||||
optval = icmp6off; | optval = icmp6off; | ||||
else | else { | ||||
INP_WLOCK(in6p); | |||||
optval = in6p->in6p_cksum; | optval = in6p->in6p_cksum; | ||||
INP_WUNLOCK(in6p); | |||||
} | |||||
error = sooptcopyout(sopt, &optval, sizeof(optval)); | error = sooptcopyout(sopt, &optval, sizeof(optval)); | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
Show All 14 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 143 Lines • ▼ Show 20 Lines | case IPV6_PREFER_TEMPADDR: | ||||
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 | ||||
return (ENOPROTOOPT); | return (ENOPROTOOPT); | ||||
} | } | ||||
error = sooptcopyout(sopt, optdata, optdatalen); | error = sooptcopyout(sopt, optdata, optdatalen); | ||||
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?