Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet/udp_usrreq.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/udp_usrreq.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.1 retrieving revision 1.8 diff -u -p -r1.1 -r1.8 --- src/sys/netinet/udp_usrreq.c 1993/03/21 09:45:37 1.1 +++ src/sys/netinet/udp_usrreq.c 1994/01/08 23:19:48 1.8 @@ -30,41 +30,34 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)udp_usrreq.c 7.20 (Berkeley) 4/20/91 + * from: @(#)udp_usrreq.c 7.20 (Berkeley) 4/20/91 + * $Id: udp_usrreq.c,v 1.8 1994/01/08 23:19:48 mycroft Exp $ */ -#include "param.h" -#include "malloc.h" -#include "mbuf.h" -#include "protosw.h" -#include "socket.h" -#include "socketvar.h" -#include "stat.h" - -#include "../net/if.h" -#include "../net/route.h" - -#include "in.h" -#include "in_systm.h" -#include "ip.h" -#include "in_pcb.h" -#include "ip_var.h" -#include "ip_icmp.h" -#include "udp.h" -#include "udp_var.h" - -struct inpcb *udp_last_inpcb = &udb; +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* * UDP protocol implementation. * Per RFC 768, August, 1980. */ -udp_init() -{ - - udb.inp_next = udb.inp_prev = &udb; -} - #ifndef COMPAT_42 int udpcksum = 1; #else @@ -73,7 +66,21 @@ int udpcksum = 0; /* XXX */ int udp_ttl = UDP_TTL; struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; +struct inpcb *udp_last_inpcb = &udb; + +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)); + +void +udp_init() +{ + + udb.inp_next = udb.inp_prev = &udb; +} +void udp_input(m, iphlen) register struct mbuf *m; int iphlen; @@ -144,7 +151,92 @@ udp_input(m, iphlen) return; } } - +#ifdef MULTICAST + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || + in_broadcast(ip->ip_dst)) { + 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.4BSD will remedy this?) + */ + /* + * Construct sockaddr format source address. + */ + udp_in.sin_port = uh->uh_sport; + udp_in.sin_addr = ip->ip_src; + m->m_len -= sizeof (struct udpiphdr); + m->m_data += sizeof (struct udpiphdr); + /* + * Locate pcb(s) for datagram. + * (Algorithm copied from raw_intr().) + */ + last = NULL; + for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) { + if (inp->inp_lport != uh->uh_dport) + continue; + if (inp->inp_laddr.s_addr != INADDR_ANY) { + if (inp->inp_laddr.s_addr != + ip->ip_dst.s_addr) + continue; + } + if (inp->inp_faddr.s_addr != INADDR_ANY) { + if (inp->inp_faddr.s_addr != + ip->ip_src.s_addr || + inp->inp_fport != uh->uh_sport) + continue; + } + + if (last != NULL) { + struct mbuf *n; + + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + if (sbappendaddr(&last->so_rcv, + (struct sockaddr *)&udp_in, + n, (struct mbuf *)0) == 0) + m_freem(n); + else + sorwakeup(last); + } + } + last = inp->inp_socket; + /* + * Don't look for additional matches if this one + * does not have the SO_REUSEADDR socket option 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 + * the SO_REUSEADDR option after setting it. + */ + if ((last->so_options & SO_REUSEADDR) == 0) + break; + } + + if (last == NULL) { + /* + * No matching pcb found; discard datagram. + * (No need to send an ICMP Port Unreachable + * for a broadcast or multicast datgram.) + */ + goto bad; + } + if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, + m, (struct mbuf *)0) == 0) + goto bad; + sorwakeup(last); + return; + } +#endif /* * Locate pcb for datagram. */ @@ -162,10 +254,13 @@ udp_input(m, iphlen) if (inp == 0) { /* don't send ICMP response for broadcast packet */ udpstat.udps_noport++; - if (m->m_flags & M_BCAST) { +#ifndef MULTICAST + /* XXX why don't we do this with MULTICAST? */ + if (m->m_flags & (M_BCAST | M_MCAST)) { udpstat.udps_noportbcast++; goto bad; } +#endif *ip = save_ip; ip->ip_len += iphlen; icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT); @@ -180,7 +275,6 @@ udp_input(m, iphlen) udp_in.sin_addr = ip->ip_src; if (inp->inp_flags & INP_CONTROLOPTS) { struct mbuf **mp = &opts; - struct mbuf *udp_saveopt(); if (inp->inp_flags & INP_RECVDSTADDR) { *mp = udp_saveopt((caddr_t) &ip->ip_dst, @@ -226,7 +320,7 @@ bad: * Create a "control" mbuf containing the specified data * with the specified type for presentation with a datagram. */ -struct mbuf * +static struct mbuf * udp_saveopt(p, size, type) caddr_t p; register int size; @@ -251,8 +345,10 @@ udp_saveopt(p, size, type) * Notify a udp user of an asynchronous error; * just wake up so that he can collect error status. */ +static void udp_notify(inp, errno) register struct inpcb *inp; + int errno; { inp->inp_socket->so_error = errno; @@ -260,6 +356,7 @@ udp_notify(inp, errno) sowwakeup(inp->inp_socket); } +void udp_ctlinput(cmd, sa, ip) int cmd; struct sockaddr *sa; @@ -279,6 +376,7 @@ udp_ctlinput(cmd, sa, ip) in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); } +int udp_output(inp, m, addr, control) register struct inpcb *inp; register struct mbuf *m; @@ -347,7 +445,11 @@ udp_output(inp, m, addr, control) ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ udpstat.udps_opackets++; error = 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) +#ifdef MULTICAST + | IP_MULTICASTOPTS, inp->inp_moptions +#endif + ); if (addr) { in_pcbdisconnect(inp); @@ -366,6 +468,7 @@ u_long udp_recvspace = 40 * (1024 + size /* 40 1K datagrams */ /*ARGSUSED*/ +int udp_usrreq(so, req, m, addr, control) struct socket *so; int req; @@ -502,6 +605,7 @@ release: return (error); } +static void udp_detach(inp) struct inpcb *inp; {