📄 ip6_output.c
字号:
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
error = sooptcopyin(sopt, &optval,
sizeof optval, sizeof optval);
if (error)
break;
#else
optval = *mtod(m, int *);
#endif
switch (optname) {
case IPV6_UNICAST_HOPS:
if (optval < -1 || optval >= 256)
error = EINVAL;
else {
/* -1 = kernel default */
in6p->in6p_hops = optval;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
if ((in6p->in6p_vflag &
INP_IPV4) != 0)
in6p->inp_ip_ttl = optval;
#endif
}
break;
#define OPTSET(bit) \
do { \
if (optval) \
in6p->in6p_flags |= (bit); \
else \
in6p->in6p_flags &= ~(bit); \
} while (0)
#define OPTSET2292(bit) \
do { \
in6p->in6p_flags |= IN6P_RFC2292; \
if (optval) \
in6p->in6p_flags |= (bit); \
else \
in6p->in6p_flags &= ~(bit); \
} while (0)
#define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0)
case IPV6_RECVPKTINFO:
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
OPTSET(IN6P_PKTINFO);
if (OPTBIT(IN6P_PKTINFO) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO);
break;
case IPV6_HOPLIMIT:
{
struct ip6_pktopts **optp;
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(IPV6_HOPLIMIT,
(u_char *)&optval,
sizeof(optval),
optp,
privileged);
break;
}
case IPV6_RECVHOPLIMIT:
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
OPTSET(IN6P_HOPLIMIT);
if (OPTBIT(IN6P_HOPLIMIT) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT);
break;
case IPV6_RECVHOPOPTS:
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
OPTSET(IN6P_HOPOPTS);
if (OPTBIT(IN6P_HOPOPTS) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS);
break;
case IPV6_RECVDSTOPTS:
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
OPTSET(IN6P_DSTOPTS);
if (OPTBIT(IN6P_DSTOPTS) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS);
break;
case IPV6_RECVRTHDRDSTOPTS:
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
OPTSET(IN6P_RTHDRDSTOPTS);
if (OPTBIT(IN6P_RTHDRDSTOPTS) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS);
break;
case IPV6_RECVRTHDR:
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
OPTSET(IN6P_RTHDR);
if (OPTBIT(IN6P_RTHDR) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR);
break;
case IPV6_FAITH:
OPTSET(IN6P_FAITH);
break;
case IPV6_RECVPATHMTU:
OPTSET(IN6P_MTU);
break;
case IPV6_V6ONLY:
/*
* make setsockopt(IPV6_V6ONLY)
* available only prior to bind(2).
* see ipng mailing list, Jun 22 2001.
*/
if (in6p->in6p_lport ||
!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
{
error = EINVAL;
break;
}
#ifdef __NetBSD__
#ifdef INET6_BINDV6ONLY
if (!optval)
error = EINVAL;
#else
OPTSET(IN6P_IPV6_V6ONLY);
#endif
#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
OPTSET(IN6P_IPV6_V6ONLY);
#else
if ((ip6_v6only && optval) ||
(!ip6_v6only && !optval))
error = 0;
else
error = EINVAL;
#endif
break;
case IPV6_RECVTCLASS:
/* cannot mix with RFC2292 XXX */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
OPTSET(IN6P_TCLASS);
break;
case IPV6_AUTOFLOWLABEL:
OPTSET(IN6P_AUTOFLOWLABEL);
break;
}
break;
case IPV6_OTCLASS:
{
struct ip6_pktopts **optp;
u_int8_t tclass;
if (optlen != sizeof(tclass)) {
error = EINVAL;
break;
}
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
error = sooptcopyin(sopt, &tclass,
sizeof tclass, sizeof tclass);
if (error)
break;
#else
tclass = *mtod(m, u_int8_t *);
#endif
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(optname,
(u_char *)&tclass,
sizeof(tclass),
optp,
privileged);
break;
}
case IPV6_TCLASS:
case IPV6_DONTFRAG:
case IPV6_USE_MIN_MTU:
if (optlen != sizeof(optval)) {
error = EINVAL;
break;
}
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
error = sooptcopyin(sopt, &optval,
sizeof optval, sizeof optval);
if (error)
break;
#else
optval = *mtod(m, int *);
#endif
{
struct ip6_pktopts **optp;
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(optname,
(u_char *)&optval,
sizeof(optval),
optp,
privileged);
break;
}
case IPV6_2292PKTINFO:
case IPV6_2292HOPLIMIT:
case IPV6_2292HOPOPTS:
case IPV6_2292DSTOPTS:
case IPV6_2292RTHDR:
/* RFC 2292 */
if (optlen != sizeof(int)) {
error = EINVAL;
break;
}
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
error = sooptcopyin(sopt, &optval,
sizeof optval, sizeof optval);
if (error)
break;
#else
optval = *mtod(m, int *);
#endif
switch (optname) {
case IPV6_2292PKTINFO:
OPTSET2292(IN6P_PKTINFO);
if (OPTBIT(IN6P_PKTINFO) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO);
break;
case IPV6_2292HOPLIMIT:
OPTSET2292(IN6P_HOPLIMIT);
if (OPTBIT(IN6P_HOPLIMIT) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT);
break;
case IPV6_2292HOPOPTS:
/*
* Check super-user privilege.
* See comments for IPV6_RECVHOPOPTS.
*/
OPTSET2292(IN6P_HOPOPTS);
if (OPTBIT(IN6P_HOPOPTS) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS);
break;
case IPV6_2292DSTOPTS:
OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
if (OPTBIT(IN6P_DSTOPTS) == 0) {
ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS);
ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS);
}
break;
case IPV6_2292RTHDR:
OPTSET2292(IN6P_RTHDR);
if (OPTBIT(IN6P_RTHDR) == 0)
ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR);
break;
}
break;
case IPV6_PKTINFO:
case IPV6_HOPOPTS:
case IPV6_RTHDR:
case IPV6_DSTOPTS:
case IPV6_RTHDRDSTOPTS:
case IPV6_NEXTHOP:
{
/* new advanced API (2292bis) */
u_char *optbuf;
int optlen;
struct ip6_pktopts **optp;
/* cannot mix with RFC2292 */
if (OPTBIT(IN6P_RFC2292)) {
error = EINVAL;
break;
}
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
optbuf = sopt->sopt_val;
optlen = sopt->sopt_valsize;
#else /* !fbsd3 */
if (m && m->m_next) {
error = EINVAL; /* XXX */
break;
}
if (m) {
optbuf = mtod(m, u_char *);
optlen = m->m_len;
} else {
optbuf = NULL;
optlen = 0;
}
#endif
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(optname,
optbuf, optlen,
optp, privileged);
break;
}
#undef OPTSET
case IPV6_MULTICAST_IF:
case IPV6_MULTICAST_HOPS:
case IPV6_MULTICAST_LOOP:
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP:
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
{
struct mbuf *m;
if (sopt->sopt_valsize > MLEN) {
error = EMSGSIZE;
break;
}
/* XXX */
MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER);
if (m == 0) {
error = ENOBUFS;
break;
}
m->m_len = sopt->sopt_valsize;
error = sooptcopyin(sopt, mtod(m, char *),
m->m_len, m->m_len);
error = ip6_setmoptions(sopt->sopt_name,
&in6p->in6p_moptions,
m);
(void)m_free(m);
}
#else
error = ip6_setmoptions(optname,
&in6p->in6p_moptions,
m);
#if defined(__bsdi__) && _BSDI_VERSION >= 199802
if (in6p->in6p_moptions != NULL)
in6p->in6p_flags |= INP_IPV6_MCAST; /* XXX */
#endif
#endif
break;
#ifndef __bsdi__
case IPV6_PORTRANGE:
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
error = sooptcopyin(sopt, &optval,
sizeof optval, sizeof optval);
if (error)
break;
#else
optval = *mtod(m, int *);
#endif
switch (optval) {
case IPV6_PORTRANGE_DEFAULT:
in6p->in6p_flags &= ~(IN6P_LOWPORT);
in6p->in6p_flags &= ~(IN6P_HIGHPORT);
break;
case IPV6_PORTRANGE_HIGH:
in6p->in6p_flags &= ~(IN6P_LOWPORT);
in6p->in6p_flags |= IN6P_HIGHPORT;
break;
case IPV6_PORTRANGE_LOW:
in6p->in6p_flags &= ~(IN6P_HIGHPORT);
in6p->in6p_flags |= IN6P_LOWPORT;
break;
default:
error = EINVAL;
break;
}
break;
#endif
#ifdef __OpenBSD__
case IPSEC6_OUTSA:
#ifndef IPSEC
error = EINVAL;
#else
s = spltdb();
if (m == 0 || m->m_len != sizeof(struct tdb_ident)) {
error = EINVAL;
} else {
tdbip = mtod(m, struct tdb_ident *);
tdb = gettdb(tdbip->spi, &tdbip->dst,
tdbip->proto);
if (tdb == NULL)
error = ESRCH;
else
tdb_add_inp(tdb, inp, 0);
}
splx(s);
#endif
break;
case IPV6_AUTH_LEVEL:
case IPV6_ESP_TRANS_LEVEL:
case IPV6_ESP_NETWORK_LEVEL:
case IPV6_IPCOMP_LEVEL:
#ifndef IPSEC
error = EINVAL;
#else
if (m == 0 || m->m_len != sizeof(int)) {
error = EINVAL;
break;
}
optval = *mtod(m, int *);
if (optval < IPSEC_LEVEL_BYPASS ||
optval > IPSEC_LEVEL_UNIQUE) {
error = EINVAL;
break;
}
switch (optname) {
case IPV6_AUTH_LEVEL:
inp->inp_seclevel[SL_AUTH] = optval;
break;
case IPV6_ESP_TRANS_LEVEL:
inp->inp_seclevel[SL_ESP_TRANS] = optval;
break;
case IPV6_ESP_NETWORK_LEVEL:
inp->inp_seclevel[SL_ESP_NETWORK] = optval;
break;
case IPV6_IPCOMP_LEVEL:
inp->inp_seclevel[SL_IPCOMP] = optval;
break;
}
if (!error)
inp->inp_secrequire = get_sa_require(inp);
#endif
break;
#endif /* OpenBSD */
#if defined(IPSEC) && !defined(__OpenBSD__)
case IPV6_IPSEC_POLICY:
{
caddr_t req = NULL;
size_t len = 0;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
struct mbuf *m;
#endif
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
break;
if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */
break;
#endif
if (m) {
req = mtod(m, caddr_t);
len = m->m_len;
}
error = ipsec6_set_policy(in6p, optname, req,
len, privileged);
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
m_freem(m);
#e
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -