ip_freef now void
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
index 922e4cb..0712363 100644 (file)
@@ -1,4 +1,4 @@
-/*     udp_usrreq.c    4.14    81/12/03        */
+/*     udp_usrreq.c    4.43    83/01/13        */
 
 #include "../h/param.h"
 #include "../h/dir.h"
 
 #include "../h/param.h"
 #include "../h/dir.h"
@@ -7,13 +7,17 @@
 #include "../h/protosw.h"
 #include "../h/socket.h"
 #include "../h/socketvar.h"
 #include "../h/protosw.h"
 #include "../h/socket.h"
 #include "../h/socketvar.h"
-#include "../net/in.h"
-#include "../net/in_pcb.h"
-#include "../net/in_systm.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
-#include "../net/udp.h"
-#include "../net/udp_var.h"
+#include "../netinet/in.h"
+#include "../net/if.h"
+#include "../net/route.h"
+#include "../netinet/in_pcb.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netinet/ip_icmp.h"
+#include "../netinet/udp.h"
+#include "../netinet/udp_var.h"
+#include <errno.h>
 
 /*
  * UDP protocol implementation.
 
 /*
  * UDP protocol implementation.
@@ -22,7 +26,6 @@
 udp_init()
 {
 
 udp_init()
 {
 
-COUNT(UDP_INIT);
        udb.inp_next = udb.inp_prev = &udb;
 }
 
        udb.inp_next = udb.inp_prev = &udb;
 }
 
@@ -35,28 +38,26 @@ udp_input(m0)
        register struct udpiphdr *ui;
        register struct inpcb *inp;
        register struct mbuf *m;
        register struct udpiphdr *ui;
        register struct inpcb *inp;
        register struct mbuf *m;
-       int len, ulen;
+       int len;
 
 
-COUNT(UDP_INPUT);
        /*
        /*
-        * Get ip and udp header together in first mbuf.
+        * Get IP and UDP header together in first mbuf.
         */
        m = m0;
         */
        m = m0;
-       if (m->m_len < sizeof (struct udpiphdr) &&
-           m_pullup(m, sizeof (struct udpiphdr)) == 0) {
+       if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
+           (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
                udpstat.udps_hdrops++;
                udpstat.udps_hdrops++;
-               goto bad;
+               return;
        }
        ui = mtod(m, struct udpiphdr *);
        }
        ui = mtod(m, struct udpiphdr *);
-       if (ui->ui_len > sizeof (struct ip))
-               ip_stripoptions((struct ip *)ui, (char *)0);
+       if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
+               ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
 
        /*
 
        /*
-        * Make mbuf data length reflect udp length.
-        * If not enough data to reflect udp length, drop.
+        * Make mbuf data length reflect UDP length.
+        * If not enough data to reflect UDP length, drop.
         */
         */
-       ulen = ntohs((u_short)ui->ui_ulen);
-       len = sizeof (struct udpiphdr) + ulen;
+       len = ntohs((u_short)ui->ui_ulen);
        if (((struct ip *)ui)->ip_len != len) {
                if (len > ((struct ip *)ui)->ip_len) {
                        udpstat.udps_badlen++;
        if (((struct ip *)ui)->ip_len != len) {
                if (len > ((struct ip *)ui)->ip_len) {
                        udpstat.udps_badlen++;
@@ -67,13 +68,13 @@ COUNT(UDP_INPUT);
        }
 
        /*
        }
 
        /*
-        * Checksum extended udp header and data.
+        * Checksum extended UDP header and data.
         */
        if (udpcksum) {
                ui->ui_next = ui->ui_prev = 0;
                ui->ui_x1 = 0;
         */
        if (udpcksum) {
                ui->ui_next = ui->ui_prev = 0;
                ui->ui_x1 = 0;
-               ui->ui_len = htons((u_short)(sizeof (struct udpiphdr) + ulen));
-               if ((ui->ui_sum = in_cksum(m, len)) != 0xffff) {
+               ui->ui_len = htons((u_short)len);
+               if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
                        udpstat.udps_badsum++;
                        printf("udp cksum %x\n", ui->ui_sum);
                        m_freem(m);
                        udpstat.udps_badsum++;
                        printf("udp cksum %x\n", ui->ui_sum);
                        m_freem(m);
@@ -82,13 +83,18 @@ COUNT(UDP_INPUT);
        }
 
        /*
        }
 
        /*
-        * Convert addresses and ports to host format.
         * Locate pcb for datagram.
         */
        inp = in_pcblookup(&udb,
         * Locate pcb for datagram.
         */
        inp = in_pcblookup(&udb,
-           ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
-       if (inp == 0)
-               goto bad;
+           ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
+               INPLOOKUP_WILDCARD);
+       if (inp == 0) {
+               /* don't send ICMP response for broadcast packet */
+               if (in_lnaof(ui->ui_dst) == INADDR_ANY)
+                       goto bad;
+               icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT);
+               return;
+       }
 
        /*
         * Construct sockaddr format source address.
 
        /*
         * Construct sockaddr format source address.
@@ -106,37 +112,67 @@ bad:
        m_freem(m);
 }
 
        m_freem(m);
 }
 
-udp_ctlinput(m)
-       struct mbuf *m;
+udp_abort(inp)
+       struct inpcb *inp;
 {
 {
+       struct socket *so = inp->inp_socket;
 
 
-COUNT(UDP_CTLINPUT);
-       printf("udp_ctlinput\n");
-       m_freem(m);
+       in_pcbdisconnect(inp);
+       soisdisconnected(so);
+}
+
+udp_ctlinput(cmd, arg)
+       int cmd;
+       caddr_t arg;
+{
+       struct in_addr *sin;
+       extern u_char inetctlerrmap[];
+
+       if (cmd < 0 || cmd > PRC_NCMDS)
+               return;
+       switch (cmd) {
+
+       case PRC_ROUTEDEAD:
+               break;
+
+       case PRC_QUENCH:
+               break;
+
+       /* these are handled by ip */
+       case PRC_IFDOWN:
+       case PRC_HOSTDEAD:
+       case PRC_HOSTUNREACH:
+               break;
+
+       default:
+               sin = &((struct icmp *)arg)->icmp_ip.ip_dst;
+               in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort);
+       }
 }
 
 }
 
-/*ARGSUSED*/
 udp_output(inp, m0)
        struct inpcb *inp;
        struct mbuf *m0;
 {
        register struct mbuf *m;
        register struct udpiphdr *ui;
 udp_output(inp, m0)
        struct inpcb *inp;
        struct mbuf *m0;
 {
        register struct mbuf *m;
        register struct udpiphdr *ui;
+       register struct socket *so;
        register int len = 0;
 
        register int len = 0;
 
-COUNT(UDP_OUTPUT);
        /*
         * Calculate data length and get a mbuf
        /*
         * Calculate data length and get a mbuf
-        * for udp and ip headers.
+        * for UDP and IP headers.
         */
        for (m = m0; m; m = m->m_next)
                len += m->m_len;
         */
        for (m = m0; m; m = m->m_next)
                len += m->m_len;
-       m = m_get(0);
-       if (m == 0)
-               goto bad;
+       m = m_get(M_DONTWAIT, MT_HEADER);
+       if (m == 0) {
+               m_freem(m0);
+               return (ENOBUFS);
+       }
 
        /*
 
        /*
-        * Fill in mbuf with extended udp header
+        * Fill in mbuf with extended UDP header
         * and addresses and length put into network format.
         */
        m->m_off = MMAXOFF - sizeof (struct udpiphdr);
         * and addresses and length put into network format.
         */
        m->m_off = MMAXOFF - sizeof (struct udpiphdr);
@@ -146,12 +182,12 @@ COUNT(UDP_OUTPUT);
        ui->ui_next = ui->ui_prev = 0;
        ui->ui_x1 = 0;
        ui->ui_pr = IPPROTO_UDP;
        ui->ui_next = ui->ui_prev = 0;
        ui->ui_x1 = 0;
        ui->ui_pr = IPPROTO_UDP;
-       ui->ui_len = sizeof (struct udpiphdr) + len;
+       ui->ui_len = len + sizeof (struct udphdr);
        ui->ui_src = inp->inp_laddr;
        ui->ui_dst = inp->inp_faddr;
        ui->ui_sport = inp->inp_lport;
        ui->ui_dport = inp->inp_fport;
        ui->ui_src = inp->inp_laddr;
        ui->ui_dst = inp->inp_faddr;
        ui->ui_sport = inp->inp_lport;
        ui->ui_dport = inp->inp_fport;
-       ui->ui_ulen = htons((u_short)len);
+       ui->ui_ulen = htons((u_short)ui->ui_len);
 
        /*
         * Stuff checksum and output datagram.
 
        /*
         * Stuff checksum and output datagram.
@@ -160,23 +196,21 @@ COUNT(UDP_OUTPUT);
        ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
        ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
        ((struct ip *)ui)->ip_ttl = MAXTTL;
        ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
        ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
        ((struct ip *)ui)->ip_ttl = MAXTTL;
-       (void) ip_output(m, (struct mbuf *)0);
-       return;
-bad:
-       m_freem(m);
+       so = inp->inp_socket;
+       return (ip_output(m, (struct mbuf *)0,
+           (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0,
+           so->so_state & SS_PRIV));
 }
 
 /*ARGSUSED*/
 }
 
 /*ARGSUSED*/
-udp_usrreq(so, req, m, addr)
+udp_usrreq(so, req, m, nam)
        struct socket *so;
        int req;
        struct socket *so;
        int req;
-       struct mbuf *m;
-       caddr_t addr;
+       struct mbuf *m, *nam;
 {
        struct inpcb *inp = sotoinpcb(so);
 {
        struct inpcb *inp = sotoinpcb(so);
-       int error;
+       int error = 0;
 
 
-COUNT(UDP_USRREQ);
        if (inp == 0 && req != PRU_ATTACH)
                return (EINVAL);
        switch (req) {
        if (inp == 0 && req != PRU_ATTACH)
                return (EINVAL);
        switch (req) {
@@ -184,9 +218,12 @@ COUNT(UDP_USRREQ);
        case PRU_ATTACH:
                if (inp != 0)
                        return (EINVAL);
        case PRU_ATTACH:
                if (inp != 0)
                        return (EINVAL);
-               error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
+               error = in_pcballoc(so, &udb);
                if (error)
                if (error)
-                       return (error);
+                       break;
+               error = soreserve(so, 2048, 2048);
+               if (error)
+                       break;
                break;
 
        case PRU_DETACH:
                break;
 
        case PRU_DETACH:
@@ -195,20 +232,27 @@ COUNT(UDP_USRREQ);
                in_pcbdetach(inp);
                break;
 
                in_pcbdetach(inp);
                break;
 
+       case PRU_BIND:
+               error = in_pcbbind(inp, nam);
+               break;
+
+       case PRU_LISTEN:
+               error = EOPNOTSUPP;
+               break;
+
        case PRU_CONNECT:
        case PRU_CONNECT:
-               if (inp->inp_faddr.s_addr)
+               if (inp->inp_faddr.s_addr != INADDR_ANY)
                        return (EISCONN);
                        return (EISCONN);
-               error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
-               if (error)
-                       return (error);
-               soisconnected(so);
+               error = in_pcbconnect(inp, nam);
+               if (error == 0)
+                       soisconnected(so);
                break;
 
        case PRU_ACCEPT:
                return (EOPNOTSUPP);
 
        case PRU_DISCONNECT:
                break;
 
        case PRU_ACCEPT:
                return (EOPNOTSUPP);
 
        case PRU_DISCONNECT:
-               if (inp->inp_faddr.s_addr == 0)
+               if (inp->inp_faddr.s_addr == INADDR_ANY)
                        return (ENOTCONN);
                in_pcbdisconnect(inp);
                soisdisconnected(so);
                        return (ENOTCONN);
                in_pcbdisconnect(inp);
                soisdisconnected(so);
@@ -218,20 +262,26 @@ COUNT(UDP_USRREQ);
                socantsendmore(so);
                break;
 
                socantsendmore(so);
                break;
 
-       case PRU_SEND:
-               if (addr) {
-                       if (inp->inp_faddr.s_addr)
+       case PRU_SEND: {
+               struct in_addr laddr;
+
+               if (nam) {
+                       laddr = inp->inp_laddr;
+                       if (inp->inp_faddr.s_addr != INADDR_ANY)
                                return (EISCONN);
                                return (EISCONN);
-                       error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
+                       error = in_pcbconnect(inp, nam);
                        if (error)
                        if (error)
-                               return (error);
+                               break;
                } else {
                } else {
-                       if (inp->inp_faddr.s_addr == 0)
+                       if (inp->inp_faddr.s_addr == INADDR_ANY)
                                return (ENOTCONN);
                }
                                return (ENOTCONN);
                }
-               udp_output(inp, m);
-               if (addr)
+               error = udp_output(inp, m);
+               if (nam) {
                        in_pcbdisconnect(inp);
                        in_pcbdisconnect(inp);
+                       inp->inp_laddr = laddr;
+               }
+               }
                break;
 
        case PRU_ABORT:
                break;
 
        case PRU_ABORT:
@@ -243,8 +293,12 @@ COUNT(UDP_USRREQ);
        case PRU_CONTROL:
                return (EOPNOTSUPP);
 
        case PRU_CONTROL:
                return (EOPNOTSUPP);
 
+       case PRU_SOCKADDR:
+               in_setsockaddr(inp, nam);
+               break;
+
        default:
                panic("udp_usrreq");
        }
        default:
                panic("udp_usrreq");
        }
-       return (0);
+       return (error);
 }
 }