root/netinet/raw_ip.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rip_init
  2. rip_input
  3. rip_output
  4. rip_ctloutput
  5. rip_usrreq

    1 /*      $OpenBSD: raw_ip.c,v 1.40 2006/11/25 18:04:44 claudio Exp $     */
    2 /*      $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $     */
    3 
    4 /*
    5  * Copyright (c) 1982, 1986, 1988, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
   33  *
   34  * NRL grants permission for redistribution and use in source and binary
   35  * forms, with or without modification, of the software and documentation
   36  * created at NRL provided that the following conditions are met:
   37  *
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 3. All advertising materials mentioning features or use of this software
   44  *    must display the following acknowledgements:
   45  *      This product includes software developed by the University of
   46  *      California, Berkeley and its contributors.
   47  *      This product includes software developed at the Information
   48  *      Technology Division, US Naval Research Laboratory.
   49  * 4. Neither the name of the NRL nor the names of its contributors
   50  *    may be used to endorse or promote products derived from this software
   51  *    without specific prior written permission.
   52  *
   53  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
   54  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   55  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   56  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
   57  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   60  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   61  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   62  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   64  *
   65  * The views and conclusions contained in the software and documentation
   66  * are those of the authors and should not be interpreted as representing
   67  * official policies, either expressed or implied, of the US Naval
   68  * Research Laboratory (NRL).
   69  */
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/mbuf.h>
   74 #include <sys/socket.h>
   75 #include <sys/protosw.h>
   76 #include <sys/socketvar.h>
   77 
   78 #include <net/if.h>
   79 #include <net/route.h>
   80 
   81 #include <netinet/in.h>
   82 #include <netinet/in_systm.h>
   83 #include <netinet/ip.h>
   84 #include <netinet/ip_mroute.h>
   85 #include <netinet/ip_var.h>
   86 #include <netinet/in_pcb.h>
   87 #include <netinet/in_var.h>
   88 #include <netinet/ip_icmp.h>
   89 
   90 struct inpcbtable rawcbtable;
   91 
   92 /*
   93  * Nominal space allocated to a raw ip socket.
   94  */
   95 #define RIPSNDQ         8192
   96 #define RIPRCVQ         8192
   97 
   98 /*
   99  * Raw interface to IP protocol.
  100  */
  101 
  102 /*
  103  * Initialize raw connection block q.
  104  */
  105 void
  106 rip_init()
  107 {
  108 
  109         in_pcbinit(&rawcbtable, 1);
  110 }
  111 
  112 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
  113 
  114 /*
  115  * Setup generic address and protocol structures
  116  * for raw_input routine, then pass them along with
  117  * mbuf chain.
  118  */
  119 void
  120 rip_input(struct mbuf *m, ...)
  121 {
  122         struct ip *ip = mtod(m, struct ip *);
  123         struct inpcb *inp, *last = NULL;
  124         struct mbuf *opts = NULL;
  125 
  126         ripsrc.sin_addr = ip->ip_src;
  127         CIRCLEQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) {
  128 #ifdef INET6
  129                 if (inp->inp_flags & INP_IPV6)
  130                         continue;
  131 #endif
  132                 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
  133                         continue;
  134                 if (inp->inp_laddr.s_addr &&
  135                     inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
  136                         continue;
  137                 if (inp->inp_faddr.s_addr &&
  138                     inp->inp_faddr.s_addr != ip->ip_src.s_addr)
  139                         continue;
  140                 if (last) {
  141                         struct mbuf *n;
  142 
  143                         if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
  144                                 if (last->inp_flags & INP_CONTROLOPTS)
  145                                         ip_savecontrol(last, &opts, ip, n);
  146                                 if (sbappendaddr(&last->inp_socket->so_rcv,
  147                                     sintosa(&ripsrc), n, opts) == 0) {
  148                                         /* should notify about lost packet */
  149                                         m_freem(n);
  150                                         if (opts)
  151                                                 m_freem(opts);
  152                                 } else
  153                                         sorwakeup(last->inp_socket);
  154                                 opts = NULL;
  155                         }
  156                 }
  157                 last = inp;
  158         }
  159         if (last) {
  160                 if (last->inp_flags & INP_CONTROLOPTS)
  161                         ip_savecontrol(last, &opts, ip, m);
  162                 if (sbappendaddr(&last->inp_socket->so_rcv, sintosa(&ripsrc), m,
  163                     opts) == 0) {
  164                         m_freem(m);
  165                         if (opts)
  166                                 m_freem(opts);
  167                 } else
  168                         sorwakeup(last->inp_socket);
  169         } else {
  170                 if (ip->ip_p != IPPROTO_ICMP)
  171                         icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0);
  172                 else
  173                         m_freem(m);
  174                 ipstat.ips_noproto++;
  175                 ipstat.ips_delivered--;
  176         }
  177 }
  178 
  179 /*
  180  * Generate IP header and pass packet to ip_output.
  181  * Tack on options user may have setup with control call.
  182  */
  183 int
  184 rip_output(struct mbuf *m, ...)
  185 {
  186         struct socket *so;
  187         u_long dst;
  188         struct ip *ip;
  189         struct inpcb *inp;
  190         int flags;
  191         va_list ap;
  192 
  193         va_start(ap, m);
  194         so = va_arg(ap, struct socket *);
  195         dst = va_arg(ap, u_long);
  196         va_end(ap);
  197 
  198         inp = sotoinpcb(so);
  199         flags = (so->so_options & (SO_DONTROUTE|SO_JUMBO)) | IP_ALLOWBROADCAST;
  200 
  201         /*
  202          * If the user handed us a complete IP packet, use it.
  203          * Otherwise, allocate an mbuf for a header and fill it in.
  204          */
  205         if ((inp->inp_flags & INP_HDRINCL) == 0) {
  206                 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
  207                         m_freem(m);
  208                         return (EMSGSIZE);
  209                 }
  210                 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
  211                 if (!m)
  212                         return (ENOBUFS);
  213                 ip = mtod(m, struct ip *);
  214                 ip->ip_tos = inp->inp_ip.ip_tos;
  215                 ip->ip_off = htons(0);
  216                 ip->ip_p = inp->inp_ip.ip_p;
  217                 ip->ip_len = htons(m->m_pkthdr.len);
  218                 ip->ip_src = inp->inp_laddr;
  219                 ip->ip_dst.s_addr = dst;
  220                 ip->ip_ttl = inp->inp_ip.ip_ttl ? inp->inp_ip.ip_ttl : MAXTTL;
  221         } else {
  222                 if (m->m_pkthdr.len > IP_MAXPACKET) {
  223                         m_freem(m);
  224                         return (EMSGSIZE);
  225                 }
  226                 if (m->m_pkthdr.len < sizeof(struct ip)) {
  227                         m_freem(m);
  228                         return (EINVAL);
  229                 }
  230                 ip = mtod(m, struct ip *);
  231                 /*
  232                  * don't allow both user specified and setsockopt options,
  233                  * and don't allow packet length sizes that will crash
  234                  */
  235                 if ((ip->ip_hl != (sizeof (*ip) >> 2) && inp->inp_options) ||
  236                     ntohs(ip->ip_len) > m->m_pkthdr.len ||
  237                     ntohs(ip->ip_len) < ip->ip_hl << 2) {
  238                         m_freem(m);
  239                         return (EINVAL);
  240                 }
  241                 if (ip->ip_id == 0) {
  242                         ip->ip_id = htons(ip_randomid());
  243                 }
  244                 /* XXX prevent ip_output from overwriting header fields */
  245                 flags |= IP_RAWOUTPUT;
  246                 ipstat.ips_rawout++;
  247         }
  248 #ifdef INET6
  249         /*
  250          * A thought:  Even though raw IP shouldn't be able to set IPv6
  251          *             multicast options, if it does, the last parameter to
  252          *             ip_output should be guarded against v6/v4 problems.
  253          */
  254 #endif
  255         return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
  256             inp->inp_moptions, inp));
  257 }
  258 
  259 /*
  260  * Raw IP socket option processing.
  261  */
  262 int
  263 rip_ctloutput(int op, struct socket *so, int level, int optname,
  264     struct mbuf **m)
  265 {
  266         struct inpcb *inp = sotoinpcb(so);
  267         int error;
  268 
  269         if (level != IPPROTO_IP) {
  270                 if (op == PRCO_SETOPT && *m)
  271                         (void) m_free(*m);
  272                 return (EINVAL);
  273         }
  274 
  275         switch (optname) {
  276 
  277         case IP_HDRINCL:
  278                 error = 0;
  279                 if (op == PRCO_SETOPT) {
  280                         if (*m == 0 || (*m)->m_len < sizeof (int))
  281                                 error = EINVAL;
  282                         else if (*mtod(*m, int *))
  283                                 inp->inp_flags |= INP_HDRINCL;
  284                         else
  285                                 inp->inp_flags &= ~INP_HDRINCL;
  286                         if (*m)
  287                                 (void)m_free(*m);
  288                 } else {
  289                         *m = m_get(M_WAIT, M_SOOPTS);
  290                         (*m)->m_len = sizeof(int);
  291                         *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
  292                 }
  293                 return (error);
  294 
  295         case MRT_INIT:
  296         case MRT_DONE:
  297         case MRT_ADD_VIF:
  298         case MRT_DEL_VIF:
  299         case MRT_ADD_MFC:
  300         case MRT_DEL_MFC:
  301         case MRT_VERSION:
  302         case MRT_ASSERT:
  303         case MRT_API_SUPPORT:
  304         case MRT_API_CONFIG:
  305         case MRT_ADD_BW_UPCALL:
  306         case MRT_DEL_BW_UPCALL:
  307 #ifdef MROUTING
  308                 switch (op) {
  309                 case PRCO_SETOPT:
  310                         error = ip_mrouter_set(so, optname, m);
  311                         break;
  312                 case PRCO_GETOPT:
  313                         error = ip_mrouter_get(so, optname, m);
  314                         break;
  315                 default:
  316                         error = EINVAL;
  317                         break;
  318                 }
  319                 return (error);
  320 #else
  321                 if (op == PRCO_SETOPT && *m)
  322                         m_free(*m);
  323                 return (EOPNOTSUPP);
  324 #endif
  325         }
  326         return (ip_ctloutput(op, so, level, optname, m));
  327 }
  328 
  329 u_long  rip_sendspace = RIPSNDQ;
  330 u_long  rip_recvspace = RIPRCVQ;
  331 
  332 /*ARGSUSED*/
  333 int
  334 rip_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
  335     struct mbuf *control)
  336 {
  337         int error = 0;
  338         struct inpcb *inp = sotoinpcb(so);
  339 #ifdef MROUTING
  340         extern struct socket *ip_mrouter;
  341 #endif
  342         if (req == PRU_CONTROL)
  343                 return (in_control(so, (u_long)m, (caddr_t)nam,
  344                     (struct ifnet *)control));
  345 
  346         if (inp == NULL && req != PRU_ATTACH) {
  347                 error = EINVAL;
  348                 goto release;
  349         }
  350 
  351         switch (req) {
  352 
  353         case PRU_ATTACH:
  354                 if (inp)
  355                         panic("rip_attach");
  356                 if ((so->so_state & SS_PRIV) == 0) {
  357                         error = EACCES;
  358                         break;
  359                 }
  360                 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
  361                     (error = in_pcballoc(so, &rawcbtable)))
  362                         break;
  363                 inp = (struct inpcb *)so->so_pcb;
  364                 inp->inp_ip.ip_p = (long)nam;
  365                 break;
  366 
  367         case PRU_DISCONNECT:
  368                 if ((so->so_state & SS_ISCONNECTED) == 0) {
  369                         error = ENOTCONN;
  370                         break;
  371                 }
  372                 /* FALLTHROUGH */
  373         case PRU_ABORT:
  374                 soisdisconnected(so);
  375                 /* FALLTHROUGH */
  376         case PRU_DETACH:
  377                 if (inp == 0)
  378                         panic("rip_detach");
  379 #ifdef MROUTING
  380                 if (so == ip_mrouter)
  381                         ip_mrouter_done();
  382 #endif
  383                 in_pcbdetach(inp);
  384                 break;
  385 
  386         case PRU_BIND:
  387             {
  388                 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
  389 
  390                 if (nam->m_len != sizeof(*addr)) {
  391                         error = EINVAL;
  392                         break;
  393                 }
  394                 if ((TAILQ_EMPTY(&ifnet)) ||
  395                     ((addr->sin_family != AF_INET) &&
  396                      (addr->sin_family != AF_IMPLINK)) ||
  397                     (addr->sin_addr.s_addr &&
  398                      ifa_ifwithaddr(sintosa(addr)) == 0)) {
  399                         error = EADDRNOTAVAIL;
  400                         break;
  401                 }
  402                 inp->inp_laddr = addr->sin_addr;
  403                 break;
  404             }
  405         case PRU_CONNECT:
  406             {
  407                 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
  408 
  409                 if (nam->m_len != sizeof(*addr)) {
  410                         error = EINVAL;
  411                         break;
  412                 }
  413                 if (TAILQ_EMPTY(&ifnet)) {
  414                         error = EADDRNOTAVAIL;
  415                         break;
  416                 }
  417                 if ((addr->sin_family != AF_INET) &&
  418                      (addr->sin_family != AF_IMPLINK)) {
  419                         error = EAFNOSUPPORT;
  420                         break;
  421                 }
  422                 inp->inp_faddr = addr->sin_addr;
  423                 soisconnected(so);
  424                 break;
  425             }
  426 
  427         case PRU_CONNECT2:
  428                 error = EOPNOTSUPP;
  429                 break;
  430 
  431         /*
  432          * Mark the connection as being incapable of further input.
  433          */
  434         case PRU_SHUTDOWN:
  435                 socantsendmore(so);
  436                 break;
  437 
  438         /*
  439          * Ship a packet out.  The appropriate raw output
  440          * routine handles any massaging necessary.
  441          */
  442         case PRU_SEND:
  443             {
  444                 u_int32_t dst;
  445 
  446                 if (so->so_state & SS_ISCONNECTED) {
  447                         if (nam) {
  448                                 error = EISCONN;
  449                                 break;
  450                         }
  451                         dst = inp->inp_faddr.s_addr;
  452                 } else {
  453                         if (nam == NULL) {
  454                                 error = ENOTCONN;
  455                                 break;
  456                         }
  457                         dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
  458                 }
  459 #ifdef IPSEC
  460                 /* XXX Find an IPsec TDB */
  461 #endif
  462                 error = rip_output(m, so, dst);
  463                 m = NULL;
  464                 break;
  465             }
  466 
  467         case PRU_SENSE:
  468                 /*
  469                  * stat: don't bother with a blocksize.
  470                  */
  471                 return (0);
  472 
  473         /*
  474          * Not supported.
  475          */
  476         case PRU_RCVOOB:
  477         case PRU_RCVD:
  478         case PRU_LISTEN:
  479         case PRU_ACCEPT:
  480         case PRU_SENDOOB:
  481                 error = EOPNOTSUPP;
  482                 break;
  483 
  484         case PRU_SOCKADDR:
  485                 in_setsockaddr(inp, nam);
  486                 break;
  487 
  488         case PRU_PEERADDR:
  489                 in_setpeeraddr(inp, nam);
  490                 break;
  491 
  492         default:
  493                 panic("rip_usrreq");
  494         }
  495 release:
  496         if (m != NULL)
  497                 m_freem(m);
  498         return (error);
  499 }

/* [<][>][^][v][top][bottom][index][help] */