📄 raw_ip6.c
字号:
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.
*/
int
rip6_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 int
rip6_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 int
rip6_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 int
rip6_abort(struct socket *so)
{
soisdisconnected(so);
return rip6_detach(so);
}
static int
rip6_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 int
rip6_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 int
rip6_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 int
rip6_shutdown(struct socket *so)
{
socantsendmore(so);
return 0;
}
static int
rip6_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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -