syscons util remove use kbdcontrol & vidcontrol instead
[unix-history] / sys / netinet / udp_usrreq.c
index cb875f0..1447952 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993
+ *     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
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * SUCH DAMAGE.
  *
  *     from: @(#)udp_usrreq.c  7.20 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)udp_usrreq.c  7.20 (Berkeley) 4/20/91
- *     $Id$
+ *     $Id: udp_usrreq.c,v 1.7 1994/02/07 19:53:25 ache Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
+#include "systm.h"
 #include "malloc.h"
 #include "mbuf.h"
 #include "protosw.h"
 #include "malloc.h"
 #include "mbuf.h"
 #include "protosw.h"
@@ -47,6 +48,7 @@
 
 #include "in.h"
 #include "in_systm.h"
 
 #include "in.h"
 #include "in_systm.h"
+#include "in_var.h"
 #include "ip.h"
 #include "in_pcb.h"
 #include "ip_var.h"
 #include "ip.h"
 #include "in_pcb.h"
 #include "ip_var.h"
 #include "udp.h"
 #include "udp_var.h"
 
 #include "udp.h"
 #include "udp_var.h"
 
-struct inpcb *udp_last_inpcb = &udb;
+struct   inpcb udb;     /* Can't be static, because of netstat want it */
+static struct  inpcb *udp_last_inpcb = &udb;
+
+static void udp_detach(struct inpcb *);
 
 /*
  * UDP protocol implementation.
  * Per RFC 768, August, 1980.
  */
 
 /*
  * UDP protocol implementation.
  * Per RFC 768, August, 1980.
  */
+void
 udp_init()
 {
 
        udb.inp_next = udb.inp_prev = &udb;
 }
 
 udp_init()
 {
 
        udb.inp_next = udb.inp_prev = &udb;
 }
 
-#ifndef        COMPAT_42
-int    udpcksum = 1;
-#else
-int    udpcksum = 0;           /* XXX */
-#endif
-int    udp_ttl = UDP_TTL;
-
-struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
+static struct  sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
 
 
+void
 udp_input(m, iphlen)
        register struct mbuf *m;
        int iphlen;
 udp_input(m, iphlen)
        register struct mbuf *m;
        int iphlen;
@@ -145,6 +145,93 @@ udp_input(m, iphlen)
                        return;
                }
        }
                        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.
 
        /*
         * Locate pcb for datagram.
@@ -163,13 +250,19 @@ udp_input(m, iphlen)
        if (inp == 0) {
                /* don't send ICMP response for broadcast packet */
                udpstat.udps_noport++;
        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;
                }
                        udpstat.udps_noportbcast++;
                        goto bad;
                }
+#endif
                *ip = save_ip;
                ip->ip_len += iphlen;
                *ip = save_ip;
                ip->ip_len += iphlen;
-               icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
+               {
+                 static struct in_addr fake;
+                 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, fake, 0);
+               }
                return;
        }
 
                return;
        }
 
@@ -252,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.
  */
  * Notify a udp user of an asynchronous error;
  * just wake up so that he can collect error status.
  */
+void
 udp_notify(inp, errno)
        register struct inpcb *inp;
 udp_notify(inp, errno)
        register struct inpcb *inp;
+       int errno;
 {
 
        inp->inp_socket->so_error = errno;
 {
 
        inp->inp_socket->so_error = errno;
@@ -261,6 +356,7 @@ udp_notify(inp, errno)
        sowwakeup(inp->inp_socket);
 }
 
        sowwakeup(inp->inp_socket);
 }
 
+void
 udp_ctlinput(cmd, sa, ip)
        int cmd;
        struct sockaddr *sa;
 udp_ctlinput(cmd, sa, ip)
        int cmd;
        struct sockaddr *sa;
@@ -280,6 +376,7 @@ udp_ctlinput(cmd, sa, ip)
                in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
 }
 
                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;
 udp_output(inp, m, addr, control)
        register struct inpcb *inp;
        register struct mbuf *m;
@@ -288,7 +385,7 @@ udp_output(inp, m, addr, control)
        register struct udpiphdr *ui;
        register int len = m->m_pkthdr.len;
        struct in_addr laddr;
        register struct udpiphdr *ui;
        register int len = m->m_pkthdr.len;
        struct in_addr laddr;
-       int s, error = 0;
+       int s = 0, error = 0;
 
        if (control)
                m_freem(control);               /* XXX */
 
        if (control)
                m_freem(control);               /* XXX */
@@ -348,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,
        ((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);
 
        if (addr) {
                in_pcbdisconnect(inp);
@@ -362,11 +463,8 @@ release:
        return (error);
 }
 
        return (error);
 }
 
-u_long udp_sendspace = 9216;           /* really max datagram size */
-u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
-                                       /* 40 1K datagrams */
-
 /*ARGSUSED*/
 /*ARGSUSED*/
+int
 udp_usrreq(so, req, m, addr, control)
        struct socket *so;
        int req;
 udp_usrreq(so, req, m, addr, control)
        struct socket *so;
        int req;
@@ -503,6 +601,7 @@ release:
        return (error);
 }
 
        return (error);
 }
 
+static void
 udp_detach(inp)
        struct inpcb *inp;
 {
 udp_detach(inp)
        struct inpcb *inp;
 {