raw_ip.c revision 4234
17055Sdg/* 27055Sdg * Copyright (c) 1982, 1986, 1988, 1993 37055Sdg * The Regents of the University of California. All rights reserved. 47055Sdg * 57055Sdg * Redistribution and use in source and binary forms, with or without 67055Sdg * modification, are permitted provided that the following conditions 77055Sdg * are met: 87055Sdg * 1. Redistributions of source code must retain the above copyright 97055Sdg * notice, this list of conditions and the following disclaimer. 107055Sdg * 2. Redistributions in binary form must reproduce the above copyright 117055Sdg * notice, this list of conditions and the following disclaimer in the 127055Sdg * documentation and/or other materials provided with the distribution. 137055Sdg * 3. All advertising materials mentioning features or use of this software 147055Sdg * must display the following acknowledgement: 157055Sdg * This product includes software developed by the University of 167055Sdg * California, Berkeley and its contributors. 177055Sdg * 4. Neither the name of the University nor the names of its contributors 187055Sdg * may be used to endorse or promote products derived from this software 197055Sdg * without specific prior written permission. 207055Sdg * 217055Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 227055Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 237055Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 247055Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 257055Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 267055Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 277055Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 287055Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 297055Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 307055Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 317055Sdg * SUCH DAMAGE. 327055Sdg * 337061Sdg * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 3416063Sgpalmer * $Id: raw_ip.c,v 1.6 1994/10/28 15:09:49 jkh Exp $ 357055Sdg */ 367055Sdg 377055Sdg#include <sys/param.h> 387055Sdg#include <sys/malloc.h> 397055Sdg#include <sys/mbuf.h> 407055Sdg#include <sys/socket.h> 417055Sdg#include <sys/protosw.h> 427055Sdg#include <sys/socketvar.h> 437055Sdg#include <sys/errno.h> 447055Sdg#include <sys/systm.h> 457055Sdg 467055Sdg#include <net/if.h> 477055Sdg#include <net/route.h> 487055Sdg 497055Sdg#include <netinet/in.h> 507055Sdg#include <netinet/in_systm.h> 517055Sdg#include <netinet/ip.h> 527055Sdg#include <netinet/ip_var.h> 537055Sdg#include <netinet/ip_mroute.h> 547055Sdg#include <netinet/in_pcb.h> 557055Sdg 567055Sdg#ifdef IPFIREWALL 577055Sdg#include <netinet/ip_fw.h> 587055Sdg#endif 597055Sdg 607055Sdgstruct inpcb rawinpcb; 617055Sdg 6211819Sjulian/* 6311819Sjulian * Nominal space allocated to a raw ip socket. 6411819Sjulian */ 6511819Sjulian#define RIPSNDQ 8192 6611819Sjulian#define RIPRCVQ 8192 677055Sdg 687055Sdg/* 697055Sdg * Raw interface to IP protocol. 707055Sdg */ 717055Sdg 727055Sdg/* 737055Sdg * Initialize raw connection block q. 747055Sdg */ 757055Sdgvoid 767055Sdgrip_init() 777055Sdg{ 787055Sdg 797055Sdg rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; 807055Sdg} 817055Sdg 827055Sdgstruct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 837055Sdg/* 847055Sdg * Setup generic address and protocol structures 857055Sdg * for raw_input routine, then pass them along with 867055Sdg * mbuf chain. 877055Sdg */ 887055Sdgvoid 897055Sdgrip_input(m) 907055Sdg struct mbuf *m; 917055Sdg{ 927055Sdg register struct ip *ip = mtod(m, struct ip *); 937055Sdg register struct inpcb *inp; 947055Sdg struct socket *last = 0; 957055Sdg 967055Sdg ripsrc.sin_addr = ip->ip_src; 977055Sdg for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) { 987055Sdg if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 997055Sdg continue; 1007055Sdg if (inp->inp_laddr.s_addr && 1017055Sdg inp->inp_laddr.s_addr == ip->ip_dst.s_addr) 1027055Sdg continue; 1037055Sdg if (inp->inp_faddr.s_addr && 1047055Sdg inp->inp_faddr.s_addr == ip->ip_src.s_addr) 1057055Sdg continue; 1067055Sdg if (last) { 1077055Sdg struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 1087055Sdg if (n) { 1097055Sdg if (sbappendaddr(&last->so_rcv, 1107055Sdg (struct sockaddr *)&ripsrc, n, 1117055Sdg (struct mbuf *)0) == 0) 1127055Sdg /* should notify about lost packet */ 1137055Sdg m_freem(n); 1147055Sdg else 1157055Sdg sorwakeup(last); 1167055Sdg } 1177055Sdg } 1187055Sdg last = inp->inp_socket; 1197055Sdg } 1207055Sdg if (last) { 1217055Sdg if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, 1227055Sdg m, (struct mbuf *)0) == 0) 1237055Sdg m_freem(m); 1247055Sdg else 1257055Sdg sorwakeup(last); 1267055Sdg } else { 1277055Sdg m_freem(m); 1287055Sdg ipstat.ips_noproto++; 1297055Sdg ipstat.ips_delivered--; 1307055Sdg } 1317055Sdg} 1327055Sdg 1337055Sdg/* 1347055Sdg * Generate IP header and pass packet to ip_output. 1357055Sdg * Tack on options user may have setup with control call. 1367055Sdg */ 1377055Sdgint 1387055Sdgrip_output(m, so, dst) 1397055Sdg register struct mbuf *m; 1408876Srgrimes struct socket *so; 1417055Sdg u_long dst; 1427055Sdg{ 1437055Sdg register struct ip *ip; 1447055Sdg register struct inpcb *inp = sotoinpcb(so); 1457055Sdg struct mbuf *opts; 1467055Sdg int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 1477055Sdg 1487055Sdg /* 1497055Sdg * If the user handed us a complete IP packet, use it. 1507055Sdg * Otherwise, allocate an mbuf for a header and fill it in. 1517055Sdg */ 1527055Sdg if ((inp->inp_flags & INP_HDRINCL) == 0) { 1537055Sdg M_PREPEND(m, sizeof(struct ip), M_WAIT); 1547055Sdg ip = mtod(m, struct ip *); 1557055Sdg ip->ip_tos = 0; 1567055Sdg ip->ip_off = 0; 1577055Sdg ip->ip_p = inp->inp_ip.ip_p; 1587055Sdg ip->ip_len = m->m_pkthdr.len; 1597055Sdg ip->ip_src = inp->inp_laddr; 1607055Sdg ip->ip_dst.s_addr = dst; 1617055Sdg ip->ip_ttl = MAXTTL; 1627055Sdg opts = inp->inp_options; 1637055Sdg } else { 1647055Sdg ip = mtod(m, struct ip *); 1657055Sdg if (ip->ip_id == 0) 1667055Sdg ip->ip_id = htons(ip_id++); 1677055Sdg opts = NULL; 1687055Sdg /* XXX prevent ip_output from overwriting header fields */ 1697055Sdg flags |= IP_RAWOUTPUT; 17011819Sjulian ipstat.ips_rawout++; 17111819Sjulian } 17211819Sjulian return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); 17311819Sjulian} 17411819Sjulian 17511819Sjulian/* 17611819Sjulian * Raw IP socket option processing. 17711819Sjulian */ 17811819Sjulianint 17911819Sjulianrip_ctloutput(op, so, level, optname, m) 18011819Sjulian int op; 18111819Sjulian struct socket *so; 1827055Sdg int level, optname; 1837055Sdg struct mbuf **m; 1847055Sdg{ 1857055Sdg register struct inpcb *inp = sotoinpcb(so); 1867055Sdg register int error; 1877055Sdg 1887055Sdg if (level != IPPROTO_IP) 1897055Sdg return (EINVAL); 1907055Sdg 1917055Sdg switch (optname) { 1927055Sdg 1937055Sdg case IP_HDRINCL: 1947055Sdg if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 1957055Sdg if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 1967055Sdg return (EINVAL); 1977055Sdg if (op == PRCO_SETOPT) { 1987055Sdg if (*mtod(*m, int *)) 1997055Sdg inp->inp_flags |= INP_HDRINCL; 2007055Sdg else 2017055Sdg inp->inp_flags &= ~INP_HDRINCL; 2027055Sdg (void)m_free(*m); 2037055Sdg } else { 2047055Sdg (*m)->m_len = sizeof (int); 2057055Sdg *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 2067055Sdg } 2077055Sdg return (0); 2087055Sdg } 2097055Sdg break; 2107055Sdg 2117055Sdg#ifdef IPFIREWALL 2127055Sdg case IP_FW_ADD_BLK: 2137055Sdg case IP_FW_ADD_FWD: 2147055Sdg case IP_FW_CHK_BLK: 2157055Sdg case IP_FW_CHK_FWD: 2167055Sdg case IP_FW_DEL_BLK: 2177055Sdg case IP_FW_DEL_FWD: 2187055Sdg case IP_FW_FLUSH: 2197055Sdg case IP_FW_POLICY: 2207055Sdg 2217055Sdg if (op == PRCO_SETOPT) { 2227055Sdg error=ip_fw_ctl(optname, *m); 2237055Sdg if (*m) 2247055Sdg (void)m_free(*m); 2257055Sdg } 2267055Sdg else 2277055Sdg error=EINVAL; 2287055Sdg return(error); 2297055Sdg#endif 2307055Sdg 2317055Sdg 2327055Sdg case IP_RSVP_ON: 2337055Sdg error = ip_rsvp_init(so); 2347055Sdg break; 2357055Sdg 2367055Sdg case IP_RSVP_OFF: 2377055Sdg error = ip_rsvp_done(); 2387055Sdg break; 2397055Sdg 2408876Srgrimes case DVMRP_INIT: 2417055Sdg case DVMRP_DONE: 2427055Sdg case DVMRP_ADD_VIF: 2437055Sdg case DVMRP_DEL_VIF: 2447055Sdg case DVMRP_ADD_MFC: 2457055Sdg case DVMRP_DEL_MFC: 2467055Sdg if (op == PRCO_SETOPT) { 2477055Sdg error = ip_mrouter_cmd(optname, so, *m); 2487055Sdg if (*m) 2497055Sdg (void)m_free(*m); 2507055Sdg } else 2517055Sdg error = EINVAL; 2527055Sdg return (error); 2537055Sdg } 2547055Sdg return (ip_ctloutput(op, so, level, optname, m)); 2557055Sdg} 2567055Sdg 2577055Sdgu_long rip_sendspace = RIPSNDQ; 2587055Sdgu_long rip_recvspace = RIPRCVQ; 2597055Sdg 2607055Sdg/*ARGSUSED*/ 2617055Sdgint 2627055Sdgrip_usrreq(so, req, m, nam, control) 2637055Sdg register struct socket *so; 2647055Sdg int req; 2657055Sdg struct mbuf *m, *nam, *control; 2667055Sdg{ 2677055Sdg register int error = 0; 2687055Sdg register struct inpcb *inp = sotoinpcb(so); 2698876Srgrimes switch (req) { 2707055Sdg 2717055Sdg case PRU_ATTACH: 2727055Sdg if (inp) 2737055Sdg panic("rip_attach"); 2747055Sdg if ((so->so_state & SS_PRIV) == 0) { 2757055Sdg error = EACCES; 2768876Srgrimes break; 2777055Sdg } 2787055Sdg if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 2797055Sdg (error = in_pcballoc(so, &rawinpcb))) 2807055Sdg break; 2817055Sdg inp = (struct inpcb *)so->so_pcb; 2828384Sdg inp->inp_ip.ip_p = (int)nam; 2837055Sdg break; 2847055Sdg 2857055Sdg case PRU_DISCONNECT: 2867055Sdg if ((so->so_state & SS_ISCONNECTED) == 0) { 2877055Sdg error = ENOTCONN; 2887055Sdg break; 2897055Sdg } 2907055Sdg /* FALLTHROUGH */ 2917055Sdg case PRU_ABORT: 2927055Sdg soisdisconnected(so); 2937055Sdg /* FALLTHROUGH */ 2947055Sdg case PRU_DETACH: 2957055Sdg if (inp == 0) 2967055Sdg panic("rip_detach"); 2977055Sdg if (so == ip_mrouter) 2987055Sdg ip_mrouter_done(); 2997055Sdg in_pcbdetach(inp); 3007055Sdg break; 3017055Sdg 3027055Sdg case PRU_BIND: 3037055Sdg { 3047055Sdg struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 3057055Sdg 3067055Sdg if (nam->m_len != sizeof(*addr)) { 3077055Sdg error = EINVAL; 3087055Sdg break; 3097055Sdg } 3107055Sdg if ((ifnet == 0) || 3117055Sdg ((addr->sin_family != AF_INET) && 3127055Sdg (addr->sin_family != AF_IMPLINK)) || 3137055Sdg (addr->sin_addr.s_addr && 3147055Sdg ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 3157055Sdg error = EADDRNOTAVAIL; 3167055Sdg break; 3177055Sdg } 3187055Sdg inp->inp_laddr = addr->sin_addr; 3197055Sdg break; 3207055Sdg } 3217055Sdg case PRU_CONNECT: 3227055Sdg { 3237055Sdg struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 3247055Sdg 3257055Sdg if (nam->m_len != sizeof(*addr)) { 3267055Sdg error = EINVAL; 3277055Sdg break; 3287055Sdg } 3297055Sdg if (ifnet == 0) { 3307055Sdg error = EADDRNOTAVAIL; 3317055Sdg break; 3327055Sdg } 3337055Sdg if ((addr->sin_family != AF_INET) && 3347055Sdg (addr->sin_family != AF_IMPLINK)) { 3357055Sdg error = EAFNOSUPPORT; 3367055Sdg break; 3377055Sdg } 3387055Sdg inp->inp_faddr = addr->sin_addr; 3397055Sdg soisconnected(so); 3407055Sdg break; 3417055Sdg } 3427055Sdg 3438384Sdg case PRU_CONNECT2: 3447055Sdg error = EOPNOTSUPP; 3457055Sdg break; 3467055Sdg 3477055Sdg /* 3487055Sdg * Mark the connection as being incapable of further input. 3497055Sdg */ 3507055Sdg case PRU_SHUTDOWN: 3517055Sdg socantsendmore(so); 3527055Sdg break; 3537055Sdg 3547055Sdg /* 3558384Sdg * Ship a packet out. The appropriate raw output 3567055Sdg * routine handles any massaging necessary. 3578384Sdg */ 3587055Sdg case PRU_SEND: 3597055Sdg { 3607055Sdg register u_long dst; 3617055Sdg 3627055Sdg if (so->so_state & SS_ISCONNECTED) { 3637055Sdg if (nam) { 3647055Sdg error = EISCONN; 3657055Sdg break; 3667055Sdg } 3677055Sdg dst = inp->inp_faddr.s_addr; 3687055Sdg } else { 3697055Sdg if (nam == NULL) { 3707055Sdg error = ENOTCONN; 3717055Sdg break; 3727055Sdg } 3737055Sdg dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 3747055Sdg } 3757055Sdg error = rip_output(m, so, dst); 3767055Sdg m = NULL; 3777055Sdg break; 3787055Sdg } 3797055Sdg 3807055Sdg case PRU_SENSE: 3817055Sdg /* 3827055Sdg * stat: don't bother with a blocksize. 3837055Sdg */ 3847055Sdg return (0); 3857055Sdg 3867055Sdg /* 3877055Sdg * Not supported. 3887055Sdg */ 3897055Sdg case PRU_RCVOOB: 3907055Sdg case PRU_RCVD: 3917055Sdg case PRU_LISTEN: 3927055Sdg case PRU_ACCEPT: 3937055Sdg case PRU_SENDOOB: 3947055Sdg error = EOPNOTSUPP; 3957055Sdg break; 3967055Sdg 3977055Sdg case PRU_SOCKADDR: 3987055Sdg in_setsockaddr(inp, nam); 3997055Sdg break; 4007055Sdg 4017055Sdg case PRU_PEERADDR: 4027055Sdg in_setpeeraddr(inp, nam); 4037055Sdg break; 4047055Sdg 4057055Sdg default: 4067055Sdg panic("rip_usrreq"); 4077055Sdg } 4087055Sdg if (m != NULL) 4097055Sdg m_freem(m); 4107055Sdg return (error); 4117055Sdg} 4127055Sdg