The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/raw_ip.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: aed9f6f753292a50fe6cbb0e7e9420db


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.