/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * b) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * c) Neither the name of Cisco Systems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE.
*/
/* save original sockaddr_in6 addr and convert it to sockaddr_in */
sin6 = *(struct sockaddr_in6 *)nam;
sin_p = (struct sockaddr_in *)nam;
in6_sin6_2_sin(sin_p, &sin6);
}
if (icmp6_errmap(ip6cp->ip6c_icmp6) == 0) { return;
}
/* * Check if we can safely examine the ports and the * verification tag of the SCTP common header.
*/ if (ip6cp->ip6c_m->m_pkthdr.len <
(int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { return;
}
/* Copy out the port numbers and the verification tag. */
memset(&sh, 0, sizeof(sh));
m_copydata(ip6cp->ip6c_m,
ip6cp->ip6c_off, sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
(caddr_t)&sh);
memset(&src, 0, sizeof(struct sockaddr_in6));
src.sin6_family = AF_INET6;
src.sin6_len = sizeof(struct sockaddr_in6);
src.sin6_port = sh.src_port;
src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { return;
}
memset(&dst, 0, sizeof(struct sockaddr_in6));
dst.sin6_family = AF_INET6;
dst.sin6_len = sizeof(struct sockaddr_in6);
dst.sin6_port = sh.dest_port;
dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { return;
}
inp = NULL;
net = NULL;
stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
(struct sockaddr *)&src,
&inp, &net, 1, SCTP_DEFAULT_VRFID); if ((stcb != NULL) &&
(net != NULL) &&
(inp != NULL)) { /* Check the verification tag */ if (ntohl(sh.v_tag) != 0) { /* * This must be the verification tag used for * sending out packets. We don't consider * packets reflecting the verification tag.
*/ if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
SCTP_TCB_UNLOCK(stcb); return;
}
} else { if (ip6cp->ip6c_m->m_pkthdr.len >=
ip6cp->ip6c_off + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) +
offsetof(struct sctp_init, a_rwnd)) { /* * In this case we can check if we * got an INIT chunk and if the * initiate tag matches.
*/
uint32_t initiate_tag;
uint8_t chunk_type;
if ((unsigned)cmd >= PRC_NCMDS) { return;
} if (PRC_IS_REDIRECT(cmd)) {
d = NULL;
} elseif (inet6ctlerrmap[cmd] == 0) { return;
} /* If the parameter is from icmp6, decode it. */ if (d != NULL) {
ip6cp = (struct ip6ctlparam *)d;
} else {
ip6cp = (struct ip6ctlparam *)NULL;
}
if (ip6cp != NULL) { /* * XXX: We assume that when IPV6 is non NULL, M and OFF are * valid.
*/ if (ip6cp->ip6c_m == NULL) { return;
}
/* Check if we can safely examine the ports and the * verification tag of the SCTP common header.
*/ if (ip6cp->ip6c_m->m_pkthdr.len <
(int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { return;
}
/* Copy out the port numbers and the verification tag. */
memset(&sh, 0, sizeof(sh));
m_copydata(ip6cp->ip6c_m,
ip6cp->ip6c_off, sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
(caddr_t)&sh);
memset(&src, 0, sizeof(struct sockaddr_in6));
src.sin6_family = AF_INET6; #ifdef HAVE_SIN6_LEN
src.sin6_len = sizeof(struct sockaddr_in6); #endif
src.sin6_port = sh.src_port;
src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
memset(&dst, 0, sizeof(struct sockaddr_in6));
dst.sin6_family = AF_INET6; #ifdef HAVE_SIN6_LEN
dst.sin6_len = sizeof(struct sockaddr_in6); #endif
dst.sin6_port = sh.dest_port;
dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
inp = NULL;
net = NULL;
stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
(struct sockaddr *)&src,
&inp, &net, 1, SCTP_DEFAULT_VRFID); if ((stcb != NULL) &&
(net != NULL) &&
(inp != NULL)) { /* Check the verification tag */ if (ntohl(sh.v_tag) != 0) { /* * This must be the verification tag used for * sending out packets. We don't consider * packets reflecting the verification tag.
*/ if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
SCTP_TCB_UNLOCK(stcb); return;
}
} else {
SCTP_TCB_UNLOCK(stcb); return;
}
sctp6_notify(inp, stcb, net,
ip6cp->ip6c_icmp6->icmp6_type,
ip6cp->ip6c_icmp6->icmp6_code,
ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); #ifdefined(__Userspace__) if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
(stcb->sctp_socket != NULL)) { struct socket *upcall_socket;
/* * this routine can probably be collapsed into the one in sctp_userreq.c * since they do the same thing and now we lookup with a sockaddr
*/ #ifdefined(__FreeBSD__) && !defined(__Userspace__) staticint
sctp6_getcred(SYSCTL_HANDLER_ARGS)
{ struct xucred xuc; struct sockaddr_in6 addrs[2]; struct sctp_inpcb *inp; struct sctp_nets *net; struct sctp_tcb *stcb; int error;
uint32_t vrf_id;
stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]),
sin6tosa(&addrs[0]),
&inp, &net, 1, vrf_id); if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { if ((inp != NULL) && (stcb == NULL)) { /* reduce ref-count */
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp); goto cred_can_cont;
}
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
error = ENOENT; goto out;
}
SCTP_TCB_UNLOCK(stcb); /* We use the write lock here, only * since in the error leg we need it. * If we used RLOCK, then we would have * to wlock/decr/unlock/rlock. Which * in theory could create a hole. Better * to use higher wlock.
*/
SCTP_INP_WLOCK(inp);
cred_can_cont:
error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); if (error) {
SCTP_INP_WUNLOCK(inp); goto out;
}
cru2x(inp->sctp_socket->so_cred, &xuc);
SCTP_INP_WUNLOCK(inp);
error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
out: return (error);
}
SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred,
CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
0, 0, sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection"); #endif
#ifdefined(__Userspace__) int
sctp6_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) #elifdefined(__FreeBSD__) staticint
sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) #elifdefined(_WIN32) staticint
sctp6_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED) #else staticint
sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED) #endif
{ int error; struct sctp_inpcb *inp; #if !defined(__Userspace__)
uint32_t vrf_id = SCTP_DEFAULT_VRFID; #endif
inp->ip_inp.inp.inp_vflag |= INP_IPV6;
inp->ip_inp.inp.in6p_hops = -1; /* use kernel default */
inp->ip_inp.inp.in6p_cksum = -1; /* just to be sure */ #ifdef INET /* * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6 * socket as well, because the socket may be bound to an IPv6 * wildcard address, which may match an IPv4-mapped IPv6 address.
*/
inp->ip_inp.inp.inp_ip_ttl = MODULE_GLOBAL(ip_defttl); #endif
SCTP_INP_WUNLOCK(inp); return (0);
}
#ifdef INET struct sockaddr_in6 *sin6; #endif/* INET */ /* No SPL needed since sctp_output does this */
inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { if (control) {
SCTP_RELEASE_PKT(control);
control = NULL;
}
SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL);
} /* * For the TCP model we may get a NULL addr, if we are a connected * socket thats ok.
*/ if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
(addr == NULL)) { goto connected_type;
} if (addr == NULL) {
SCTP_RELEASE_PKT(m); if (control) {
SCTP_RELEASE_PKT(control);
control = NULL;
}
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); return (EDESTADDRREQ);
} switch (addr->sa_family) { #ifdef INET case AF_INET: #ifdefined(HAVE_SA_LEN) if (addr->sa_len != sizeof(struct sockaddr_in)) { if (control) {
SCTP_RELEASE_PKT(control);
control = NULL;
}
SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL);
} #endif break; #endif #ifdef INET6 case AF_INET6: #ifdefined(HAVE_SA_LEN) if (addr->sa_len != sizeof(struct sockaddr_in6)) { if (control) {
SCTP_RELEASE_PKT(control);
control = NULL;
}
SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL);
} #endif break; #endif default: if (control) {
SCTP_RELEASE_PKT(control);
control = NULL;
}
SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL);
} #ifdef INET
sin6 = (struct sockaddr_in6 *)addr; if (SCTP_IPV6_V6ONLY(inp)) { /* * if IPV6_V6ONLY flag, we discard datagrams destined to a * v4 addr or v4-mapped addr
*/ if (addr->sa_family == AF_INET) { if (control) {
SCTP_RELEASE_PKT(control);
control = NULL;
}
SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL);
} if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { if (control) {
SCTP_RELEASE_PKT(control);
control = NULL;
}
SCTP_RELEASE_PKT(m);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return (EINVAL);
}
} if ((addr->sa_family == AF_INET6) &&
IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { struct sockaddr_in sin;
/* convert v4-mapped into v4 addr and send */
in6_sin6_2_sin(&sin, sin6); return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
} #endif/* INET */
connected_type: /* now what about control */ if (control) { if (inp->control) {
SCTP_PRINTF("huh? control set?\n");
SCTP_RELEASE_PKT(inp->control);
inp->control = NULL;
}
inp->control = control;
} /* Place the data */ if (inp->pkt) {
SCTP_BUF_NEXT(inp->pkt_last) = m;
inp->pkt_last = m;
} else {
inp->pkt_last = inp->pkt = m;
} if ( #if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) /* FreeBSD and MacOSX uses a flag passed */
((flags & PRUS_MORETOCOME) == 0) #else
1 /* Open BSD does not have any "more to come"
* indication */ #endif
) { /* * note with the current version this code will only be used * by OpenBSD, NetBSD and FreeBSD have methods for * re-defining sosend() to use sctp_sosend(). One can * optionally switch back to this code (by changing back the * definitions but this is not advisable.
*/ #ifdefined(__FreeBSD__) && !defined(__Userspace__) struct epoch_tracker et; #endif int ret;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.19Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.