version 1.93.4.1, 2004/03/31 20:09:25 |
version 1.103, 2003/06/29 22:32:01 |
|
|
/* |
/* |
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
* All rights reserved. |
* 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 |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
* are met: |
* are met: |
|
|
* 3. Neither the name of the project nor the names of its contributors |
* 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 |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* without specific prior written permission. |
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
Line 71 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 71 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include "opt_ipsec.h" |
#include "opt_ipsec.h" |
#include "opt_inet_csum.h" |
#include "opt_inet_csum.h" |
#include "opt_ipkdb.h" |
#include "opt_ipkdb.h" |
|
#include "opt_mbuftrace.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
Line 106 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 107 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <netinet6/udp6_var.h> |
#include <netinet6/udp6_var.h> |
#endif |
#endif |
|
|
#ifdef PULLDOWN_TEST |
|
#ifndef INET6 |
#ifndef INET6 |
/* always need ip6.h for IP6_EXTHDR_GET */ |
/* always need ip6.h for IP6_EXTHDR_GET */ |
#include <netinet/ip6.h> |
#include <netinet/ip6.h> |
#endif |
#endif |
#endif |
|
|
|
#include "faith.h" |
#include "faith.h" |
#if defined(NFAITH) && NFAITH > 0 |
#if defined(NFAITH) && NFAITH > 0 |
Line 163 static void udp_notify __P((struct inpcb |
|
Line 162 static void udp_notify __P((struct inpcb |
|
#endif |
#endif |
int udbhashsize = UDBHASHSIZE; |
int udbhashsize = UDBHASHSIZE; |
|
|
|
#ifdef MBUFTRACE |
|
struct mowner udp_mowner = { "udp" }; |
|
struct mowner udp_rx_mowner = { "udp", "rx" }; |
|
struct mowner udp_tx_mowner = { "udp", "tx" }; |
|
#endif |
|
|
#ifdef UDP_CSUM_COUNTERS |
#ifdef UDP_CSUM_COUNTERS |
#include <sys/device.h> |
#include <sys/device.h> |
|
|
|
|
evcnt_attach_static(&udp_hwcsum_data); |
evcnt_attach_static(&udp_hwcsum_data); |
evcnt_attach_static(&udp_swcsum); |
evcnt_attach_static(&udp_swcsum); |
#endif /* UDP_CSUM_COUNTERS */ |
#endif /* UDP_CSUM_COUNTERS */ |
|
|
|
MOWNER_ATTACH(&udp_tx_mowner); |
|
MOWNER_ATTACH(&udp_rx_mowner); |
|
MOWNER_ATTACH(&udp_mowner); |
} |
} |
|
|
#ifdef INET |
#ifdef INET |
Line 213 udp_input(m, va_alist) |
|
Line 222 udp_input(m, va_alist) |
|
struct sockaddr_in src, dst; |
struct sockaddr_in src, dst; |
struct ip *ip; |
struct ip *ip; |
struct udphdr *uh; |
struct udphdr *uh; |
int iphlen, proto; |
int iphlen; |
int len; |
int len; |
int n; |
int n; |
|
u_int16_t ip_len; |
|
|
va_start(ap, m); |
va_start(ap, m); |
iphlen = va_arg(ap, int); |
iphlen = va_arg(ap, int); |
proto = va_arg(ap, int); |
(void)va_arg(ap, int); /* ignore value, advance ap */ |
va_end(ap); |
va_end(ap); |
|
|
|
MCLAIM(m, &udp_rx_mowner); |
udpstat.udps_ipackets++; |
udpstat.udps_ipackets++; |
|
|
#ifndef PULLDOWN_TEST |
|
/* |
|
* 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. |
|
*/ |
|
if (iphlen > sizeof (struct ip)) { |
|
ip_stripoptions(m, (struct mbuf *)0); |
|
iphlen = sizeof(struct ip); |
|
} |
|
#else |
|
/* |
|
* we may enable the above code if we save and pass IPv4 options |
|
* to the userland. |
|
*/ |
|
#endif |
|
|
|
/* |
/* |
* Get IP and UDP header together in first mbuf. |
* Get IP and UDP header together in first mbuf. |
*/ |
*/ |
ip = mtod(m, struct ip *); |
ip = mtod(m, struct ip *); |
#ifndef PULLDOWN_TEST |
|
if (m->m_len < iphlen + sizeof(struct udphdr)) { |
|
if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { |
|
udpstat.udps_hdrops++; |
|
return; |
|
} |
|
ip = mtod(m, struct ip *); |
|
} |
|
uh = (struct udphdr *)((caddr_t)ip + iphlen); |
|
#else |
|
IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); |
IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); |
if (uh == NULL) { |
if (uh == NULL) { |
udpstat.udps_hdrops++; |
udpstat.udps_hdrops++; |
return; |
return; |
} |
} |
#endif |
KASSERT(UDP_HDR_ALIGNED_P(uh)); |
|
|
/* destination port of 0 is illegal, based on RFC768. */ |
/* destination port of 0 is illegal, based on RFC768. */ |
if (uh->uh_dport == 0) |
if (uh->uh_dport == 0) |
Line 271 udp_input(m, va_alist) |
|
Line 254 udp_input(m, va_alist) |
|
* Make mbuf data length reflect UDP length. |
* Make mbuf data length reflect UDP length. |
* If not enough data to reflect UDP length, drop. |
* If not enough data to reflect UDP length, drop. |
*/ |
*/ |
|
ip_len = ntohs(ip->ip_len); |
len = ntohs((u_int16_t)uh->uh_ulen); |
len = ntohs((u_int16_t)uh->uh_ulen); |
if (ip->ip_len != iphlen + len) { |
if (ip_len != iphlen + len) { |
if (ip->ip_len < iphlen + len || len < sizeof(struct udphdr)) { |
if (ip_len < iphlen + len || len < sizeof(struct udphdr)) { |
udpstat.udps_badlen++; |
udpstat.udps_badlen++; |
goto bad; |
goto bad; |
} |
} |
m_adj(m, iphlen + len - ip->ip_len); |
m_adj(m, iphlen + len - ip_len); |
} |
} |
|
|
/* |
/* |
Line 392 udp6_input(mp, offp, proto) |
|
Line 376 udp6_input(mp, offp, proto) |
|
struct udphdr *uh; |
struct udphdr *uh; |
u_int32_t plen, ulen; |
u_int32_t plen, ulen; |
|
|
#ifndef PULLDOWN_TEST |
|
IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); |
|
#endif |
|
ip6 = mtod(m, struct ip6_hdr *); |
ip6 = mtod(m, struct ip6_hdr *); |
|
|
#if defined(NFAITH) && 0 < NFAITH |
#if defined(NFAITH) && 0 < NFAITH |
Line 409 udp6_input(mp, offp, proto) |
|
Line 390 udp6_input(mp, offp, proto) |
|
|
|
/* check for jumbogram is done in ip6_input. we can trust pkthdr.len */ |
/* check for jumbogram is done in ip6_input. we can trust pkthdr.len */ |
plen = m->m_pkthdr.len - off; |
plen = m->m_pkthdr.len - off; |
#ifndef PULLDOWN_TEST |
|
uh = (struct udphdr *)((caddr_t)ip6 + off); |
|
#else |
|
IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr)); |
IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr)); |
if (uh == NULL) { |
if (uh == NULL) { |
ip6stat.ip6s_tooshort++; |
ip6stat.ip6s_tooshort++; |
return IPPROTO_DONE; |
return IPPROTO_DONE; |
} |
} |
#endif |
KASSERT(UDP_HDR_ALIGNED_P(uh)); |
ulen = ntohs((u_short)uh->uh_ulen); |
ulen = ntohs((u_short)uh->uh_ulen); |
/* |
/* |
* RFC2675 section 4: jumbograms will have 0 in the UDP header field, |
* RFC2675 section 4: jumbograms will have 0 in the UDP header field, |
Line 445 udp6_input(mp, offp, proto) |
|
Line 423 udp6_input(mp, offp, proto) |
|
/* |
/* |
* Checksum extended UDP header and data. |
* Checksum extended UDP header and data. |
*/ |
*/ |
if (uh->uh_sum == 0) { |
if (uh->uh_sum == 0) |
udp6stat.udp6s_nosum++; |
udp6stat.udp6s_nosum++; |
goto bad; |
else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { |
} else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { |
|
udp6stat.udp6s_badsum++; |
udp6stat.udp6s_badsum++; |
goto bad; |
goto bad; |
} |
} |
Line 498 udp4_sendup(m, off, src, so) |
|
Line 475 udp4_sendup(m, off, src, so) |
|
struct mbuf *opts = NULL; |
struct mbuf *opts = NULL; |
struct mbuf *n; |
struct mbuf *n; |
struct inpcb *inp = NULL; |
struct inpcb *inp = NULL; |
#ifdef INET6 |
|
struct in6pcb *in6p = NULL; |
|
#endif |
|
|
|
if (!so) |
if (!so) |
return; |
return; |
Line 510 udp4_sendup(m, off, src, so) |
|
Line 484 udp4_sendup(m, off, src, so) |
|
break; |
break; |
#ifdef INET6 |
#ifdef INET6 |
case AF_INET6: |
case AF_INET6: |
in6p = sotoin6pcb(so); |
|
break; |
break; |
#endif |
#endif |
default: |
default: |
Line 616 udp4_realinput(src, dst, m, off) |
|
Line 589 udp4_realinput(src, dst, m, off) |
|
|
|
if (IN_MULTICAST(dst4->s_addr) || |
if (IN_MULTICAST(dst4->s_addr) || |
in_broadcast(*dst4, m->m_pkthdr.rcvif)) { |
in_broadcast(*dst4, m->m_pkthdr.rcvif)) { |
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 653 udp4_realinput(src, dst, m, off) |
|
Line 625 udp4_realinput(src, dst, m, off) |
|
continue; |
continue; |
} |
} |
|
|
last = inp; |
|
udp4_sendup(m, off, (struct sockaddr *)src, |
udp4_sendup(m, off, (struct sockaddr *)src, |
inp->inp_socket); |
inp->inp_socket); |
rcvcnt++; |
rcvcnt++; |
Line 722 udp6_realinput(af, src, dst, m, off) |
|
Line 693 udp6_realinput(af, src, dst, m, off) |
|
|
|
if (IN6_IS_ADDR_MULTICAST(&dst6) || |
if (IN6_IS_ADDR_MULTICAST(&dst6) || |
(af == AF_INET && IN_MULTICAST(dst4->s_addr))) { |
(af == AF_INET && IN_MULTICAST(dst4->s_addr))) { |
struct in6pcb *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 768 udp6_realinput(af, src, dst, m, off) |
|
Line 738 udp6_realinput(af, src, dst, m, off) |
|
continue; |
continue; |
} |
} |
|
|
last = in6p; |
|
udp6_sendup(m, off, (struct sockaddr *)src, |
udp6_sendup(m, off, (struct sockaddr *)src, |
in6p->in6p_socket); |
in6p->in6p_socket); |
rcvcnt++; |
rcvcnt++; |
Line 873 udp_output(m, va_alist) |
|
Line 842 udp_output(m, va_alist) |
|
int error = 0; |
int error = 0; |
va_list ap; |
va_list ap; |
|
|
|
MCLAIM(m, &udp_tx_mowner); |
va_start(ap, m); |
va_start(ap, m); |
inp = va_arg(ap, struct inpcb *); |
inp = va_arg(ap, struct inpcb *); |
va_end(ap); |
va_end(ap); |
Line 891 udp_output(m, va_alist) |
|
Line 861 udp_output(m, va_alist) |
|
* Compute the packet length of the IP header, and |
* Compute the packet length of the IP header, and |
* punt if the length looks bogus. |
* punt if the length looks bogus. |
*/ |
*/ |
if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) { |
if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { |
error = EMSGSIZE; |
error = EMSGSIZE; |
goto release; |
goto release; |
} |
} |
Line 923 udp_output(m, va_alist) |
|
Line 893 udp_output(m, va_alist) |
|
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); |
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); |
} else |
} else |
ui->ui_sum = 0; |
ui->ui_sum = 0; |
((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; |
((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len); |
((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++; |
Line 993 udp_usrreq(so, req, m, nam, control, p) |
|
Line 963 udp_usrreq(so, req, m, nam, control, p) |
|
error = EISCONN; |
error = EISCONN; |
break; |
break; |
} |
} |
|
#ifdef MBUFTRACE |
|
so->so_mowner = &udp_mowner; |
|
so->so_rcv.sb_mowner = &udp_rx_mowner; |
|
so->so_snd.sb_mowner = &udp_tx_mowner; |
|
#endif |
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { |
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { |
error = soreserve(so, udp_sendspace, udp_recvspace); |
error = soreserve(so, udp_sendspace, udp_recvspace); |
if (error) |
if (error) |
Line 1033 udp_usrreq(so, req, m, nam, control, p) |
|
Line 1008 udp_usrreq(so, req, m, nam, control, p) |
|
so->so_state &= ~SS_ISCONNECTED; /* XXX */ |
so->so_state &= ~SS_ISCONNECTED; /* XXX */ |
in_pcbdisconnect(inp); |
in_pcbdisconnect(inp); |
inp->inp_laddr = zeroin_addr; /* XXX */ |
inp->inp_laddr = zeroin_addr; /* XXX */ |
|
if (inp->inp_ia != NULL) { |
|
LIST_REMOVE(inp, inp_ialink); |
|
IFAFREE(&inp->inp_ia->ia_ifa); |
|
inp->inp_ia = NULL; |
|
} |
in_pcbstate(inp, INP_BOUND); /* XXX */ |
in_pcbstate(inp, INP_BOUND); /* XXX */ |
break; |
break; |
|
|
Line 1061 udp_usrreq(so, req, m, nam, control, p) |
|
Line 1041 udp_usrreq(so, req, m, nam, control, p) |
|
goto die; |
goto die; |
} |
} |
error = in_pcbconnect(inp, nam); |
error = in_pcbconnect(inp, nam); |
if (error) { |
if (error) |
die: |
goto die; |
m_freem(m); |
|
break; |
|
} |
|
} else { |
} else { |
if ((so->so_state & SS_ISCONNECTED) == 0) { |
if ((so->so_state & SS_ISCONNECTED) == 0) { |
error = ENOTCONN; |
error = ENOTCONN; |
Line 1073 udp_usrreq(so, req, m, nam, control, p) |
|
Line 1050 udp_usrreq(so, req, m, nam, control, p) |
|
} |
} |
} |
} |
error = udp_output(m, inp); |
error = udp_output(m, inp); |
|
m = NULL; |
if (nam) { |
if (nam) { |
in_pcbdisconnect(inp); |
in_pcbdisconnect(inp); |
inp->inp_laddr = laddr; /* XXX */ |
inp->inp_laddr = laddr; /* XXX */ |
in_pcbstate(inp, INP_BOUND); /* XXX */ |
in_pcbstate(inp, INP_BOUND); /* XXX */ |
} |
} |
|
die: |
|
if (inp->inp_ia != NULL && in_nullhost(inp->inp_laddr)) { |
|
LIST_REMOVE(inp, inp_ialink); |
|
IFAFREE(&inp->inp_ia->ia_ifa); |
|
inp->inp_ia = NULL; |
|
} |
|
if (m) |
|
m_freem(m); |
} |
} |
break; |
break; |
|
|
Line 1138 udp_sysctl(name, namelen, oldp, oldlenp, |
|
Line 1124 udp_sysctl(name, namelen, oldp, oldlenp, |
|
return (sysctl_int(oldp, oldlenp, newp, newlen, |
return (sysctl_int(oldp, oldlenp, newp, newlen, |
&udp_sendspace)); |
&udp_sendspace)); |
case UDPCTL_RECVSPACE: |
case UDPCTL_RECVSPACE: |
return (sysctl_int(oldp, oldlenp, newp, newlen, |
return (sysctl_int(oldp, oldlenp, newp, newlen, |
&udp_recvspace)); |
&udp_recvspace)); |
default: |
default: |
return (ENOPROTOOPT); |
return (ENOPROTOOPT); |