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 + -
显示快捷键?