raw_ip6.c

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

C
715
字号
				  in6p->in6p_moptions,				  &in6p->in6p_route,				  &oifp, &in6p->in6p_laddr,				  &error)) == 0) {		if (error == 0)			error = EADDRNOTAVAIL;		goto bad;	}	ip6->ip6_src = *in6a;	if (oifp && dstsock->sin6_scope_id == 0 &&	    (error = scope6_setzoneid(oifp, dstsock)) != 0) { /* XXX */		goto bad;	}	if (oifp == NULL && in6p->in6p_route.ro_rt)		oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];	/* fill in the rest of the IPv6 header fields */	ip6->ip6_dst = *dst;	ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |		(in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);	ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |		(IPV6_VERSION & IPV6_VERSION_MASK);	/* ip6_plen will be filled in ip6_output, so not fill it here. */	ip6->ip6_nxt = in6p->in6p_ip6_nxt;	ip6->ip6_hlim = in6_selecthlim(in6p, oifp);	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||	    in6p->in6p_cksum != -1) {		struct mbuf *n;		int off;		u_int16_t *p;		/* compute checksum */		if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)			off = offsetof(struct icmp6_hdr, icmp6_cksum);		else			off = in6p->in6p_cksum;		if (plen < off + 1) {			error = EINVAL;			goto bad;		}		off += sizeof(struct ip6_hdr);		n = m;		while (n && n->m_len <= off) {			off -= n->m_len;			n = n->m_next;		}		if (!n)			goto bad;		p = (u_int16_t *)(mtod(n, caddr_t) + off);		*p = 0;		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);	}#ifdef IPSEC	if (ipsec_setsocket(m, so) != 0) {		error = ENOBUFS;		goto bad;	}#endif /*IPSEC*/	oifp = NULL;		/* just in case */	error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, 0,			   in6p->in6p_moptions, &oifp);	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {		if (oifp)			icmp6_ifoutstat_inc(oifp, type, code);		icmp6stat.icp6s_outhist[type]++;	} else		rip6stat.rip6s_opackets++;	goto freectl; bad:	if (m)		m_freem(m); freectl:	if (control) {		ip6_clearpktopts(in6p->in6p_outputopts, -1);		in6p->in6p_outputopts = stickyopt;		m_freem(control);	}	return(error);}/* * Raw IPv6 socket option processing. */intrip6_ctloutput(so, sopt)	struct socket *so;	struct sockopt *sopt;{	int error;	if (sopt->sopt_level == IPPROTO_ICMPV6)		/*		 * XXX: is it better to call icmp6_ctloutput() directly		 * from protosw?		 */		return(icmp6_ctloutput(so, sopt));	else if (sopt->sopt_level != IPPROTO_IPV6)		return (EINVAL);	error = 0;	switch (sopt->sopt_dir) {	case SOPT_GET:		switch (sopt->sopt_name) {		case MRT6_INIT:		case MRT6_DONE:		case MRT6_ADD_MIF:		case MRT6_DEL_MIF:		case MRT6_ADD_MFC:		case MRT6_DEL_MFC:		case MRT6_PIM:			error = ip6_mrouter_get(so, sopt);			break;		case IPV6_CHECKSUM:			error = ip6_raw_ctloutput(so, sopt);			break;		default:			error = ip6_ctloutput(so, sopt);			break;		}		break;	case SOPT_SET:		switch (sopt->sopt_name) {		case MRT6_INIT:		case MRT6_DONE:		case MRT6_ADD_MIF:		case MRT6_DEL_MIF:		case MRT6_ADD_MFC:		case MRT6_DEL_MFC:		case MRT6_PIM:			error = ip6_mrouter_set(so, sopt);			break;		case IPV6_CHECKSUM:			error = ip6_raw_ctloutput(so, sopt);			break;		default:			error = ip6_ctloutput(so, sopt);			break;		}		break;	}	return (error);}static intrip6_attach(struct socket *so, int proto, struct proc *p){	struct inpcb *inp;	int error, s;	inp = sotoinpcb(so);	if (inp)		panic("rip6_attach");	error = soreserve(so, rip_sendspace, rip_recvspace);	if (error)		return error;	s = splnet();	error = in_pcballoc(so, &ripcbinfo, p);	splx(s);	if (error)		return error;	inp = (struct inpcb *)so->so_pcb;	inp->inp_vflag |= INP_IPV6;	inp->in6p_ip6_nxt = (long)proto;	inp->in6p_hops = -1;	/* use kernel default */	inp->in6p_cksum = -1;	MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,	       sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);	ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);	return 0;}static intrip6_detach(struct socket *so){	struct inpcb *inp;	inp = sotoinpcb(so);	if (inp == 0)		panic("rip6_detach");	/* xxx: RSVP */	if (so == ip6_mrouter)		ip6_mrouter_done();	if (inp->in6p_icmp6filt) {		FREE(inp->in6p_icmp6filt, M_PCB);		inp->in6p_icmp6filt = NULL;	}	in6_pcbdetach(inp);	return 0;}static intrip6_abort(struct socket *so){	soisdisconnected(so);	return rip6_detach(so);}static intrip6_disconnect(struct socket *so){	struct inpcb *inp = sotoinpcb(so);	if ((so->so_state & SS_ISCONNECTED) == 0)		return ENOTCONN;	inp->in6p_faddr = in6addr_any;	return rip6_abort(so);}static intrip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p){	struct inpcb *inp = sotoinpcb(so);	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;	struct ifaddr *ia = NULL;	int error = 0;	if (nam->sa_len != sizeof(*addr))		return EINVAL;	if (nam->sa_family != AF_INET6)		return EAFNOSUPPORT;	if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6)		return EADDRNOTAVAIL;	if ((error = scope6_check_id(addr, ip6_use_defzone)) != 0)		return(error);#ifndef SCOPEDROUTING	addr->sin6_scope_id = 0; /* for ifa_ifwithaddr */#endif	if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&	    (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)		return EADDRNOTAVAIL;	if (ia &&	    ((struct in6_ifaddr *)ia)->ia6_flags &	    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|	     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {		return(EADDRNOTAVAIL);	}	inp->in6p_laddr = addr->sin6_addr;	return 0;}static intrip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p){	struct inpcb *inp = sotoinpcb(so);	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;	struct in6_addr *in6a = NULL;	struct ifnet *ifp = NULL;	int error = 0;	if (nam->sa_len != sizeof(*addr))		return EINVAL;	if (TAILQ_EMPTY(&ifnet))		return EADDRNOTAVAIL;	if (addr->sin6_family != AF_INET6)		return EAFNOSUPPORT;	if ((error = scope6_check_id(addr, ip6_use_defzone)) != 0)		return(error);	/* Source address selection. XXX: need pcblookup? */	in6a = in6_selectsrc(addr, inp->in6p_outputopts,			     inp->in6p_moptions, &inp->in6p_route,			     &ifp, &inp->in6p_laddr, &error);	if (in6a == NULL)		return (error ? error : EADDRNOTAVAIL);	/* see above */	if (ifp && addr->sin6_scope_id == 0 &&	    (error = scope6_setzoneid(ifp, addr)) != 0) { /* XXX */		return(error);	}	inp->in6p_laddr = *in6a;	inp->in6p_faddr = addr->sin6_addr;	soisconnected(so);	return 0;}static intrip6_shutdown(struct socket *so){	socantsendmore(so);	return 0;}static intrip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,	 struct mbuf *control, struct proc *p){	int error = 0;	struct inpcb *inp = sotoinpcb(so);	struct sockaddr_in6 tmp;	struct sockaddr_in6 *dst;	/* always copy sockaddr to avoid overwrites */	if (so->so_state & SS_ISCONNECTED) {		if (nam) {			m_freem(m);			return EISCONN;		}		/* XXX */		bzero(&tmp, sizeof(tmp));		tmp.sin6_family = AF_INET6;		tmp.sin6_len = sizeof(struct sockaddr_in6);		bcopy(&inp->in6p_faddr, &tmp.sin6_addr,		      sizeof(struct in6_addr));		dst = &tmp;	} else {		if (nam == NULL) {			m_freem(m);			return ENOTCONN;		}		if (nam->sa_len != sizeof(struct sockaddr_in6)) {			m_freem(m);			return(EINVAL);		}		tmp = *(struct sockaddr_in6 *)nam;		dst = &tmp;		if (dst->sin6_family == AF_UNSPEC) {			/*			 * XXX: we allow this case for backward			 * compatibility to buggy applications that			 * rely on old (and wrong) kernel behavior.			 */			log(LOG_INFO, "rip6 SEND: address family is "			    "unspec. Assume AF_INET6\n");		} else if (dst->sin6_family != AF_INET6) {			m_freem(m);			return(EAFNOSUPPORT);		}		if ((error = scope6_check_id(dst, ip6_use_defzone)) != 0) {			m_freem(m);			return(error);		}	}	return rip6_output(m, so, dst, control);}struct pr_usrreqs rip6_usrreqs = {	rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect,	pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,	pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,	pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown,	in6_setsockaddr, sosend, soreceive, sopoll};

⌨️ 快捷键说明

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