Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet6/udp6_usrreq.c
Show First 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | |||||
extern struct protosw inetsw[]; | extern struct protosw inetsw[]; | ||||
static void udp6_detach(struct socket *so); | static void udp6_detach(struct socket *so); | ||||
static int | static int | ||||
udp6_append(struct inpcb *inp, struct mbuf *n, int off, | udp6_append(struct inpcb *inp, struct mbuf *n, int off, | ||||
struct sockaddr_in6 *fromsa) | struct sockaddr_in6 *fromsa) | ||||
{ | { | ||||
struct socket *so; | struct socket *so; | ||||
struct mbuf *opts; | struct mbuf *opts = NULL, *tmp_opts; | ||||
struct udpcb *up; | struct udpcb *up; | ||||
INP_LOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
/* | /* | ||||
* Engage the tunneling protocol. | * Engage the tunneling protocol. | ||||
*/ | */ | ||||
up = intoudpcb(inp); | up = intoudpcb(inp); | ||||
if (up->u_tun_func != NULL) { | if (up->u_tun_func != NULL) { | ||||
in_pcbref(inp); | in_pcbref(inp); | ||||
INP_RUNLOCK(inp); | INP_RUNLOCK(inp); | ||||
(*up->u_tun_func)(n, off, inp, (struct sockaddr *)fromsa, | (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&fromsa[0], | ||||
up->u_tun_ctx); | up->u_tun_ctx); | ||||
INP_RLOCK(inp); | INP_RLOCK(inp); | ||||
return (in_pcbrele_rlocked(inp)); | return (in_pcbrele_rlocked(inp)); | ||||
} | } | ||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
/* Check AH/ESP integrity. */ | /* Check AH/ESP integrity. */ | ||||
if (IPSEC_ENABLED(ipv6)) { | if (IPSEC_ENABLED(ipv6)) { | ||||
if (IPSEC_CHECK_POLICY(ipv6, n, inp) != 0) { | if (IPSEC_CHECK_POLICY(ipv6, n, inp) != 0) { | ||||
m_freem(n); | m_freem(n); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
#ifdef MAC | #ifdef MAC | ||||
if (mac_inpcb_check_deliver(inp, n) != 0) { | if (mac_inpcb_check_deliver(inp, n) != 0) { | ||||
m_freem(n); | m_freem(n); | ||||
return (0); | return (0); | ||||
} | } | ||||
#endif | #endif | ||||
opts = NULL; | opts = NULL; | ||||
if (inp->inp_flags & INP_CONTROLOPTS || | if (inp->inp_flags & INP_CONTROLOPTS || | ||||
inp->inp_socket->so_options & SO_TIMESTAMP) | inp->inp_socket->so_options & SO_TIMESTAMP) | ||||
ip6_savecontrol(inp, n, &opts); | ip6_savecontrol(inp, n, &opts); | ||||
if ((inp->inp_vflag & INP_IPV6) && (inp->inp_flags2 & INP_ORIGDSTADDR)) { | |||||
tmp_opts = sbcreatecontrol((caddr_t)&fromsa[1], | |||||
sizeof(struct sockaddr_in6), IPV6_ORIGDSTADDR, IPPROTO_IPV6); | |||||
if (tmp_opts) { | |||||
if (opts) { | |||||
tmp_opts->m_next = opts; | |||||
opts = tmp_opts; | |||||
} else | |||||
opts = tmp_opts; | |||||
} | |||||
} | |||||
m_adj(n, off + sizeof(struct udphdr)); | m_adj(n, off + sizeof(struct udphdr)); | ||||
so = inp->inp_socket; | so = inp->inp_socket; | ||||
SOCKBUF_LOCK(&so->so_rcv); | SOCKBUF_LOCK(&so->so_rcv); | ||||
if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n, | if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)&fromsa[0], n, | ||||
opts) == 0) { | opts) == 0) { | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | SOCKBUF_UNLOCK(&so->so_rcv); | ||||
m_freem(n); | m_freem(n); | ||||
if (opts) | if (opts) | ||||
m_freem(opts); | m_freem(opts); | ||||
UDPSTAT_INC(udps_fullsock); | UDPSTAT_INC(udps_fullsock); | ||||
} else | } else | ||||
sorwakeup_locked(so); | sorwakeup_locked(so); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
udp6_input(struct mbuf **mp, int *offp, int proto) | udp6_input(struct mbuf **mp, int *offp, int proto) | ||||
{ | { | ||||
struct mbuf *m = *mp; | struct mbuf *m = *mp; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct udphdr *uh; | struct udphdr *uh; | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
struct inpcbinfo *pcbinfo; | struct inpcbinfo *pcbinfo; | ||||
struct udpcb *up; | struct udpcb *up; | ||||
int off = *offp; | int off = *offp; | ||||
int cscov_partial; | int cscov_partial; | ||||
int plen, ulen; | int plen, ulen; | ||||
struct sockaddr_in6 fromsa; | struct sockaddr_in6 fromsa[2]; | ||||
struct m_tag *fwd_tag; | struct m_tag *fwd_tag; | ||||
uint16_t uh_sum; | uint16_t uh_sum; | ||||
uint8_t nxt; | uint8_t nxt; | ||||
ifp = m->m_pkthdr.rcvif; | ifp = m->m_pkthdr.rcvif; | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
#ifndef PULLDOWN_TEST | #ifndef PULLDOWN_TEST | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | #endif | ||||
if (uh_sum != 0) { | if (uh_sum != 0) { | ||||
UDPSTAT_INC(udps_badsum); | UDPSTAT_INC(udps_badsum); | ||||
goto badunlocked; | goto badunlocked; | ||||
} | } | ||||
/* | /* | ||||
* Construct sockaddr format source address. | * Construct sockaddr format source address. | ||||
*/ | */ | ||||
init_sin6(&fromsa, m); | init_sin6(&fromsa[0], m, 0); | ||||
fromsa.sin6_port = uh->uh_sport; | fromsa[0].sin6_port = uh->uh_sport; | ||||
init_sin6(&fromsa[1], m, 1); | |||||
fromsa[1].sin6_port = uh->uh_dport; | |||||
pcbinfo = udp_get_inpcbinfo(nxt); | pcbinfo = udp_get_inpcbinfo(nxt); | ||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | ||||
struct inpcb *last; | struct inpcb *last; | ||||
struct inpcbhead *pcblist; | struct inpcbhead *pcblist; | ||||
struct ip6_moptions *imo; | struct ip6_moptions *imo; | ||||
INP_INFO_RLOCK(pcbinfo); | INP_INFO_RLOCK(pcbinfo); | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | LIST_FOREACH(inp, pcblist, inp_list) { | ||||
bzero(&mcaddr, sizeof(struct sockaddr_in6)); | bzero(&mcaddr, sizeof(struct sockaddr_in6)); | ||||
mcaddr.sin6_len = sizeof(struct sockaddr_in6); | mcaddr.sin6_len = sizeof(struct sockaddr_in6); | ||||
mcaddr.sin6_family = AF_INET6; | mcaddr.sin6_family = AF_INET6; | ||||
mcaddr.sin6_addr = ip6->ip6_dst; | mcaddr.sin6_addr = ip6->ip6_dst; | ||||
blocked = im6o_mc_filter(imo, ifp, | blocked = im6o_mc_filter(imo, ifp, | ||||
(struct sockaddr *)&mcaddr, | (struct sockaddr *)&mcaddr, | ||||
(struct sockaddr *)&fromsa); | (struct sockaddr *)&fromsa[0]); | ||||
if (blocked != MCAST_PASS) { | if (blocked != MCAST_PASS) { | ||||
if (blocked == MCAST_NOTGMEMBER) | if (blocked == MCAST_NOTGMEMBER) | ||||
IP6STAT_INC(ip6s_notmember); | IP6STAT_INC(ip6s_notmember); | ||||
if (blocked == MCAST_NOTSMEMBER || | if (blocked == MCAST_NOTSMEMBER || | ||||
blocked == MCAST_MUTED) | blocked == MCAST_MUTED) | ||||
UDPSTAT_INC(udps_filtermcast); | UDPSTAT_INC(udps_filtermcast); | ||||
INP_RUNLOCK(inp); /* XXX */ | INP_RUNLOCK(inp); /* XXX */ | ||||
continue; | continue; | ||||
} | } | ||||
INP_RUNLOCK(inp); | INP_RUNLOCK(inp); | ||||
} | } | ||||
if (last != NULL) { | if (last != NULL) { | ||||
struct mbuf *n; | struct mbuf *n; | ||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != | if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != | ||||
NULL) { | NULL) { | ||||
INP_RLOCK(last); | INP_RLOCK(last); | ||||
UDP_PROBE(receive, NULL, last, ip6, | UDP_PROBE(receive, NULL, last, ip6, | ||||
last, uh); | last, uh); | ||||
if (udp6_append(last, n, off, &fromsa)) | if (udp6_append(last, n, off, fromsa)) | ||||
goto inp_lost; | goto inp_lost; | ||||
INP_RUNLOCK(last); | INP_RUNLOCK(last); | ||||
} | } | ||||
} | } | ||||
last = inp; | last = inp; | ||||
/* | /* | ||||
* Don't look for additional matches if this one does | * Don't look for additional matches if this one does | ||||
* not have either the SO_REUSEPORT or SO_REUSEADDR | * not have either the SO_REUSEPORT or SO_REUSEADDR | ||||
Show All 15 Lines | if (last == NULL) { | ||||
*/ | */ | ||||
UDPSTAT_INC(udps_noport); | UDPSTAT_INC(udps_noport); | ||||
UDPSTAT_INC(udps_noportmcast); | UDPSTAT_INC(udps_noportmcast); | ||||
goto badheadlocked; | goto badheadlocked; | ||||
} | } | ||||
INP_RLOCK(last); | INP_RLOCK(last); | ||||
INP_INFO_RUNLOCK(pcbinfo); | INP_INFO_RUNLOCK(pcbinfo); | ||||
UDP_PROBE(receive, NULL, last, ip6, last, uh); | UDP_PROBE(receive, NULL, last, ip6, last, uh); | ||||
if (udp6_append(last, m, off, &fromsa) == 0) | if (udp6_append(last, m, off, fromsa) == 0) | ||||
INP_RUNLOCK(last); | INP_RUNLOCK(last); | ||||
inp_lost: | inp_lost: | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
} | } | ||||
/* | /* | ||||
* Locate pcb for datagram. | * Locate pcb for datagram. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | #endif | ||||
if (cscov_partial) { | if (cscov_partial) { | ||||
if (up->u_rxcslen == 0 || up->u_rxcslen > ulen) { | if (up->u_rxcslen == 0 || up->u_rxcslen > ulen) { | ||||
INP_RUNLOCK(inp); | INP_RUNLOCK(inp); | ||||
m_freem(m); | m_freem(m); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
} | } | ||||
} | } | ||||
UDP_PROBE(receive, NULL, inp, ip6, inp, uh); | UDP_PROBE(receive, NULL, inp, ip6, inp, uh); | ||||
if (udp6_append(inp, m, off, &fromsa) == 0) | if (udp6_append(inp, m, off, fromsa) == 0) | ||||
INP_RUNLOCK(inp); | INP_RUNLOCK(inp); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
badheadlocked: | badheadlocked: | ||||
INP_INFO_RUNLOCK(pcbinfo); | INP_INFO_RUNLOCK(pcbinfo); | ||||
badunlocked: | badunlocked: | ||||
if (m) | if (m) | ||||
m_freem(m); | m_freem(m); | ||||
▲ Show 20 Lines • Show All 808 Lines • Show Last 20 Lines |