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