2000-07-04 16:35:15 +00:00
|
|
|
/* $FreeBSD$ */
|
2001-06-11 12:39:29 +00:00
|
|
|
/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */
|
2000-07-04 16:35:15 +00:00
|
|
|
|
2005-01-07 02:30:35 +00:00
|
|
|
/*-
|
1999-12-07 17:39:16 +00:00
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. 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.
|
|
|
|
* 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
|
|
|
|
*/
|
|
|
|
|
2005-01-07 02:30:35 +00:00
|
|
|
/*-
|
1999-12-07 17:39:16 +00:00
|
|
|
* Copyright (c) 1982, 1986, 1989, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. 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.
|
|
|
|
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
|
|
|
|
*
|
|
|
|
* @(#)udp_var.h 8.1 (Berkeley) 6/10/93
|
|
|
|
*/
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
#include "opt_inet.h"
|
|
|
|
#include "opt_inet6.h"
|
1999-12-22 19:13:38 +00:00
|
|
|
#include "opt_ipsec.h"
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <sys/param.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/errno.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <sys/kernel.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/lock.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <sys/mbuf.h>
|
2006-11-06 13:42:10 +00:00
|
|
|
#include <sys/priv.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/proc.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <sys/protosw.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/signalvar.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/socketvar.h>
|
|
|
|
#include <sys/stat.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/sx.h>
|
|
|
|
#include <sys/sysctl.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <sys/syslog.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/systm.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_types.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <net/route.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_pcb.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <netinet/in_systm.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <netinet/in_var.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip6.h>
|
|
|
|
#include <netinet/icmp6.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <netinet/ip_var.h>
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/udp_var.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <netinet6/ip6protosw.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <netinet6/ip6_var.h>
|
|
|
|
#include <netinet6/in6_pcb.h>
|
|
|
|
#include <netinet6/udp6_var.h>
|
2005-07-25 12:31:43 +00:00
|
|
|
#include <netinet6/scope6_var.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
#ifdef IPSEC
|
|
|
|
#include <netinet6/ipsec.h>
|
1999-12-22 19:13:38 +00:00
|
|
|
#include <netinet6/ipsec6.h>
|
2002-04-19 04:46:24 +00:00
|
|
|
#endif /* IPSEC */
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2002-10-16 02:25:05 +00:00
|
|
|
#ifdef FAST_IPSEC
|
|
|
|
#include <netipsec/ipsec.h>
|
|
|
|
#include <netipsec/ipsec6.h>
|
|
|
|
#endif /* FAST_IPSEC */
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
/*
|
|
|
|
* UDP protocol inplementation.
|
|
|
|
* Per RFC 768, August, 1980.
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern struct protosw inetsw[];
|
Chance protocol switch method pru_detach() so that it returns void
rather than an error. Detaches do not "fail", they other occur or
the protocol flags SS_PROTOREF to take ownership of the socket.
soclose() no longer looks at so_pcb to see if it's NULL, relying
entirely on the protocol to decide whether it's time to free the
socket or not using SS_PROTOREF. so_pcb is now entirely owned and
managed by the protocol code. Likewise, no longer test so_pcb in
other socket functions, such as soreceive(), which have no business
digging into protocol internals.
Protocol detach routines no longer try to free the socket on detach,
this is performed in the socket code if the protocol permits it.
In rts_detach(), no longer test for rp != NULL in detach, and
likewise in other protocols that don't permit a NULL so_pcb, reduce
the incidence of testing for it during detach.
netinet and netinet6 are not fully updated to this change, which
will be in an upcoming commit. In their current state they may leak
memory or panic.
MFC after: 3 months
2006-04-01 15:42:02 +00:00
|
|
|
static void udp6_detach __P((struct socket *so));
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2006-05-01 21:39:48 +00:00
|
|
|
static void
|
|
|
|
udp6_append(struct inpcb *in6p, struct mbuf *n, int off,
|
|
|
|
struct sockaddr_in6 *fromsa)
|
|
|
|
{
|
|
|
|
struct socket *so;
|
|
|
|
struct mbuf *opts;
|
|
|
|
|
|
|
|
/* XXXRW: Not yet: INP_LOCK_ASSERT(in6p); */
|
|
|
|
|
|
|
|
#if defined(IPSEC) || defined(FAST_IPSEC)
|
|
|
|
/*
|
|
|
|
* Check AH/ESP integrity.
|
|
|
|
*/
|
|
|
|
if (ipsec6_in_reject(n, in6p)) {
|
|
|
|
m_freem(n);
|
|
|
|
#ifdef IPSEC
|
|
|
|
ipsec6stat.in_polvio++;
|
|
|
|
#endif /* IPSEC */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif /*IPSEC || FAST_IPSEC*/
|
|
|
|
|
|
|
|
opts = NULL;
|
|
|
|
if (in6p->in6p_flags & IN6P_CONTROLOPTS ||
|
|
|
|
in6p->inp_socket->so_options & SO_TIMESTAMP)
|
|
|
|
ip6_savecontrol(in6p, n, &opts);
|
|
|
|
m_adj(n, off + sizeof(struct udphdr));
|
|
|
|
|
|
|
|
so = in6p->inp_socket;
|
|
|
|
SOCKBUF_LOCK(&so->so_rcv);
|
|
|
|
if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n,
|
|
|
|
opts) == 0) {
|
|
|
|
SOCKBUF_UNLOCK(&so->so_rcv);
|
|
|
|
m_freem(n);
|
|
|
|
if (opts)
|
|
|
|
m_freem(opts);
|
|
|
|
udpstat.udps_fullsock++;
|
|
|
|
} else
|
|
|
|
sorwakeup_locked(so);
|
|
|
|
}
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
int
|
|
|
|
udp6_input(mp, offp, proto)
|
|
|
|
struct mbuf **mp;
|
|
|
|
int *offp, proto;
|
|
|
|
{
|
2006-05-01 21:39:48 +00:00
|
|
|
struct mbuf *m = *mp;
|
1999-12-07 17:39:16 +00:00
|
|
|
register struct ip6_hdr *ip6;
|
|
|
|
register struct udphdr *uh;
|
|
|
|
register struct inpcb *in6p;
|
|
|
|
int off = *offp;
|
|
|
|
int plen, ulen;
|
2003-11-02 19:09:29 +00:00
|
|
|
struct sockaddr_in6 fromsa;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
|
2001-09-25 18:40:52 +00:00
|
|
|
if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
|
2001-06-11 12:39:29 +00:00
|
|
|
/* XXX send icmp6 host/port unreach? */
|
|
|
|
m_freem(m);
|
|
|
|
return IPPROTO_DONE;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
2004-02-13 15:11:47 +00:00
|
|
|
#ifndef PULLDOWN_TEST
|
|
|
|
IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
uh = (struct udphdr *)((caddr_t)ip6 + off);
|
|
|
|
#else
|
|
|
|
IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh));
|
|
|
|
if (!uh)
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
#endif
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
udpstat.udps_ipackets++;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
|
|
|
|
ulen = ntohs((u_short)uh->uh_ulen);
|
|
|
|
|
|
|
|
if (plen != ulen) {
|
|
|
|
udpstat.udps_badlen++;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Checksum extended UDP header and data.
|
|
|
|
*/
|
2004-04-01 13:48:23 +00:00
|
|
|
if (uh->uh_sum == 0) {
|
1999-12-07 17:39:16 +00:00
|
|
|
udpstat.udps_nosum++;
|
2006-04-12 03:23:56 +00:00
|
|
|
goto bad_unlocked;
|
2004-04-01 13:48:23 +00:00
|
|
|
}
|
|
|
|
if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
|
1999-12-07 17:39:16 +00:00
|
|
|
udpstat.udps_badsum++;
|
2006-04-12 03:23:56 +00:00
|
|
|
goto bad_unlocked;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
2006-05-01 21:39:48 +00:00
|
|
|
/*
|
|
|
|
* Construct sockaddr format source address.
|
|
|
|
*/
|
|
|
|
init_sin6(&fromsa, m);
|
|
|
|
fromsa.sin6_port = uh->uh_sport;
|
|
|
|
|
2006-04-12 03:23:56 +00:00
|
|
|
INP_INFO_RLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
|
|
|
struct inpcb *last;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deliver a multicast datagram to all sockets
|
|
|
|
* for which the local and remote addresses and ports match
|
|
|
|
* those of the incoming datagram. This allows more than
|
|
|
|
* one process to receive multicasts on the same port.
|
|
|
|
* (This really ought to be done for unicast datagrams as
|
|
|
|
* well, but that would cause problems with existing
|
|
|
|
* applications that open both address-specific sockets and
|
|
|
|
* a wildcard socket listening to the same port -- they would
|
|
|
|
* end up receiving duplicates of every unicast datagram.
|
|
|
|
* Those applications open the multiple sockets to overcome an
|
|
|
|
* inadequacy of the UDP socket interface, but for backwards
|
|
|
|
* compatibility we avoid the problem here rather than
|
|
|
|
* fixing the interface. Maybe 4.5BSD will remedy this?)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In a case that laddr should be set to the link-local
|
|
|
|
* address (this happens in RIPng), the multicast address
|
|
|
|
* specified in the received packet does not match with
|
|
|
|
* laddr. To cure this situation, the matching is relaxed
|
|
|
|
* if the receiving interface is the same as one specified
|
|
|
|
* in the socket and if the destination multicast address
|
|
|
|
* matches one of the multicast groups specified in the socket.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2002-04-19 04:46:24 +00:00
|
|
|
* KAME note: traditionally we dropped udpiphdr from mbuf here.
|
1999-12-07 17:39:16 +00:00
|
|
|
* We need udphdr for IPsec processing so we do that later.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Locate pcb(s) for datagram.
|
|
|
|
* (Algorithm copied from raw_intr().)
|
2006-04-12 03:32:54 +00:00
|
|
|
*
|
|
|
|
* XXXRW: The individual inpcbs need to be locked in the
|
|
|
|
* style of udp_input().
|
1999-12-07 17:39:16 +00:00
|
|
|
*/
|
|
|
|
last = NULL;
|
|
|
|
LIST_FOREACH(in6p, &udb, inp_list) {
|
1999-12-21 11:14:12 +00:00
|
|
|
if ((in6p->inp_vflag & INP_IPV6) == 0)
|
1999-12-07 17:39:16 +00:00
|
|
|
continue;
|
|
|
|
if (in6p->in6p_lport != uh->uh_dport)
|
|
|
|
continue;
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
|
|
|
|
if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
|
2004-02-13 15:11:47 +00:00
|
|
|
&ip6->ip6_dst))
|
1999-12-07 17:39:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
|
|
|
|
if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
|
|
|
|
&ip6->ip6_src) ||
|
2004-02-13 15:11:47 +00:00
|
|
|
in6p->in6p_fport != uh->uh_sport)
|
1999-12-07 17:39:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last != NULL) {
|
2004-02-13 15:11:47 +00:00
|
|
|
struct mbuf *n;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
|
2006-09-07 18:44:54 +00:00
|
|
|
INP_LOCK(last);
|
|
|
|
udp6_append(last, n, off, &fromsa);
|
|
|
|
INP_UNLOCK(last);
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
last = in6p;
|
|
|
|
/*
|
|
|
|
* Don't look for additional matches if this one does
|
|
|
|
* not have either the SO_REUSEPORT or SO_REUSEADDR
|
|
|
|
* socket options set. This heuristic avoids searching
|
|
|
|
* through all pcbs in the common case of a non-shared
|
|
|
|
* port. It assumes that an application will never
|
|
|
|
* clear these options after setting them.
|
|
|
|
*/
|
|
|
|
if ((last->in6p_socket->so_options &
|
2002-05-31 11:52:35 +00:00
|
|
|
(SO_REUSEPORT|SO_REUSEADDR)) == 0)
|
1999-12-07 17:39:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last == NULL) {
|
|
|
|
/*
|
|
|
|
* No matching pcb found; discard datagram.
|
|
|
|
* (No need to send an ICMP Port Unreachable
|
|
|
|
* for a broadcast or multicast datgram.)
|
|
|
|
*/
|
|
|
|
udpstat.udps_noport++;
|
|
|
|
udpstat.udps_noportmcast++;
|
|
|
|
goto bad;
|
|
|
|
}
|
2006-05-01 21:39:48 +00:00
|
|
|
INP_LOCK(last);
|
|
|
|
udp6_append(last, m, off, &fromsa);
|
|
|
|
INP_UNLOCK(last);
|
2006-04-12 03:23:56 +00:00
|
|
|
INP_INFO_RUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Locate pcb for datagram.
|
|
|
|
*/
|
|
|
|
in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
|
|
|
|
&ip6->ip6_dst, uh->uh_dport, 1,
|
|
|
|
m->m_pkthdr.rcvif);
|
2006-04-12 03:32:54 +00:00
|
|
|
if (in6p == NULL) {
|
1999-12-07 17:39:16 +00:00
|
|
|
if (log_in_vain) {
|
2006-12-12 12:17:58 +00:00
|
|
|
char ip6bufs[INET6_ADDRSTRLEN];
|
|
|
|
char ip6bufd[INET6_ADDRSTRLEN];
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
log(LOG_INFO,
|
2002-08-19 19:47:13 +00:00
|
|
|
"Connection attempt to UDP [%s]:%d from [%s]:%d\n",
|
2006-12-12 12:17:58 +00:00
|
|
|
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
|
|
|
|
ntohs(uh->uh_dport),
|
|
|
|
ip6_sprintf(ip6bufs, &ip6->ip6_src),
|
|
|
|
ntohs(uh->uh_sport));
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
udpstat.udps_noport++;
|
|
|
|
if (m->m_flags & M_MCAST) {
|
|
|
|
printf("UDP6: M_MCAST is set in a unicast packet.\n");
|
|
|
|
udpstat.udps_noportmcast++;
|
|
|
|
goto bad;
|
|
|
|
}
|
2006-04-12 03:23:56 +00:00
|
|
|
INP_INFO_RUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
2006-04-12 03:32:54 +00:00
|
|
|
INP_LOCK(in6p);
|
2006-05-01 21:39:48 +00:00
|
|
|
udp6_append(in6p, m, off, &fromsa);
|
2006-04-12 03:32:54 +00:00
|
|
|
INP_UNLOCK(in6p);
|
2006-04-12 03:23:56 +00:00
|
|
|
INP_INFO_RUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
return IPPROTO_DONE;
|
|
|
|
bad:
|
2006-04-12 03:23:56 +00:00
|
|
|
INP_INFO_RUNLOCK(&udbinfo);
|
|
|
|
bad_unlocked:
|
1999-12-07 17:39:16 +00:00
|
|
|
if (m)
|
|
|
|
m_freem(m);
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
udp6_ctlinput(cmd, sa, d)
|
|
|
|
int cmd;
|
|
|
|
struct sockaddr *sa;
|
|
|
|
void *d;
|
|
|
|
{
|
|
|
|
struct udphdr uh;
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
struct mbuf *m;
|
2000-07-04 16:35:15 +00:00
|
|
|
int off = 0;
|
2001-06-11 12:39:29 +00:00
|
|
|
struct ip6ctlparam *ip6cp = NULL;
|
|
|
|
const struct sockaddr_in6 *sa6_src = NULL;
|
2004-02-13 14:50:01 +00:00
|
|
|
void *cmdarg;
|
2002-06-14 08:35:21 +00:00
|
|
|
struct inpcb *(*notify) __P((struct inpcb *, int)) = udp_notify;
|
2001-06-11 12:39:29 +00:00
|
|
|
struct udp_portonly {
|
|
|
|
u_int16_t uh_sport;
|
|
|
|
u_int16_t uh_dport;
|
|
|
|
} *uhp;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
if (sa->sa_family != AF_INET6 ||
|
|
|
|
sa->sa_len != sizeof(struct sockaddr_in6))
|
|
|
|
return;
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
if ((unsigned)cmd >= PRC_NCMDS)
|
|
|
|
return;
|
|
|
|
if (PRC_IS_REDIRECT(cmd))
|
|
|
|
notify = in6_rtchange, d = NULL;
|
|
|
|
else if (cmd == PRC_HOSTDEAD)
|
|
|
|
d = NULL;
|
|
|
|
else if (inet6ctlerrmap[cmd] == 0)
|
1999-12-07 17:39:16 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* if the parameter is from icmp6, decode it. */
|
|
|
|
if (d != NULL) {
|
2001-06-11 12:39:29 +00:00
|
|
|
ip6cp = (struct ip6ctlparam *)d;
|
1999-12-07 17:39:16 +00:00
|
|
|
m = ip6cp->ip6c_m;
|
|
|
|
ip6 = ip6cp->ip6c_ip6;
|
|
|
|
off = ip6cp->ip6c_off;
|
2004-02-13 14:50:01 +00:00
|
|
|
cmdarg = ip6cp->ip6c_cmdarg;
|
2001-06-11 12:39:29 +00:00
|
|
|
sa6_src = ip6cp->ip6c_src;
|
1999-12-07 17:39:16 +00:00
|
|
|
} else {
|
|
|
|
m = NULL;
|
|
|
|
ip6 = NULL;
|
2004-02-13 14:50:01 +00:00
|
|
|
cmdarg = NULL;
|
2001-06-11 12:39:29 +00:00
|
|
|
sa6_src = &sa6_any;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ip6) {
|
|
|
|
/*
|
|
|
|
* XXX: We assume that when IPV6 is non NULL,
|
|
|
|
* M and OFF are valid.
|
|
|
|
*/
|
|
|
|
|
2000-10-23 07:11:01 +00:00
|
|
|
/* check if we can safely examine src and dst ports */
|
2001-06-11 12:39:29 +00:00
|
|
|
if (m->m_pkthdr.len < off + sizeof(*uhp))
|
2000-10-23 07:11:01 +00:00
|
|
|
return;
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
bzero(&uh, sizeof(uh));
|
|
|
|
m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
|
|
|
|
|
2004-08-06 03:45:45 +00:00
|
|
|
(void) in6_pcbnotify(&udbinfo, sa, uh.uh_dport,
|
2004-02-13 14:50:01 +00:00
|
|
|
(struct sockaddr *)ip6cp->ip6c_src,
|
|
|
|
uh.uh_sport, cmd, cmdarg, notify);
|
1999-12-07 17:39:16 +00:00
|
|
|
} else
|
2004-08-06 03:45:45 +00:00
|
|
|
(void) in6_pcbnotify(&udbinfo, sa, 0,
|
2002-02-27 02:44:45 +00:00
|
|
|
(const struct sockaddr *)sa6_src,
|
2004-02-13 14:50:01 +00:00
|
|
|
0, cmd, cmdarg, notify);
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
udp6_getcred(SYSCTL_HANDLER_ARGS)
|
1999-12-07 17:39:16 +00:00
|
|
|
{
|
2001-02-18 13:30:20 +00:00
|
|
|
struct xucred xuc;
|
1999-12-07 17:39:16 +00:00
|
|
|
struct sockaddr_in6 addrs[2];
|
|
|
|
struct inpcb *inp;
|
2006-04-12 03:03:47 +00:00
|
|
|
int error;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2006-11-06 13:42:10 +00:00
|
|
|
error = priv_check_cred(req->td->td_ucred, PRIV_NETINET_GETCRED,
|
|
|
|
SUSER_ALLOWJAIL);
|
1999-12-07 17:39:16 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
if (req->newlen != sizeof(addrs))
|
|
|
|
return (EINVAL);
|
2001-02-18 13:30:20 +00:00
|
|
|
if (req->oldlen != sizeof(struct xucred))
|
2000-07-04 16:35:15 +00:00
|
|
|
return (EINVAL);
|
1999-12-07 17:39:16 +00:00
|
|
|
error = SYSCTL_IN(req, addrs, sizeof(addrs));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
2005-07-25 12:31:43 +00:00
|
|
|
if ((error = sa6_embedscope(&addrs[0], ip6_use_defzone)) != 0 ||
|
|
|
|
(error = sa6_embedscope(&addrs[1], ip6_use_defzone)) != 0) {
|
|
|
|
return (error);
|
|
|
|
}
|
2006-04-12 03:03:47 +00:00
|
|
|
INP_INFO_RLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr,
|
|
|
|
addrs[1].sin6_port,
|
|
|
|
&addrs[0].sin6_addr, addrs[0].sin6_port,
|
|
|
|
1, NULL);
|
2006-04-12 03:03:47 +00:00
|
|
|
if (inp == NULL) {
|
|
|
|
INP_INFO_RUNLOCK(&udbinfo);
|
|
|
|
return (ENOENT);
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
2006-04-12 03:03:47 +00:00
|
|
|
INP_LOCK(inp);
|
|
|
|
KASSERT(inp->inp_socket != NULL,
|
|
|
|
("udp6_getcred: inp_socket == NULL"));
|
2002-02-27 04:45:37 +00:00
|
|
|
cru2x(inp->inp_socket->so_cred, &xuc);
|
2006-04-12 03:03:47 +00:00
|
|
|
INP_UNLOCK(inp);
|
|
|
|
INP_INFO_RUNLOCK(&udbinfo);
|
2001-02-18 13:30:20 +00:00
|
|
|
error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
|
1999-12-07 17:39:16 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
|
|
|
|
0, 0,
|
2001-02-18 13:30:20 +00:00
|
|
|
udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection");
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2006-04-01 15:15:05 +00:00
|
|
|
static void
|
1999-12-07 17:39:16 +00:00
|
|
|
udp6_abort(struct socket *so)
|
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
KASSERT(inp != NULL, ("udp6_abort: inp == NULL"));
|
2006-04-12 03:03:47 +00:00
|
|
|
|
2006-07-21 17:11:15 +00:00
|
|
|
#ifdef INET
|
|
|
|
if (inp->inp_vflag & INP_IPV4) {
|
|
|
|
struct pr_usrreqs *pru;
|
|
|
|
|
|
|
|
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
|
|
|
|
(*pru->pru_abort)(so);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
2005-06-01 11:38:19 +00:00
|
|
|
INP_LOCK(inp);
|
2006-07-21 17:11:15 +00:00
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
|
|
|
in6_pcbdisconnect(inp);
|
|
|
|
inp->in6p_laddr = in6addr_any;
|
|
|
|
soisdisconnected(so);
|
|
|
|
}
|
|
|
|
INP_UNLOCK(inp);
|
2005-06-01 11:38:19 +00:00
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
udp6_attach(struct socket *so, int proto, struct thread *td)
|
1999-12-07 17:39:16 +00:00
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
2006-04-12 03:03:47 +00:00
|
|
|
int error;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
2006-04-09 16:33:41 +00:00
|
|
|
KASSERT(inp == NULL, ("udp6_attach: inp != NULL"));
|
2006-04-12 03:03:47 +00:00
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
|
|
|
|
error = soreserve(so, udp_sendspace, udp_recvspace);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
if (error)
|
1999-12-07 17:39:16 +00:00
|
|
|
return error;
|
|
|
|
}
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
2006-07-18 22:34:27 +00:00
|
|
|
error = in_pcballoc(so, &udbinfo);
|
2004-07-27 23:44:03 +00:00
|
|
|
if (error) {
|
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
return error;
|
2004-07-27 23:44:03 +00:00
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
inp = (struct inpcb *)so->so_pcb;
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
inp->inp_vflag |= INP_IPV6;
|
2006-02-02 11:46:05 +00:00
|
|
|
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
|
2002-07-15 19:25:46 +00:00
|
|
|
inp->inp_vflag |= INP_IPV4;
|
1999-12-07 17:39:16 +00:00
|
|
|
inp->in6p_hops = -1; /* use kernel default */
|
|
|
|
inp->in6p_cksum = -1; /* just to be sure */
|
2000-06-22 16:48:59 +00:00
|
|
|
/*
|
|
|
|
* 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->inp_ip_ttl = ip_defttl;
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_UNLOCK(inp);
|
1999-12-07 17:39:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
1999-12-07 17:39:16 +00:00
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
2006-04-12 03:03:47 +00:00
|
|
|
int error;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
|
2006-04-12 03:03:47 +00:00
|
|
|
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_LOCK(inp);
|
1999-12-07 17:39:16 +00:00
|
|
|
inp->inp_vflag &= ~INP_IPV4;
|
|
|
|
inp->inp_vflag |= INP_IPV6;
|
2001-06-11 12:39:29 +00:00
|
|
|
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
|
1999-12-07 17:39:16 +00:00
|
|
|
struct sockaddr_in6 *sin6_p;
|
|
|
|
|
|
|
|
sin6_p = (struct sockaddr_in6 *)nam;
|
|
|
|
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
|
|
|
|
inp->inp_vflag |= INP_IPV4;
|
|
|
|
else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
|
|
|
|
in6_sin6_2_sin(&sin, sin6_p);
|
|
|
|
inp->inp_vflag |= INP_IPV4;
|
|
|
|
inp->inp_vflag &= ~INP_IPV6;
|
2004-03-27 21:05:46 +00:00
|
|
|
error = in_pcbbind(inp, (struct sockaddr *)&sin,
|
|
|
|
td->td_ucred);
|
2004-07-27 23:44:03 +00:00
|
|
|
goto out;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-27 21:05:46 +00:00
|
|
|
error = in6_pcbbind(inp, nam, td->td_ucred);
|
2004-07-27 23:44:03 +00:00
|
|
|
out:
|
|
|
|
INP_UNLOCK(inp);
|
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2006-07-21 17:11:15 +00:00
|
|
|
static void
|
|
|
|
udp6_close(struct socket *so)
|
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
|
|
|
KASSERT(inp != NULL, ("udp6_close: inp == NULL"));
|
|
|
|
|
|
|
|
#ifdef INET
|
|
|
|
if (inp->inp_vflag & INP_IPV4) {
|
|
|
|
struct pr_usrreqs *pru;
|
|
|
|
|
|
|
|
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
|
|
|
|
(*pru->pru_disconnect)(so);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
|
|
|
INP_LOCK(inp);
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
|
|
|
in6_pcbdisconnect(inp);
|
|
|
|
inp->in6p_laddr = in6addr_any;
|
|
|
|
soisdisconnected(so);
|
|
|
|
}
|
|
|
|
INP_UNLOCK(inp);
|
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
|
|
|
}
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
1999-12-07 17:39:16 +00:00
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
2006-04-12 03:03:47 +00:00
|
|
|
int error;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
|
2006-04-12 03:03:47 +00:00
|
|
|
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_LOCK(inp);
|
2001-06-11 12:39:29 +00:00
|
|
|
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
|
1999-12-07 17:39:16 +00:00
|
|
|
struct sockaddr_in6 *sin6_p;
|
|
|
|
|
|
|
|
sin6_p = (struct sockaddr_in6 *)nam;
|
|
|
|
if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
|
2006-05-20 13:26:08 +00:00
|
|
|
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
|
|
|
error = EISCONN;
|
|
|
|
goto out;
|
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
in6_sin6_2_sin(&sin, sin6_p);
|
2004-03-27 21:05:46 +00:00
|
|
|
error = in_pcbconnect(inp, (struct sockaddr *)&sin,
|
|
|
|
td->td_ucred);
|
1999-12-21 11:14:12 +00:00
|
|
|
if (error == 0) {
|
1999-12-07 17:39:16 +00:00
|
|
|
inp->inp_vflag |= INP_IPV4;
|
|
|
|
inp->inp_vflag &= ~INP_IPV6;
|
|
|
|
soisconnected(so);
|
|
|
|
}
|
2004-07-27 23:44:03 +00:00
|
|
|
goto out;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
}
|
2004-07-27 23:44:03 +00:00
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
|
|
|
error = EISCONN;
|
|
|
|
goto out;
|
|
|
|
}
|
2004-03-27 21:05:46 +00:00
|
|
|
error = in6_pcbconnect(inp, nam, td->td_ucred);
|
1999-12-21 11:14:12 +00:00
|
|
|
if (error == 0) {
|
2006-02-02 11:46:05 +00:00
|
|
|
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
|
|
|
|
/* should be non mapped addr */
|
2001-06-11 12:39:29 +00:00
|
|
|
inp->inp_vflag &= ~INP_IPV4;
|
|
|
|
inp->inp_vflag |= INP_IPV6;
|
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
soisconnected(so);
|
|
|
|
}
|
2004-07-27 23:44:03 +00:00
|
|
|
out:
|
|
|
|
INP_UNLOCK(inp);
|
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
Chance protocol switch method pru_detach() so that it returns void
rather than an error. Detaches do not "fail", they other occur or
the protocol flags SS_PROTOREF to take ownership of the socket.
soclose() no longer looks at so_pcb to see if it's NULL, relying
entirely on the protocol to decide whether it's time to free the
socket or not using SS_PROTOREF. so_pcb is now entirely owned and
managed by the protocol code. Likewise, no longer test so_pcb in
other socket functions, such as soreceive(), which have no business
digging into protocol internals.
Protocol detach routines no longer try to free the socket on detach,
this is performed in the socket code if the protocol permits it.
In rts_detach(), no longer test for rp != NULL in detach, and
likewise in other protocols that don't permit a NULL so_pcb, reduce
the incidence of testing for it during detach.
netinet and netinet6 are not fully updated to this change, which
will be in an upcoming commit. In their current state they may leak
memory or panic.
MFC after: 3 months
2006-04-01 15:42:02 +00:00
|
|
|
static void
|
1999-12-07 17:39:16 +00:00
|
|
|
udp6_detach(struct socket *so)
|
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
KASSERT(inp != NULL, ("udp6_detach: inp == NULL"));
|
2006-04-12 03:03:47 +00:00
|
|
|
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_LOCK(inp);
|
1999-12-07 17:39:16 +00:00
|
|
|
in6_pcbdetach(inp);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
in6_pcbfree(inp);
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
udp6_disconnect(struct socket *so)
|
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
2006-04-12 03:03:47 +00:00
|
|
|
int error;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
|
2006-04-12 03:03:47 +00:00
|
|
|
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_LOCK(inp);
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2004-02-13 15:11:47 +00:00
|
|
|
#ifdef INET
|
1999-12-07 17:39:16 +00:00
|
|
|
if (inp->inp_vflag & INP_IPV4) {
|
|
|
|
struct pr_usrreqs *pru;
|
|
|
|
|
|
|
|
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
|
2004-07-27 23:44:03 +00:00
|
|
|
error = (*pru->pru_disconnect)(so);
|
|
|
|
goto out;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
2004-02-13 15:11:47 +00:00
|
|
|
#endif
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2004-07-27 23:44:03 +00:00
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
|
|
|
error = ENOTCONN;
|
|
|
|
goto out;
|
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
in6_pcbdisconnect(inp);
|
|
|
|
inp->in6p_laddr = in6addr_any;
|
2004-07-27 23:44:03 +00:00
|
|
|
/* XXXRW: so_state locking? */
|
1999-12-07 17:39:16 +00:00
|
|
|
so->so_state &= ~SS_ISCONNECTED; /* XXX */
|
2004-07-27 23:44:03 +00:00
|
|
|
out:
|
|
|
|
INP_UNLOCK(inp);
|
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
1999-12-07 17:39:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
2001-09-12 08:38:13 +00:00
|
|
|
struct mbuf *control, struct thread *td)
|
1999-12-07 17:39:16 +00:00
|
|
|
{
|
|
|
|
struct inpcb *inp;
|
2000-07-04 16:35:15 +00:00
|
|
|
int error = 0;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
inp = sotoinpcb(so);
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
KASSERT(inp != NULL, ("udp6_send: inp == NULL"));
|
2006-04-12 03:03:47 +00:00
|
|
|
|
Update in_pcb-derived basic socket types following changes to
pru_abort(), pru_detach(), and in_pcbdetach():
- Universally support and enforce the invariant that so_pcb is
never NULL, converting dozens of unnecessary NULL checks into
assertions, and eliminating dozens of unnecessary error handling
cases in protocol code.
- In some cases, eliminate unnecessary pcbinfo locking, as it is no
longer required to ensure so_pcb != NULL. For example, in protocol
shutdown methods, and in raw IP send.
- Abort and detach protocol switch methods no longer return failures,
nor attempt to free sockets, as the socket layer does this.
- Invoke in_pcbfree() after in_pcbdetach() in order to free the
detached in_pcb structure for a socket.
MFC after: 3 months
2006-04-01 16:20:54 +00:00
|
|
|
INP_INFO_WLOCK(&udbinfo);
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_LOCK(inp);
|
2000-07-04 16:35:15 +00:00
|
|
|
if (addr) {
|
|
|
|
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (addr->sa_family != AF_INET6) {
|
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-13 15:11:47 +00:00
|
|
|
#ifdef INET
|
2006-02-02 11:46:05 +00:00
|
|
|
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
|
1999-12-07 17:39:16 +00:00
|
|
|
int hasv4addr;
|
|
|
|
struct sockaddr_in6 *sin6 = 0;
|
|
|
|
|
|
|
|
if (addr == 0)
|
|
|
|
hasv4addr = (inp->inp_vflag & INP_IPV4);
|
|
|
|
else {
|
|
|
|
sin6 = (struct sockaddr_in6 *)addr;
|
|
|
|
hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
|
|
|
|
? 1 : 0;
|
|
|
|
}
|
|
|
|
if (hasv4addr) {
|
|
|
|
struct pr_usrreqs *pru;
|
|
|
|
|
2004-02-13 15:11:47 +00:00
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) &&
|
|
|
|
!IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) {
|
|
|
|
/*
|
|
|
|
* when remote addr is IPv4-mapped
|
|
|
|
* address, local addr should not be
|
|
|
|
* an IPv6 address; since you cannot
|
|
|
|
* determine how to map IPv6 source
|
|
|
|
* address to IPv4.
|
|
|
|
*/
|
2004-07-27 23:44:03 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
2004-02-13 15:11:47 +00:00
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
if (sin6)
|
|
|
|
in6_sin6_2_sin_in_sock(addr);
|
|
|
|
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
|
|
|
|
error = ((*pru->pru_send)(so, flags, m, addr, control,
|
2001-09-12 08:38:13 +00:00
|
|
|
td));
|
1999-12-07 17:39:16 +00:00
|
|
|
/* addr will just be freed in sendit(). */
|
2004-07-27 23:44:03 +00:00
|
|
|
goto out;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
}
|
2004-02-13 15:11:47 +00:00
|
|
|
#endif
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2004-07-27 23:44:03 +00:00
|
|
|
error = udp6_output(inp, m, addr, control, td);
|
|
|
|
out:
|
|
|
|
INP_UNLOCK(inp);
|
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
|
|
|
return error;
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
bad:
|
2004-07-27 23:44:03 +00:00
|
|
|
INP_UNLOCK(inp);
|
|
|
|
INP_INFO_WUNLOCK(&udbinfo);
|
2000-07-04 16:35:15 +00:00
|
|
|
m_freem(m);
|
2003-10-06 14:02:09 +00:00
|
|
|
return (error);
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct pr_usrreqs udp6_usrreqs = {
|
2004-11-08 14:44:54 +00:00
|
|
|
.pru_abort = udp6_abort,
|
|
|
|
.pru_attach = udp6_attach,
|
|
|
|
.pru_bind = udp6_bind,
|
|
|
|
.pru_connect = udp6_connect,
|
|
|
|
.pru_control = in6_control,
|
|
|
|
.pru_detach = udp6_detach,
|
|
|
|
.pru_disconnect = udp6_disconnect,
|
|
|
|
.pru_peeraddr = in6_mapped_peeraddr,
|
|
|
|
.pru_send = udp6_send,
|
|
|
|
.pru_shutdown = udp_shutdown,
|
|
|
|
.pru_sockaddr = in6_mapped_sockaddr,
|
2006-07-21 17:11:15 +00:00
|
|
|
.pru_sosetlabel = in_pcbsosetlabel,
|
|
|
|
.pru_close = udp6_close
|
1999-12-07 17:39:16 +00:00
|
|
|
};
|