ip6_output.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,527 行 · 第 1/5 页

C
2,527
字号
					/* 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);#endif			    }				break;#endif /* KAME IPSEC */#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)			case IPV6_FW_ADD:			case IPV6_FW_DEL:			case IPV6_FW_FLUSH:			case IPV6_FW_ZERO:			    {#if defined(__FreeBSD__) && __FreeBSD__ >= 3				struct mbuf *m;				struct mbuf **mp = &m;#endif#if defined(__FreeBSD__) && __FreeBSD__ >= 3				if (ip6_fw_ctl_ptr == NULL)					return EINVAL;				/* XXX */				if ((error = soopt_getm(sopt, &m)) != 0)					break;				/* XXX */				if ((error = soopt_mcopyin(sopt, m)) != 0)					break;#else				if (ip6_fw_ctl_ptr == NULL) {					if (m) (void)m_free(m);					return EINVAL;				}#endif				error = (*ip6_fw_ctl_ptr)(optname, mp);				m = *mp;			    }				break;#endif			default:				error = ENOPROTOOPT;				break;			}#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)			if (m)				(void)m_free(m);#endif			break;#if defined(__FreeBSD__) && __FreeBSD__ >= 3		case SOPT_GET:#else		case PRCO_GETOPT:#endif			switch (optname) {			case IPV6_2292PKTOPTIONS:#ifdef IPV6_PKTOPTIONS			case IPV6_PKTOPTIONS:#endif#if defined(__FreeBSD__) && __FreeBSD__ >= 3				if (in6p->in6p_inputopts &&				    in6p->in6p_inputopts->head) {					struct mbuf *m;					m = m_copym(in6p->in6p_inputopts->head,					    0, M_COPYALL, M_WAIT);					error = soopt_mcopyout(sopt, m);					if (error == 0)						m_freem(m);				} else					sopt->sopt_valsize = 0;#else				if (in6p->in6p_inputopts &&				    in6p->in6p_inputopts->head) {					*mp = m_copym(in6p->in6p_inputopts->head,						      0, M_COPYALL, M_WAIT);				} else {					*mp = m_get(M_WAIT, MT_SOOPTS);					(*mp)->m_len = 0;				}#endif				break;			case IPV6_RECVHOPOPTS:			case IPV6_RECVDSTOPTS:			case IPV6_RECVRTHDRDSTOPTS:			case IPV6_UNICAST_HOPS:			case IPV6_RECVPKTINFO:			case IPV6_RECVHOPLIMIT:			case IPV6_RECVRTHDR:			case IPV6_USE_MIN_MTU:			case IPV6_RECVPATHMTU:			case IPV6_DONTFRAG:			case IPV6_FAITH:			case IPV6_V6ONLY:#ifndef __bsdi__			case IPV6_PORTRANGE:#endif			case IPV6_RECVTCLASS:			case IPV6_AUTOFLOWLABEL:				switch (optname) {				case IPV6_UNICAST_HOPS:					optval = in6p->in6p_hops;					break;				case IPV6_RECVPKTINFO:					optval = OPTBIT(IN6P_PKTINFO);					break;				case IPV6_RECVHOPLIMIT:					optval = OPTBIT(IN6P_HOPLIMIT);					break;				case IPV6_RECVHOPOPTS:					optval = OPTBIT(IN6P_HOPOPTS);					brea

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?