BSD 4_3_Reno release
[unix-history] / usr / src / sys / netinet / raw_ip.c
index 43eeb1a..3825222 100644 (file)
@@ -1,23 +1,27 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution is only permitted until one year after the first shipment
+ * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
+ * binary forms are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement:  This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software.  Neither the name of the University 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 AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  *
- *     @(#)raw_ip.c    7.4 (Berkeley) 6/29/88
+ *     @(#)raw_ip.c    7.8 (Berkeley) 7/25/90
  */
 
 #include "param.h"
  */
 
 #include "param.h"
+#include "malloc.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "protosw.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "protosw.h"
 #include "in_systm.h"
 #include "ip.h"
 #include "ip_var.h"
 #include "in_systm.h"
 #include "ip.h"
 #include "ip_var.h"
+#include "in_pcb.h"
 
 /*
  * Raw interface to IP protocol.
  */
 
 
 /*
  * Raw interface to IP protocol.
  */
 
-struct sockaddr_in ripdst = { AF_INET };
-struct sockaddr_in ripsrc = { AF_INET };
+struct sockaddr_in ripdst = { sizeof(ripdst), AF_INET };
+struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
 struct sockproto ripproto = { PF_INET };
 /*
  * Setup generic address and protocol structures
 struct sockproto ripproto = { PF_INET };
 /*
  * Setup generic address and protocol structures
@@ -53,63 +58,51 @@ rip_input(m)
        ripproto.sp_protocol = ip->ip_p;
        ripdst.sin_addr = ip->ip_dst;
        ripsrc.sin_addr = ip->ip_src;
        ripproto.sp_protocol = ip->ip_p;
        ripdst.sin_addr = ip->ip_dst;
        ripsrc.sin_addr = ip->ip_src;
-       raw_input(m, &ripproto, (struct sockaddr *)&ripsrc,
-         (struct sockaddr *)&ripdst);
+       if (raw_input(m, &ripproto, (struct sockaddr *)&ripsrc,
+         (struct sockaddr *)&ripdst) == 0) {
+               ipstat.ips_noproto++;
+               ipstat.ips_delivered--;
+       }
 }
 
 /*
  * Generate IP header and pass packet to ip_output.
  * Tack on options user may have setup with control call.
  */
 }
 
 /*
  * Generate IP header and pass packet to ip_output.
  * Tack on options user may have setup with control call.
  */
-rip_output(m0, so)
-       struct mbuf *m0;
+#define        satosin(sa)     ((struct sockaddr_in *)(sa))
+rip_output(m, so)
+       register struct mbuf *m;
        struct socket *so;
 {
        struct socket *so;
 {
-       register struct mbuf *m;
        register struct ip *ip;
        register struct ip *ip;
-       int len = 0, error;
-       struct rawcb *rp = sotorawcb(so);
-       struct sockaddr_in *sin;
+       register struct raw_inpcb *rp = sotorawinpcb(so);
+       register struct sockaddr_in *sin;
 
        /*
 
        /*
-        * Calculate data length and get an mbuf
-        * for IP header.
+        * If the user handed us a complete IP packet, use it.
+        * Otherwise, allocate an mbuf for a header and fill it in.
         */
         */
-       for (m = m0; m; m = m->m_next)
-               len += m->m_len;
-       m = m_get(M_DONTWAIT, MT_HEADER);
-       if (m == 0) {
-               error = ENOBUFS;
-               goto bad;
+       if (rp->rinp_flags & RINPF_HDRINCL)
+               ip = mtod(m, struct ip *);
+       else {
+               M_PREPEND(m, sizeof(struct ip), M_WAIT);
+               ip = mtod(m, struct ip *);
+               ip->ip_tos = 0;
+               ip->ip_off = 0;
+               ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol;
+               ip->ip_len = m->m_pkthdr.len;
+               if (sin = satosin(rp->rinp_rcb.rcb_laddr)) {
+                       ip->ip_src = sin->sin_addr;
+               } else
+                       ip->ip_src.s_addr = 0;
+               if (sin = satosin(rp->rinp_rcb.rcb_faddr))
+                   ip->ip_dst = sin->sin_addr;
+               ip->ip_ttl = MAXTTL;
        }
        }
-       
-       /*
-        * Fill in IP header as needed.
-        */
-       m->m_off = MMAXOFF - sizeof(struct ip);
-       m->m_len = sizeof(struct ip);
-       m->m_next = m0;
-       ip = mtod(m, struct ip *);
-       ip->ip_tos = 0;
-       ip->ip_off = 0;
-       ip->ip_p = rp->rcb_proto.sp_protocol;
-       ip->ip_len = sizeof(struct ip) + len;
-       if (rp->rcb_flags & RAW_LADDR) {
-               sin = (struct sockaddr_in *)&rp->rcb_laddr;
-               if (sin->sin_family != AF_INET) {
-                       error = EAFNOSUPPORT;
-                       goto bad;
-               }
-               ip->ip_src.s_addr = sin->sin_addr.s_addr;
-       } else
-               ip->ip_src.s_addr = 0;
-       ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr;
-       ip->ip_ttl = MAXTTL;
-       return (ip_output(m, rp->rcb_options, &rp->rcb_route, 
+       return (ip_output(m,
+          (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options,
+           &rp->rinp_route, 
           (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
           (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
-bad:
-       m_freem(m);
-       return (error);
 }
 
 /*
 }
 
 /*
@@ -122,7 +115,7 @@ rip_ctloutput(op, so, level, optname, m)
        struct mbuf **m;
 {
        int error = 0;
        struct mbuf **m;
 {
        int error = 0;
-       register struct rawcb *rp = sotorawcb(so);
+       register struct raw_inpcb *rp = sotorawinpcb(so);
 
        if (level != IPPROTO_IP)
                error = EINVAL;
 
        if (level != IPPROTO_IP)
                error = EINVAL;
@@ -130,8 +123,20 @@ rip_ctloutput(op, so, level, optname, m)
 
        case PRCO_SETOPT:
                switch (optname) {
 
        case PRCO_SETOPT:
                switch (optname) {
+
                case IP_OPTIONS:
                case IP_OPTIONS:
-                       return (ip_pcbopts(&rp->rcb_options, *m));
+                       return (ip_pcbopts(&rp->rinp_options, *m));
+
+               case IP_HDRINCL:
+                       if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) {
+                               error = EINVAL;
+                               break;
+                       }
+                       if (*mtod(*m, int *))
+                               rp->rinp_flags |= RINPF_HDRINCL;
+                       else
+                               rp->rinp_flags &= ~RINPF_HDRINCL;
+                       break;
 
                default:
                        error = EINVAL;
 
                default:
                        error = EINVAL;
@@ -140,19 +145,27 @@ rip_ctloutput(op, so, level, optname, m)
                break;
 
        case PRCO_GETOPT:
                break;
 
        case PRCO_GETOPT:
+               *m = m_get(M_WAIT, MT_SOOPTS);
                switch (optname) {
                switch (optname) {
+
                case IP_OPTIONS:
                case IP_OPTIONS:
-                       *m = m_get(M_WAIT, MT_SOOPTS);
-                       if (rp->rcb_options) {
-                               (*m)->m_off = rp->rcb_options->m_off;
-                               (*m)->m_len = rp->rcb_options->m_len;
-                               bcopy(mtod(rp->rcb_options, caddr_t),
+                       if (rp->rinp_options) {
+                               (*m)->m_len = rp->rinp_options->m_len;
+                               bcopy(mtod(rp->rinp_options, caddr_t),
                                    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
                        } else
                                (*m)->m_len = 0;
                        break;
                                    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
                        } else
                                (*m)->m_len = 0;
                        break;
+
+               case IP_HDRINCL:
+                       (*m)->m_len = sizeof (int);
+                       *mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
+                       break;
+
                default:
                        error = EINVAL;
                default:
                        error = EINVAL;
+                       m_freem(*m);
+                       *m = 0;
                        break;
                }
                break;
                        break;
                }
                break;
@@ -161,3 +174,75 @@ rip_ctloutput(op, so, level, optname, m)
                (void)m_free(*m);
        return (error);
 }
                (void)m_free(*m);
        return (error);
 }
+
+/*ARGSUSED*/
+rip_usrreq(so, req, m, nam, rights, control)
+       register struct socket *so;
+       int req;
+       struct mbuf *m, *nam, *rights, *control;
+{
+       register int error = 0;
+       register struct raw_inpcb *rp = sotorawinpcb(so);
+
+       switch (req) {
+
+       case PRU_ATTACH:
+               if (rp)
+                       panic("rip_attach");
+               MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK);
+               if (rp == 0)
+                       return (ENOBUFS);
+               bzero((caddr_t)rp, sizeof *rp);
+               so->so_pcb = (caddr_t)rp;
+               break;
+
+       case PRU_DETACH:
+               if (rp == 0)
+                       panic("rip_detach");
+               if (rp->rinp_options)
+                       m_freem(rp->rinp_options);
+               if (rp->rinp_route.ro_rt)
+                       RTFREE(rp->rinp_route.ro_rt);
+               if (rp->rinp_rcb.rcb_laddr)
+                       rp->rinp_rcb.rcb_laddr = 0;
+               break;
+
+       case PRU_BIND:
+           {
+               struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
+
+               if (nam->m_len != sizeof(*addr))
+                       return (EINVAL);
+               if ((ifnet == 0) ||
+                   ((addr->sin_family != AF_INET) &&
+                    (addr->sin_family != AF_IMPLINK)) ||
+                   (addr->sin_addr.s_addr &&
+                    ifa_ifwithaddr((struct sockaddr *)addr) == 0))
+                       return (EADDRNOTAVAIL);
+               rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr;
+               rp->rinp_laddr = *addr;
+               return (0);
+           }
+       case PRU_CONNECT:
+           {
+               struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
+
+               if (nam->m_len != sizeof(*addr))
+                       return (EINVAL);
+               if (ifnet == 0)
+                       return (EADDRNOTAVAIL);
+               if ((addr->sin_family != AF_INET) &&
+                    (addr->sin_family != AF_IMPLINK))
+                       return (EAFNOSUPPORT);
+               rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr;
+               rp->rinp_faddr = *addr;
+               soisconnected(so);
+               return (0);
+           }
+       }
+       error =  raw_usrreq(so, req, m, nam, rights, control);
+
+       if (error && (req == PRU_ATTACH) && so->so_pcb)
+               free(so->so_pcb, M_PCB);
+       return (error);
+}