version 1.37, 1996/09/30 16:16:45 |
version 1.47.6.2, 1999/07/06 11:02:51 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 1982, 1986, 1988, 1990, 1993 |
* 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. |
|
*/ |
|
|
|
/* |
|
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 |
* The Regents of the University of California. All rights reserved. |
* The Regents of the University of California. All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
* |
* |
* @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 |
* @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 |
*/ |
*/ |
#include "kgdb.h" |
|
|
/* MAPPED_ADDR_ENABLE must be revisited */ |
|
|
|
#include "ipkdb.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
#include <sys/mbuf.h> |
#include <sys/mbuf.h> |
|
#ifdef MAPPED_ADDR_ENABLED |
|
#include <sys/domain.h> |
|
#endif /* MAPPED_ADDR_ENABLED */ |
#include <sys/protosw.h> |
#include <sys/protosw.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
#include <sys/socketvar.h> |
#include <sys/socketvar.h> |
|
|
|
|
#include <machine/stdarg.h> |
#include <machine/stdarg.h> |
|
|
|
#ifdef IPSEC |
|
#include <netinet6/ipsec.h> |
|
#include <netkey/key.h> |
|
#include <netkey/key_debug.h> |
|
#endif /*IPSEC*/ |
|
|
/* |
/* |
* UDP protocol implementation. |
* UDP protocol implementation. |
* Per RFC 768, August, 1980. |
* Per RFC 768, August, 1980. |
Line 76 int udpcksum = 0; /* XXX */ |
|
Line 117 int udpcksum = 0; /* XXX */ |
|
#endif |
#endif |
|
|
static void udp_notify __P((struct inpcb *, int)); |
static void udp_notify __P((struct inpcb *, int)); |
static struct mbuf *udp_saveopt __P((caddr_t, int, int)); |
|
|
|
#ifndef UDBHASHSIZE |
#ifndef UDBHASHSIZE |
#define UDBHASHSIZE 128 |
#define UDBHASHSIZE 128 |
Line 99 udp_input(m, va_alist) |
|
Line 139 udp_input(m, va_alist) |
|
va_dcl |
va_dcl |
#endif |
#endif |
{ |
{ |
|
int proto; |
register struct ip *ip; |
register struct ip *ip; |
register struct udphdr *uh; |
register struct udphdr *uh; |
register struct inpcb *inp; |
register struct inpcb *inp; |
Line 108 udp_input(m, va_alist) |
|
Line 149 udp_input(m, va_alist) |
|
int iphlen; |
int iphlen; |
va_list ap; |
va_list ap; |
struct sockaddr_in udpsrc; |
struct sockaddr_in udpsrc; |
|
#ifdef MAPPED_ADDR_ENABLED |
|
struct sockaddr_in6 mapped; |
|
#endif |
|
struct sockaddr *sa; |
|
|
va_start(ap, m); |
va_start(ap, m); |
iphlen = va_arg(ap, int); |
iphlen = va_arg(ap, int); |
|
proto = va_arg(ap, int); |
va_end(ap); |
va_end(ap); |
|
|
udpstat.udps_ipackets++; |
udpstat.udps_ipackets++; |
Line 144 udp_input(m, va_alist) |
|
Line 190 udp_input(m, va_alist) |
|
* If not enough data to reflect UDP length, drop. |
* If not enough data to reflect UDP length, drop. |
*/ |
*/ |
len = ntohs((u_int16_t)uh->uh_ulen); |
len = ntohs((u_int16_t)uh->uh_ulen); |
if (ip->ip_len != len) { |
if (ip->ip_len != iphlen + len) { |
if (len > ip->ip_len) { |
if (ip->ip_len < iphlen + len) { |
udpstat.udps_badlen++; |
udpstat.udps_badlen++; |
goto bad; |
goto bad; |
} |
} |
m_adj(m, len - ip->ip_len); |
m_adj(m, iphlen + len - ip->ip_len); |
/* ip->ip_len = len; */ |
|
} |
} |
/* |
/* |
* Save a copy of the IP header in case we want restore it |
* Save a copy of the IP header in case we want restore it |
Line 165 udp_input(m, va_alist) |
|
Line 210 udp_input(m, va_alist) |
|
bzero(((struct ipovly *)ip)->ih_x1, |
bzero(((struct ipovly *)ip)->ih_x1, |
sizeof ((struct ipovly *)ip)->ih_x1); |
sizeof ((struct ipovly *)ip)->ih_x1); |
((struct ipovly *)ip)->ih_len = uh->uh_ulen; |
((struct ipovly *)ip)->ih_len = uh->uh_ulen; |
if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) { |
if (in_cksum(m, len + sizeof (struct ip)) != 0) { |
udpstat.udps_badsum++; |
udpstat.udps_badsum++; |
m_freem(m); |
m_freem(m); |
return; |
return; |
} |
} |
} |
} |
|
|
|
/* |
|
* Construct sockaddr format source address. |
|
*/ |
|
udpsrc.sin_family = AF_INET; |
|
udpsrc.sin_len = sizeof(struct sockaddr_in); |
|
udpsrc.sin_addr = ip->ip_src; |
|
udpsrc.sin_port = uh->uh_sport; |
|
bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero)); |
|
|
if (IN_MULTICAST(ip->ip_dst.s_addr) || |
if (IN_MULTICAST(ip->ip_dst.s_addr) || |
in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { |
in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { |
struct socket *last; |
struct inpcb *last; |
/* |
/* |
* Deliver a multicast or broadcast datagram to *all* sockets |
* Deliver a multicast or broadcast datagram to *all* sockets |
* for which the local and remote addresses and ports match |
* for which the local and remote addresses and ports match |
Line 191 udp_input(m, va_alist) |
|
Line 245 udp_input(m, va_alist) |
|
* fixing the interface. Maybe 4.5BSD will remedy this?) |
* fixing the interface. Maybe 4.5BSD will remedy this?) |
*/ |
*/ |
|
|
|
iphlen += sizeof(struct udphdr); |
/* |
/* |
* Construct sockaddr format source address. |
* KAME note: usually we drop udpiphdr from mbuf here. |
|
* we need udpiphdr for iPsec processing so we do that later. |
*/ |
*/ |
udpsrc.sin_family = AF_INET; |
|
udpsrc.sin_len = sizeof(struct sockaddr_in); |
|
udpsrc.sin_addr = ip->ip_src; |
|
udpsrc.sin_port = uh->uh_sport; |
|
bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero)); |
|
|
|
m->m_len -= sizeof (struct udpiphdr); |
|
m->m_data += sizeof (struct udpiphdr); |
|
/* |
/* |
* Locate pcb(s) for datagram. |
* Locate pcb(s) for datagram. |
* (Algorithm copied from raw_intr().) |
* (Algorithm copied from raw_intr().) |
Line 225 udp_input(m, va_alist) |
|
Line 273 udp_input(m, va_alist) |
|
if (last != NULL) { |
if (last != NULL) { |
struct mbuf *n; |
struct mbuf *n; |
|
|
|
#ifdef IPSEC |
|
/* check AH/ESP integrity. */ |
|
if (last != NULL && ipsec4_in_reject(m, last)) { |
|
ipsecstat.in_polvio++; |
|
/* do not inject data to pcb */ |
|
} else |
|
#endif /*IPSEC*/ |
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { |
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { |
if (sbappendaddr(&last->so_rcv, |
m_adj(m, iphlen); |
sintosa(&udpsrc), n, |
if (last->inp_flags & INP_CONTROLOPTS |
(struct mbuf *)0) == 0) { |
|| last->inp_socket->so_options & |
|
SO_TIMESTAMP) { |
|
ip_savecontrol(last, &opts, |
|
ip, n); |
|
} |
|
sa = (struct sockaddr *)&udpsrc; |
|
#ifdef MAPPED_ADDR_ENABLED |
|
if (last->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) { |
|
in6_sin_2_v4mapsin6(&udpsrc, |
|
&mapped); |
|
sa = (struct sockaddr *)&mapped; |
|
} |
|
#endif /* MAPPED_ADDR_ENABLED */ |
|
if (sbappendaddr( |
|
&last->inp_socket->so_rcv, |
|
sa, n, opts) == 0) { |
m_freem(n); |
m_freem(n); |
udpstat.udps_fullsock++; |
if (opts) |
|
m_freem(opts); |
} else |
} else |
sorwakeup(last); |
sorwakeup(last->inp_socket); |
|
opts = 0; |
} |
} |
} |
} |
last = inp->inp_socket; |
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 |
Line 244 udp_input(m, va_alist) |
|
Line 316 udp_input(m, va_alist) |
|
* port. It * assumes that an application will never |
* port. It * assumes that an application will never |
* clear these options after setting them. |
* clear these options after setting them. |
*/ |
*/ |
if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) |
if ((last->inp_socket->so_options & |
|
(SO_REUSEPORT|SO_REUSEADDR)) == 0) |
break; |
break; |
} |
} |
|
|
Line 254 udp_input(m, va_alist) |
|
Line 327 udp_input(m, va_alist) |
|
* (No need to send an ICMP Port Unreachable |
* (No need to send an ICMP Port Unreachable |
* for a broadcast or multicast datgram.) |
* for a broadcast or multicast datgram.) |
*/ |
*/ |
|
udpstat.udps_noport++; |
udpstat.udps_noportbcast++; |
udpstat.udps_noportbcast++; |
goto bad; |
goto bad; |
} |
} |
if (sbappendaddr(&last->so_rcv, sintosa(&udpsrc), m, |
#ifdef IPSEC |
(struct mbuf *)0) == 0) { |
/* check AH/ESP integrity. */ |
|
if (last != NULL && ipsec4_in_reject(m, last)) { |
|
ipsecstat.in_polvio++; |
|
goto bad; |
|
} |
|
#endif /*IPSEC*/ |
|
if (last->inp_flags & INP_CONTROLOPTS || |
|
last->inp_socket->so_options & SO_TIMESTAMP) |
|
ip_savecontrol(last, &opts, ip, m); |
|
sa = (struct sockaddr *)&udpsrc; |
|
#ifdef MAPPED_ADDR_ENABLED |
|
if (last->inp_socket->so_proto->pr_domain->dom_family == |
|
AF_INET6) { |
|
in6_sin_2_v4mapsin6(&udpsrc, &mapped); |
|
sa = (struct sockaddr *)&mapped; |
|
} |
|
#endif /* MAPPED_ADDR_ENABLED */ |
|
if (sbappendaddr(&last->inp_socket->so_rcv, sa, m, opts) == 0) { |
udpstat.udps_fullsock++; |
udpstat.udps_fullsock++; |
goto bad; |
goto bad; |
} |
} |
sorwakeup(last); |
sorwakeup(last->inp_socket); |
return; |
return; |
} |
} |
/* |
/* |
Line 280 udp_input(m, va_alist) |
|
Line 371 udp_input(m, va_alist) |
|
goto bad; |
goto bad; |
} |
} |
*ip = save_ip; |
*ip = save_ip; |
ip->ip_len += iphlen; |
#if NIPKDB > 0 |
#if NKGDB > 0 |
if (checkipkdb(&ip->ip_src, |
if (checkkgdb(&ip->ip_src, |
uh->uh_sport, |
uh->uh_sport, |
uh->uh_dport, |
uh->uh_dport, |
m, |
m, |
iphlen + sizeof(struct udphdr), |
iphlen + sizeof(struct udphdr), |
len - sizeof(struct udphdr))) |
len - sizeof(struct udphdr))) |
|
/* It was a debugger connect packet, just drop it now */ |
/* It was a debugger connect packet, just drop it now */ |
goto bad; |
goto bad; |
#endif |
#endif |
Line 295 udp_input(m, va_alist) |
|
Line 385 udp_input(m, va_alist) |
|
return; |
return; |
} |
} |
} |
} |
|
#ifdef IPSEC |
|
if (inp != NULL && ipsec4_in_reject(m, inp)) { |
|
ipsecstat.in_polvio++; |
|
goto bad; |
|
} |
|
#endif /*IPSEC*/ |
|
|
/* |
/* |
* Construct sockaddr format source address. |
|
* Stuff source address and datagram in user buffer. |
* Stuff source address and datagram in user buffer. |
*/ |
*/ |
udpsrc.sin_family = AF_INET; |
if (inp->inp_flags & INP_CONTROLOPTS || |
udpsrc.sin_len = sizeof(struct sockaddr_in); |
inp->inp_socket->so_options & SO_TIMESTAMP) |
udpsrc.sin_addr = ip->ip_src; |
ip_savecontrol(inp, &opts, ip, m); |
udpsrc.sin_port = uh->uh_sport; |
|
bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero)); |
|
|
|
if (inp->inp_flags & INP_CONTROLOPTS) { |
|
struct mbuf **mp = &opts; |
|
|
|
if (inp->inp_flags & INP_RECVDSTADDR) { |
|
*mp = udp_saveopt((caddr_t) &ip->ip_dst, |
|
sizeof(struct in_addr), IP_RECVDSTADDR); |
|
if (*mp) |
|
mp = &(*mp)->m_next; |
|
} |
|
#ifdef notyet |
|
/* options were tossed above */ |
|
if (inp->inp_flags & INP_RECVOPTS) { |
|
*mp = udp_saveopt((caddr_t) opts_deleted_above, |
|
sizeof(struct in_addr), IP_RECVOPTS); |
|
if (*mp) |
|
mp = &(*mp)->m_next; |
|
} |
|
/* ip_srcroute doesn't do what we want here, need to fix */ |
|
if (inp->inp_flags & INP_RECVRETOPTS) { |
|
*mp = udp_saveopt((caddr_t) ip_srcroute(), |
|
sizeof(struct in_addr), IP_RECVRETOPTS); |
|
if (*mp) |
|
mp = &(*mp)->m_next; |
|
} |
|
#endif |
|
} |
|
iphlen += sizeof(struct udphdr); |
iphlen += sizeof(struct udphdr); |
m->m_len -= iphlen; |
m->m_len -= iphlen; |
m->m_pkthdr.len -= iphlen; |
m->m_pkthdr.len -= iphlen; |
m->m_data += iphlen; |
m->m_data += iphlen; |
if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udpsrc), m, |
sa = (struct sockaddr *)&udpsrc; |
opts) == 0) { |
#ifdef MAPPED_ADDR_ENABLED |
|
if (inp->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) { |
|
in6_sin_2_v4mapsin6(&udpsrc, &mapped); |
|
sa = (struct sockaddr *)&mapped; |
|
} |
|
#endif /* MAPPED_ADDR_ENABLED */ |
|
if (sbappendaddr(&inp->inp_socket->so_rcv, sa, m, opts) == 0) { |
udpstat.udps_fullsock++; |
udpstat.udps_fullsock++; |
goto bad; |
goto bad; |
} |
} |
|
|
m_freem(m); |
m_freem(m); |
if (opts) |
if (opts) |
m_freem(opts); |
m_freem(opts); |
} |
return; |
|
|
/* |
|
* Create a "control" mbuf containing the specified data |
|
* with the specified type for presentation with a datagram. |
|
*/ |
|
struct mbuf * |
|
udp_saveopt(p, size, type) |
|
caddr_t p; |
|
register int size; |
|
int type; |
|
{ |
|
register struct cmsghdr *cp; |
|
struct mbuf *m; |
|
|
|
if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) |
|
return ((struct mbuf *) NULL); |
|
cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); |
|
bcopy(p, CMSG_DATA(cp), size); |
|
size += sizeof(*cp); |
|
m->m_len = size; |
|
cp->cmsg_len = size; |
|
cp->cmsg_level = IPPROTO_IP; |
|
cp->cmsg_type = type; |
|
return (m); |
|
} |
} |
|
|
/* |
/* |
Line 450 udp_output(m, va_alist) |
|
Line 498 udp_output(m, va_alist) |
|
} |
} |
|
|
/* |
/* |
|
* Compute the packet length of the IP header, and |
|
* punt if the length looks bogus. |
|
*/ |
|
if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) { |
|
error = EMSGSIZE; |
|
goto release; |
|
} |
|
|
|
/* |
* Fill in mbuf with extended UDP header |
* Fill in mbuf with extended UDP header |
* and addresses and length put into network format. |
* and addresses and length put into network format. |
*/ |
*/ |
Line 475 udp_output(m, va_alist) |
|
Line 532 udp_output(m, va_alist) |
|
((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ |
((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ |
((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ |
((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ |
udpstat.udps_opackets++; |
udpstat.udps_opackets++; |
|
|
|
#ifdef IPSEC |
|
m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket; |
|
#endif /*IPSEC*/ |
|
|
return (ip_output(m, inp->inp_options, &inp->inp_route, |
return (ip_output(m, inp->inp_options, &inp->inp_route, |
inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), |
inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), |
inp->inp_moptions)); |
inp->inp_moptions)); |
|
|
return (error); |
return (error); |
} |
} |
|
|
u_long udp_sendspace = 9216; /* really max datagram size */ |
int udp_sendspace = 9216; /* really max datagram size */ |
u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); |
int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); |
/* 40 1K datagrams */ |
/* 40 1K datagrams */ |
|
|
/*ARGSUSED*/ |
/*ARGSUSED*/ |
Line 536 udp_usrreq(so, req, m, nam, control, p) |
|
Line 598 udp_usrreq(so, req, m, nam, control, p) |
|
break; |
break; |
inp = sotoinpcb(so); |
inp = sotoinpcb(so); |
inp->inp_ip.ip_ttl = ip_defttl; |
inp->inp_ip.ip_ttl = ip_defttl; |
|
#ifdef IPSEC |
|
inp = (struct inpcb *)so->so_pcb; |
|
error = ipsec_init_policy(&inp->inp_sp); |
|
#endif /*IPSEC*/ |
break; |
break; |
|
|
case PRU_DETACH: |
case PRU_DETACH: |
Line 667 udp_sysctl(name, namelen, oldp, oldlenp, |
|
Line 733 udp_sysctl(name, namelen, oldp, oldlenp, |
|
switch (name[0]) { |
switch (name[0]) { |
case UDPCTL_CHECKSUM: |
case UDPCTL_CHECKSUM: |
return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); |
return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); |
|
case UDPCTL_SENDSPACE: |
|
return (sysctl_int(oldp, oldlenp, newp, newlen, |
|
&udp_sendspace)); |
|
case UDPCTL_RECVSPACE: |
|
return (sysctl_int(oldp, oldlenp, newp, newlen, |
|
&udp_recvspace)); |
default: |
default: |
return (ENOPROTOOPT); |
return (ENOPROTOOPT); |
} |
} |