📄 udp_usrreq.c
字号:
//==========================================================================
//
// sys/netinet/udp_usrreq.c
//
//
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-01-10
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
/* $OpenBSD: udp_usrreq.c,v 1.30 1999/12/12 10:59:41 itojun Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1990, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 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_usrreq.c 8.4 (Berkeley) 1/21/94
*/
/*
%%% portions-copyright-nrl-95
Portions of this software are Copyright 1995-1998 by Randall Atkinson,
Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
Reserved. All rights under this copyright have been assigned to the US
Naval Research Laboratory (NRL). The NRL Copyright Notice and License
Agreement Version 1.1 (January 17, 1995) applies to these portions of the
software.
You should have received a copy of the license with this software. If you
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/errno.h>
#ifdef __ECOS
#undef errno
#endif
#ifndef __ECOS
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <vm/vm.h>
#include <sys/sysctl.h>
#endif
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#ifdef IPSEC
#include <netinet/ip_ipsp.h>
extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#endif
#include <machine/stdarg.h>
#ifdef INET6
#ifndef INET
#include <netinet/in.h>
#endif
#include <netinet6/ip6.h>
#include <netinet6/in6_var.h>
#include <netinet6/ip6_var.h>
#include <netinet6/icmp6.h>
#include <netinet6/ip6protosw.h>
#ifndef CREATE_IPV6_MAPPED
#define CREATE_IPV6_MAPPED(a6, a4) \
do { \
bzero(&(a6), sizeof(a6)); \
(a6).s6_addr[10] = (a6).s6_addr[11] = 0xff; \
*(u_int32_t *)&(a6).s6_addr[12] = (a4); \
} while (0)
#endif
extern int ip6_defhlim;
#endif /* INET6 */
/*
* UDP protocol implementation.
* Per RFC 768, August, 1980.
*/
int udpcksum = 1;
static void udp_detach __P((struct inpcb *));
static void udp_notify __P((struct inpcb *, int));
static struct mbuf *udp_saveopt __P((caddr_t, int, int));
#ifndef UDBHASHSIZE
#define UDBHASHSIZE 128
#endif
int udbhashsize = UDBHASHSIZE;
/* from in_pcb.c */
extern struct baddynamicports baddynamicports;
void
udp_init()
{
in_pcbinit(&udbtable, udbhashsize);
}
#if defined(INET6) && !defined(TCP6)
int
udp6_input(mp, offp, proto)
struct mbuf **mp;
int *offp, proto;
{
struct mbuf *m = *mp;
#if defined(NFAITH) && 0 < NFAITH
if (m->m_pkthdr.rcvif) {
if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
/* XXX send icmp6 host/port unreach? */
m_freem(m);
return IPPROTO_DONE;
}
}
#endif
udp_input(m, *offp, proto);
return IPPROTO_DONE;
}
#endif
void
#if __STDC__
udp_input(struct mbuf *m, ...)
#else
udp_input(m, va_alist)
struct mbuf *m;
va_dcl
#endif
{
register struct ip *ip;
register struct udphdr *uh;
register struct inpcb *inp;
struct mbuf *opts = 0;
int len;
struct ip save_ip;
int iphlen;
va_list ap;
u_int16_t savesum;
union {
struct sockaddr sa;
struct sockaddr_in sin;
#ifdef INET6
struct sockaddr_in6 sin6;
#endif /* INET6 */
} srcsa, dstsa;
#ifdef INET6
struct ip6_hdr *ipv6;
struct sockaddr_in6 src_v4mapped;
#endif /* INET6 */
#ifdef IPSEC
struct tdb *tdb = NULL;
#endif /* IPSEC */
va_start(ap, m);
iphlen = va_arg(ap, int);
va_end(ap);
udpstat.udps_ipackets++;
#ifdef IPSEC
/* Save the last SA which was used to process the mbuf */
if ((m->m_flags & (M_CONF|M_AUTH)) && m->m_pkthdr.tdbi) {
struct tdb_ident *tdbi = m->m_pkthdr.tdbi;
/* XXX gettdb() should really be called at spltdb(). */
/* XXX this is splsoftnet(), currently they are the same. */
tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
free(m->m_pkthdr.tdbi, M_TEMP);
m->m_pkthdr.tdbi = NULL;
}
#endif /* IPSEC */
switch (mtod(m, struct ip *)->ip_v) {
case 4:
ip = mtod(m, struct ip *);
#ifdef INET6
ipv6 = NULL;
#endif /* INET6 */
srcsa.sa.sa_family = AF_INET;
break;
#ifdef INET6
case 6:
ip = NULL;
ipv6 = mtod(m, struct ip6_hdr *);
srcsa.sa.sa_family = AF_INET6;
break;
#endif /* INET6 */
default:
#ifdef __ECOS
diag_printf("udp_input: received unknown IP version %d",
mtod(m, struct ip *)->ip_v);
#else
printf("udp_input: received unknown IP version %d",
mtod(m, struct ip *)->ip_v);
#endif
goto bad;
}
/*
* Strip IP options, if any; should skip this,
* make available to user, and use on returned packets,
* but we don't yet have a way to check the checksum
* with options still present.
*/
/*
* (contd. from above...) Furthermore, we may want to strip options
* for such things as ICMP errors, where options just get in the way.
*/
if (ip && iphlen > sizeof (struct ip)) {
ip_stripoptions(m, (struct mbuf *)0);
iphlen = sizeof(struct ip);
}
/*
* Get IP and UDP header together in first mbuf.
*/
if (m->m_len < iphlen + sizeof(struct udphdr)) {
if ((m = m_pullup2(m, iphlen + sizeof(struct udphdr))) == 0) {
udpstat.udps_hdrops++;
return;
}
#ifdef INET6
if (ipv6)
ipv6 = mtod(m, struct ip6_hdr *);
else
#endif /* INET6 */
ip = mtod(m, struct ip *);
}
uh = (struct udphdr *)(mtod(m, caddr_t) + iphlen);
/*
* Make mbuf data length reflect UDP length.
* If not enough data to reflect UDP length, drop.
*/
len = ntohs((u_int16_t)uh->uh_ulen);
if (m->m_pkthdr.len - iphlen != len) {
if (len > (m->m_pkthdr.len - iphlen) ||
len < sizeof(struct udphdr)) {
udpstat.udps_badlen++;
goto bad;
}
m_adj(m, len - (m->m_pkthdr.len - iphlen));
}
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
*/
if (ip)
save_ip = *ip;
/*
* Checksum extended UDP header and data.
* from W.R.Stevens: check incoming udp cksums even if
* udpcksum is not set.
*/
savesum = uh->uh_sum;
#ifdef INET6
if (ipv6) {
/*
* In IPv6, the UDP checksum is ALWAYS used.
*/
if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, iphlen, len))) {
udpstat.udps_badsum++;
goto bad;
}
} else
#endif /* INET6 */
if (uh->uh_sum) {
bzero(((struct ipovly *)ip)->ih_x1,
sizeof ((struct ipovly *)ip)->ih_x1);
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) {
udpstat.udps_badsum++;
m_freem(m);
return;
}
} else
udpstat.udps_nosum++;
switch (srcsa.sa.sa_family) {
case AF_INET:
bzero(&srcsa, sizeof(struct sockaddr_in));
srcsa.sin.sin_len = sizeof(struct sockaddr_in);
srcsa.sin.sin_family = AF_INET;
srcsa.sin.sin_port = uh->uh_sport;
srcsa.sin.sin_addr = ip->ip_src;
#ifdef INET6
bzero(&src_v4mapped, sizeof(struct sockaddr_in6));
src_v4mapped.sin6_len = sizeof(struct sockaddr_in6);
src_v4mapped.sin6_family = AF_INET6;
src_v4mapped.sin6_port = uh->uh_sport;
CREATE_IPV6_MAPPED(src_v4mapped.sin6_addr, ip->ip_src.s_addr);
#endif /* INET6 */
bzero(&dstsa, sizeof(struct sockaddr_in));
dstsa.sin.sin_len = sizeof(struct sockaddr_in);
dstsa.sin.sin_family = AF_INET;
dstsa.sin.sin_port = uh->uh_dport;
dstsa.sin.sin_addr = ip->ip_dst;
break;
#ifdef INET6
case AF_INET6:
bzero(&srcsa, sizeof(struct sockaddr_in6));
srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
srcsa.sin6.sin6_family = AF_INET6;
srcsa.sin6.sin6_port = uh->uh_sport;
srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ipv6->ip6_flow;
srcsa.sin6.sin6_addr = ipv6->ip6_src;
if (IN6_IS_SCOPE_LINKLOCAL(&srcsa.sin6.sin6_addr))
srcsa.sin6.sin6_addr.s6_addr16[1] = 0;
if (m->m_pkthdr.rcvif) {
if (IN6_IS_SCOPE_LINKLOCAL(&srcsa.sin6.sin6_addr)) {
srcsa.sin6.sin6_scope_id =
m->m_pkthdr.rcvif->if_index;
} else
srcsa.sin6.sin6_scope_id = 0;
} else
srcsa.sin6.sin6_scope_id = 0;
bzero(&dstsa, sizeof(struct sockaddr_in6));
dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
dstsa.sin6.sin6_family = AF_INET6;
dstsa.sin6.sin6_port = uh->uh_dport;
dstsa.sin6.sin6_addr = ipv6->ip6_dst;
break;
#endif /* INET6 */
}
#ifdef INET6
if ((ipv6 && IN6_IS_ADDR_MULTICAST(&ipv6->ip6_dst)) ||
(ip && IN_MULTICAST(ip->ip_dst.s_addr)) ||
(ip && in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) {
#else /* INET6 */
if (IN_MULTICAST(ip->ip_dst.s_addr) ||
in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
#endif /* INET6 */
struct socket *last;
/*
* Deliver a multicast or broadcast 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 multi/broadcasts 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?)
*/
iphlen += sizeof(struct udphdr);
/*
* Locate pcb(s) for datagram.
* (Algorithm copied from raw_intr().)
*/
last = NULL;
for (inp = udbtable.inpt_queue.cqh_first;
inp != (struct inpcb *)&udbtable.inpt_queue;
inp = inp->inp_queue.cqe_next) {
if (inp->inp_lport != uh->uh_dport)
continue;
#ifdef INET6
if (ipv6) {
if (!(inp->inp_flags & INP_IPV6))
continue;
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
&ipv6->ip6_dst))
continue;
} else
#endif /* INET6 */
if (inp->inp_laddr.s_addr != INADDR_ANY) {
if (inp->inp_laddr.s_addr !=
ip->ip_dst.s_addr)
continue;
}
#ifdef INET6
if (ipv6) {
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
&ipv6->ip6_src) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -