raw_ip.c revision 70254
11573Srgrimes/*
21573Srgrimes * Copyright (c) 1982, 1986, 1988, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 3. All advertising materials mentioning features or use of this software
141573Srgrimes *    must display the following acknowledgement:
151573Srgrimes *	This product includes software developed by the University of
161573Srgrimes *	California, Berkeley and its contributors.
171573Srgrimes * 4. Neither the name of the University nor the names of its contributors
181573Srgrimes *    may be used to endorse or promote products derived from this software
191573Srgrimes *    without specific prior written permission.
201573Srgrimes *
211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311573Srgrimes * SUCH DAMAGE.
321573Srgrimes *
331573Srgrimes *	@(#)raw_ip.c	8.7 (Berkeley) 5/15/95
341573Srgrimes * $FreeBSD: head/sys/netinet/raw_ip.c 70254 2000-12-21 21:44:31Z bmilekic $
351573Srgrimes */
361573Srgrimes
371573Srgrimes#include "opt_inet6.h"
381573Srgrimes#include "opt_ipsec.h"
391573Srgrimes
401573Srgrimes#include <sys/param.h>
411573Srgrimes#include <sys/systm.h>
421573Srgrimes#include <sys/kernel.h>
431573Srgrimes#include <sys/malloc.h>
441573Srgrimes#include <sys/mbuf.h>
451573Srgrimes#include <sys/protosw.h>
461573Srgrimes#include <sys/socket.h>
471573Srgrimes#include <sys/socketvar.h>
481573Srgrimes#include <sys/sysctl.h>
491573Srgrimes
501573Srgrimes#include <vm/vm_zone.h>
511573Srgrimes
521573Srgrimes#include <net/if.h>
531573Srgrimes#include <net/route.h>
541573Srgrimes
551573Srgrimes#define _IP_VHL
561573Srgrimes#include <netinet/in.h>
571573Srgrimes#include <netinet/in_systm.h>
581573Srgrimes#include <netinet/ip.h>
591573Srgrimes#include <netinet/in_pcb.h>
601573Srgrimes#include <netinet/in_var.h>
611573Srgrimes#include <netinet/ip_var.h>
621573Srgrimes#include <netinet/ip_mroute.h>
631573Srgrimes
641573Srgrimes#include <netinet/ip_fw.h>
651573Srgrimes
661573Srgrimes#ifdef IPSEC
671573Srgrimes#include <netinet6/ipsec.h>
681573Srgrimes#endif /*IPSEC*/
691573Srgrimes
701573Srgrimes#include "opt_ipdn.h"
711573Srgrimes#ifdef DUMMYNET
721573Srgrimes#include <netinet/ip_dummynet.h>
731573Srgrimes#endif
741573Srgrimes
751573Srgrimesstruct	inpcbhead ripcb;
761573Srgrimesstruct	inpcbinfo ripcbinfo;
771573Srgrimes
781573Srgrimes/*
791573Srgrimes * Nominal space allocated to a raw ip socket.
801573Srgrimes */
811573Srgrimes#define	RIPSNDQ		8192
821573Srgrimes#define	RIPRCVQ		8192
831573Srgrimes
841573Srgrimes/*
851573Srgrimes * Raw interface to IP protocol.
861573Srgrimes */
871573Srgrimes
881573Srgrimes/*
891573Srgrimes * Initialize raw connection block q.
901573Srgrimes */
911573Srgrimesvoid
921573Srgrimesrip_init()
931573Srgrimes{
941573Srgrimes	LIST_INIT(&ripcb);
951573Srgrimes	ripcbinfo.listhead = &ripcb;
961573Srgrimes	/*
971573Srgrimes	 * XXX We don't use the hash list for raw IP, but it's easier
981573Srgrimes	 * to allocate a one entry hash list than it is to check all
991573Srgrimes	 * over the place for hashbase == NULL.
1001573Srgrimes	 */
1011573Srgrimes	ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
1021573Srgrimes	ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
1031573Srgrimes	ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb),
1041573Srgrimes				   maxsockets, ZONE_INTERRUPT, 0);
1051573Srgrimes}
1061573Srgrimes
1071573Srgrimesstatic struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
1081573Srgrimes/*
1091573Srgrimes * Setup generic address and protocol structures
1101573Srgrimes * for raw_input routine, then pass them along with
1111573Srgrimes * mbuf chain.
1121573Srgrimes */
1131573Srgrimesvoid
1141573Srgrimesrip_input(m, off, proto)
1151573Srgrimes	struct mbuf *m;
1161573Srgrimes	int off, proto;
1171573Srgrimes{
1181573Srgrimes	register struct ip *ip = mtod(m, struct ip *);
1191573Srgrimes	register struct inpcb *inp;
1201573Srgrimes	struct inpcb *last = 0;
1211573Srgrimes	struct mbuf *opts = 0;
1221573Srgrimes
1231573Srgrimes	ripsrc.sin_addr = ip->ip_src;
1241573Srgrimes	LIST_FOREACH(inp, &ripcb, inp_list) {
1251573Srgrimes#ifdef INET6
1261573Srgrimes		if ((inp->inp_vflag & INP_IPV4) == 0)
1271573Srgrimes			continue;
1281573Srgrimes#endif
1291573Srgrimes		if (inp->inp_ip_p && inp->inp_ip_p != proto)
1301573Srgrimes			continue;
1311573Srgrimes		if (inp->inp_laddr.s_addr &&
1321573Srgrimes                  inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
1331573Srgrimes			continue;
1341573Srgrimes		if (inp->inp_faddr.s_addr &&
1351573Srgrimes                  inp->inp_faddr.s_addr != ip->ip_src.s_addr)
1361573Srgrimes			continue;
1371573Srgrimes		if (last) {
1383285Sache			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
1393285Sache			if (n) {
1403285Sache				if (last->inp_flags & INP_CONTROLOPTS ||
1413285Sache				    last->inp_socket->so_options & SO_TIMESTAMP)
1423285Sache				    ip_savecontrol(last, &opts, ip, n);
1433285Sache				if (sbappendaddr(&last->inp_socket->so_rcv,
1441573Srgrimes				    (struct sockaddr *)&ripsrc, n,
1451573Srgrimes				    opts) == 0) {
1461573Srgrimes					/* should notify about lost packet */
1471573Srgrimes					m_freem(n);
1481573Srgrimes					if (opts)
1491573Srgrimes					    m_freem(opts);
1501573Srgrimes				} else
1511573Srgrimes					sorwakeup(last->inp_socket);
1521573Srgrimes				opts = 0;
1531573Srgrimes			}
1541573Srgrimes		}
1551573Srgrimes		last = inp;
1561573Srgrimes	}
1571573Srgrimes	if (last) {
1581573Srgrimes		if (last->inp_flags & INP_CONTROLOPTS ||
1591573Srgrimes		    last->inp_socket->so_options & SO_TIMESTAMP)
1601573Srgrimes			ip_savecontrol(last, &opts, ip, m);
1611573Srgrimes		if (sbappendaddr(&last->inp_socket->so_rcv,
1621573Srgrimes		    (struct sockaddr *)&ripsrc, m, opts) == 0) {
1631573Srgrimes			m_freem(m);
1641573Srgrimes			if (opts)
1651573Srgrimes			    m_freem(opts);
1661573Srgrimes		} else
1671573Srgrimes			sorwakeup(last->inp_socket);
1681573Srgrimes	} else {
1691573Srgrimes		m_freem(m);
1701573Srgrimes              ipstat.ips_noproto++;
1711573Srgrimes              ipstat.ips_delivered--;
1721573Srgrimes      }
1731573Srgrimes}
1741573Srgrimes
1751573Srgrimes/*
1761573Srgrimes * Generate IP header and pass packet to ip_output.
1771573Srgrimes * Tack on options user may have setup with control call.
1781573Srgrimes */
1791573Srgrimesint
1801573Srgrimesrip_output(m, so, dst)
1811573Srgrimes	struct mbuf *m;
1821573Srgrimes	struct socket *so;
1831573Srgrimes	u_long dst;
1841573Srgrimes{
1851573Srgrimes	register struct ip *ip;
1861573Srgrimes	register struct inpcb *inp = sotoinpcb(so);
1871573Srgrimes	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
1881573Srgrimes
1891573Srgrimes	/*
1901573Srgrimes	 * If the user handed us a complete IP packet, use it.
1911573Srgrimes	 * Otherwise, allocate an mbuf for a header and fill it in.
1921573Srgrimes	 */
1931573Srgrimes	if ((inp->inp_flags & INP_HDRINCL) == 0) {
1941573Srgrimes		if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
1951573Srgrimes			m_freem(m);
1961573Srgrimes			return(EMSGSIZE);
1971573Srgrimes		}
1981573Srgrimes		M_PREPEND(m, sizeof(struct ip), M_TRYWAIT);
1991573Srgrimes		ip = mtod(m, struct ip *);
2001573Srgrimes		ip->ip_tos = 0;
2011573Srgrimes		ip->ip_off = 0;
2021573Srgrimes		ip->ip_p = inp->inp_ip_p;
2031573Srgrimes		ip->ip_len = m->m_pkthdr.len;
2041573Srgrimes		ip->ip_src = inp->inp_laddr;
2051573Srgrimes		ip->ip_dst.s_addr = dst;
2061573Srgrimes		ip->ip_ttl = MAXTTL;
2071573Srgrimes	} else {
2081573Srgrimes		if (m->m_pkthdr.len > IP_MAXPACKET) {
2091573Srgrimes			m_freem(m);
2101573Srgrimes			return(EMSGSIZE);
2111573Srgrimes		}
2121573Srgrimes		ip = mtod(m, struct ip *);
2131573Srgrimes		/* don't allow both user specified and setsockopt options,
2141573Srgrimes		   and don't allow packet length sizes that will crash */
2151573Srgrimes		if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
2161573Srgrimes		     && inp->inp_options)
2171573Srgrimes		    || (ip->ip_len > m->m_pkthdr.len)
2181573Srgrimes		    || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
2191573Srgrimes			m_freem(m);
2201573Srgrimes			return EINVAL;
2211573Srgrimes		}
2221573Srgrimes		if (ip->ip_id == 0)
2231573Srgrimes			ip->ip_id = htons(ip_id++);
2241573Srgrimes		/* XXX prevent ip_output from overwriting header fields */
2251573Srgrimes		flags |= IP_RAWOUTPUT;
2261573Srgrimes		ipstat.ips_rawout++;
2271573Srgrimes	}
2281573Srgrimes
2291573Srgrimes#ifdef IPSEC
2301573Srgrimes	ipsec_setsocket(m, so);
2311573Srgrimes#endif /*IPSEC*/
2321573Srgrimes
2331573Srgrimes	return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
2341573Srgrimes			  inp->inp_moptions));
2351573Srgrimes}
2361573Srgrimes
2371573Srgrimes/*
2381573Srgrimes * Raw IP socket option processing.
2391573Srgrimes */
2401573Srgrimesint
2411573Srgrimesrip_ctloutput(so, sopt)
2421573Srgrimes	struct socket *so;
2431573Srgrimes	struct sockopt *sopt;
2441573Srgrimes{
2451573Srgrimes	struct	inpcb *inp = sotoinpcb(so);
2461573Srgrimes	int	error, optval;
2471573Srgrimes
2481573Srgrimes	if (sopt->sopt_level != IPPROTO_IP)
2491573Srgrimes		return (EINVAL);
2501573Srgrimes
2511573Srgrimes	error = 0;
2521573Srgrimes
2531573Srgrimes	switch (sopt->sopt_dir) {
2541573Srgrimes	case SOPT_GET:
2551573Srgrimes		switch (sopt->sopt_name) {
2561573Srgrimes		case IP_HDRINCL:
2571573Srgrimes			optval = inp->inp_flags & INP_HDRINCL;
2581573Srgrimes			error = sooptcopyout(sopt, &optval, sizeof optval);
2591573Srgrimes			break;
2601573Srgrimes
2611573Srgrimes		case IP_FW_ADD:
2621573Srgrimes		case IP_FW_GET:
2631573Srgrimes			if (ip_fw_ctl_ptr == 0)
2641573Srgrimes				error = ENOPROTOOPT;
2651573Srgrimes			else
2661573Srgrimes				error = ip_fw_ctl_ptr(sopt);
2671573Srgrimes			break;
2681573Srgrimes
2691573Srgrimes#ifdef DUMMYNET
2701573Srgrimes		case IP_DUMMYNET_GET:
2711573Srgrimes			if (ip_dn_ctl_ptr == NULL)
2721573Srgrimes				error = ENOPROTOOPT ;
2731573Srgrimes			else
2741573Srgrimes				error = ip_dn_ctl_ptr(sopt);
2751573Srgrimes			break ;
2761573Srgrimes#endif /* DUMMYNET */
2771573Srgrimes
2781573Srgrimes		case MRT_INIT:
2791573Srgrimes		case MRT_DONE:
2801573Srgrimes		case MRT_ADD_VIF:
2811573Srgrimes		case MRT_DEL_VIF:
2821573Srgrimes		case MRT_ADD_MFC:
2831573Srgrimes		case MRT_DEL_MFC:
2841573Srgrimes		case MRT_VERSION:
2851573Srgrimes		case MRT_ASSERT:
2861573Srgrimes			error = ip_mrouter_get(so, sopt);
2871573Srgrimes			break;
2881573Srgrimes
2891573Srgrimes		default:
2901573Srgrimes			error = ip_ctloutput(so, sopt);
2911573Srgrimes			break;
2921573Srgrimes		}
2931573Srgrimes		break;
2941573Srgrimes
2951573Srgrimes	case SOPT_SET:
2961573Srgrimes		switch (sopt->sopt_name) {
2971573Srgrimes		case IP_HDRINCL:
2981573Srgrimes			error = sooptcopyin(sopt, &optval, sizeof optval,
2991573Srgrimes					    sizeof optval);
3001573Srgrimes			if (error)
3011573Srgrimes				break;
3021573Srgrimes			if (optval)
3031573Srgrimes				inp->inp_flags |= INP_HDRINCL;
3041573Srgrimes			else
3051573Srgrimes				inp->inp_flags &= ~INP_HDRINCL;
3061573Srgrimes			break;
3071573Srgrimes
3081573Srgrimes		case IP_FW_ADD:
3091573Srgrimes		case IP_FW_DEL:
3101573Srgrimes		case IP_FW_FLUSH:
3111573Srgrimes		case IP_FW_ZERO:
3121573Srgrimes		case IP_FW_RESETLOG:
3131573Srgrimes			if (ip_fw_ctl_ptr == 0)
3141573Srgrimes				error = ENOPROTOOPT;
3151573Srgrimes			else
3161573Srgrimes				error = ip_fw_ctl_ptr(sopt);
3171573Srgrimes			break;
3181573Srgrimes
3191573Srgrimes#ifdef DUMMYNET
3201573Srgrimes		case IP_DUMMYNET_CONFIGURE:
3211573Srgrimes		case IP_DUMMYNET_DEL:
3221573Srgrimes		case IP_DUMMYNET_FLUSH:
3231573Srgrimes			if (ip_dn_ctl_ptr == NULL)
3241573Srgrimes				error = ENOPROTOOPT ;
3251573Srgrimes			else
3261573Srgrimes				error = ip_dn_ctl_ptr(sopt);
3271573Srgrimes			break ;
3281573Srgrimes#endif
3291573Srgrimes
3301573Srgrimes		case IP_RSVP_ON:
3311573Srgrimes			error = ip_rsvp_init(so);
3321573Srgrimes			break;
3331573Srgrimes
3341573Srgrimes		case IP_RSVP_OFF:
3351573Srgrimes			error = ip_rsvp_done();
3361573Srgrimes			break;
3371573Srgrimes
3381573Srgrimes			/* XXX - should be combined */
3391573Srgrimes		case IP_RSVP_VIF_ON:
3401573Srgrimes			error = ip_rsvp_vif_init(so, sopt);
3411573Srgrimes			break;
3421573Srgrimes
3431573Srgrimes		case IP_RSVP_VIF_OFF:
3441573Srgrimes			error = ip_rsvp_vif_done(so, sopt);
3451573Srgrimes			break;
3461573Srgrimes
3471573Srgrimes		case MRT_INIT:
3481573Srgrimes		case MRT_DONE:
3491573Srgrimes		case MRT_ADD_VIF:
3501573Srgrimes		case MRT_DEL_VIF:
3511573Srgrimes		case MRT_ADD_MFC:
3521573Srgrimes		case MRT_DEL_MFC:
3531573Srgrimes		case MRT_VERSION:
3541573Srgrimes		case MRT_ASSERT:
3551573Srgrimes			error = ip_mrouter_set(so, sopt);
3561573Srgrimes			break;
3571573Srgrimes
3581573Srgrimes		default:
3591573Srgrimes			error = ip_ctloutput(so, sopt);
3601573Srgrimes			break;
3611573Srgrimes		}
3621573Srgrimes		break;
3631573Srgrimes	}
3641573Srgrimes
3651573Srgrimes	return (error);
3661573Srgrimes}
3671573Srgrimes
3681573Srgrimes/*
3691573Srgrimes * This function exists solely to receive the PRC_IFDOWN messages which
3701573Srgrimes * are sent by if_down().  It looks for an ifaddr whose ifa_addr is sa,
3711573Srgrimes * and calls in_ifadown() to remove all routes corresponding to that address.
3721573Srgrimes * It also receives the PRC_IFUP messages from if_up() and reinstalls the
3731573Srgrimes * interface routes.
3741573Srgrimes */
3751573Srgrimesvoid
3761573Srgrimesrip_ctlinput(cmd, sa, vip)
3771573Srgrimes	int cmd;
3781573Srgrimes	struct sockaddr *sa;
3791573Srgrimes	void *vip;
3801573Srgrimes{
3811573Srgrimes	struct in_ifaddr *ia;
3821573Srgrimes	struct ifnet *ifp;
3831573Srgrimes	int err;
3841573Srgrimes	int flags;
3851573Srgrimes
3861573Srgrimes	switch (cmd) {
3871573Srgrimes	case PRC_IFDOWN:
3881573Srgrimes		for (ia = in_ifaddrhead.tqh_first; ia;
3891573Srgrimes		     ia = ia->ia_link.tqe_next) {
3901573Srgrimes			if (ia->ia_ifa.ifa_addr == sa
3911573Srgrimes			    && (ia->ia_flags & IFA_ROUTE)) {
3921573Srgrimes				/*
3931573Srgrimes				 * in_ifscrub kills the interface route.
3941573Srgrimes				 */
3951573Srgrimes				in_ifscrub(ia->ia_ifp, ia);
3961573Srgrimes				/*
3971573Srgrimes				 * in_ifadown gets rid of all the rest of
3981573Srgrimes				 * the routes.  This is not quite the right
3991573Srgrimes				 * thing to do, but at least if we are running
4001573Srgrimes				 * a routing process they will come back.
4011573Srgrimes				 */
4021573Srgrimes				in_ifadown(&ia->ia_ifa);
4031573Srgrimes				break;
4041573Srgrimes			}
4051573Srgrimes		}
4061573Srgrimes		break;
4071573Srgrimes
4081573Srgrimes	case PRC_IFUP:
4091573Srgrimes		for (ia = in_ifaddrhead.tqh_first; ia;
4101573Srgrimes		     ia = ia->ia_link.tqe_next) {
4111573Srgrimes			if (ia->ia_ifa.ifa_addr == sa)
4121573Srgrimes				break;
4131573Srgrimes		}
4141573Srgrimes		if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
4151573Srgrimes			return;
4161573Srgrimes		flags = RTF_UP;
4171573Srgrimes		ifp = ia->ia_ifa.ifa_ifp;
4181573Srgrimes
4191573Srgrimes		if ((ifp->if_flags & IFF_LOOPBACK)
4201573Srgrimes		    || (ifp->if_flags & IFF_POINTOPOINT))
4211573Srgrimes			flags |= RTF_HOST;
4221573Srgrimes
4231573Srgrimes		err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
4241573Srgrimes		if (err == 0)
4251573Srgrimes			ia->ia_flags |= IFA_ROUTE;
4261573Srgrimes		break;
4271573Srgrimes	}
4281573Srgrimes}
4291573Srgrimes
4301573Srgrimesu_long	rip_sendspace = RIPSNDQ;
4311573Srgrimesu_long	rip_recvspace = RIPRCVQ;
4321573Srgrimes
4331573SrgrimesSYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
4341573Srgrimes    &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
4351573SrgrimesSYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
4361573Srgrimes    &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
4371573Srgrimes
4381573Srgrimesstatic int
4391573Srgrimesrip_attach(struct socket *so, int proto, struct proc *p)
4401573Srgrimes{
4411573Srgrimes	struct inpcb *inp;
4421573Srgrimes	int error, s;
4431573Srgrimes
4441573Srgrimes	inp = sotoinpcb(so);
4451573Srgrimes	if (inp)
4461573Srgrimes		panic("rip_attach");
4471573Srgrimes	if (p && (error = suser(p)) != 0)
4481573Srgrimes		return error;
4491573Srgrimes
4501573Srgrimes	error = soreserve(so, rip_sendspace, rip_recvspace);
4511573Srgrimes	if (error)
4521573Srgrimes		return error;
4531573Srgrimes	s = splnet();
4541573Srgrimes	error = in_pcballoc(so, &ripcbinfo, p);
4551573Srgrimes	splx(s);
4561573Srgrimes	if (error)
4571573Srgrimes		return error;
4581573Srgrimes	inp = (struct inpcb *)so->so_pcb;
4591573Srgrimes	inp->inp_vflag |= INP_IPV4;
4601573Srgrimes	inp->inp_ip_p = proto;
4611573Srgrimes#ifdef IPSEC
4621573Srgrimes	error = ipsec_init_policy(so, &inp->inp_sp);
4631573Srgrimes	if (error != 0) {
4641573Srgrimes		in_pcbdetach(inp);
4651573Srgrimes		return error;
4661573Srgrimes	}
4671573Srgrimes#endif /*IPSEC*/
4681573Srgrimes	return 0;
4691573Srgrimes}
4701573Srgrimes
4711573Srgrimesstatic int
4721573Srgrimesrip_detach(struct socket *so)
4731573Srgrimes{
4741573Srgrimes	struct inpcb *inp;
4751573Srgrimes
4761573Srgrimes	inp = sotoinpcb(so);
4771573Srgrimes	if (inp == 0)
4781573Srgrimes		panic("rip_detach");
4791573Srgrimes	if (so == ip_mrouter)
4801573Srgrimes		ip_mrouter_done();
4811573Srgrimes	ip_rsvp_force_done(so);
4821573Srgrimes	if (so == ip_rsvpd)
4831573Srgrimes		ip_rsvp_done();
4841573Srgrimes	in_pcbdetach(inp);
4851573Srgrimes	return 0;
4861573Srgrimes}
4871573Srgrimes
4881573Srgrimesstatic int
4891573Srgrimesrip_abort(struct socket *so)
4901573Srgrimes{
4911573Srgrimes	soisdisconnected(so);
4921573Srgrimes	return rip_detach(so);
4931573Srgrimes}
4941573Srgrimes
4951573Srgrimesstatic int
4961573Srgrimesrip_disconnect(struct socket *so)
4971573Srgrimes{
4981573Srgrimes	if ((so->so_state & SS_ISCONNECTED) == 0)
4991573Srgrimes		return ENOTCONN;
5001573Srgrimes	return rip_abort(so);
5011573Srgrimes}
5021573Srgrimes
5031573Srgrimesstatic int
5041573Srgrimesrip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
5051573Srgrimes{
5061573Srgrimes	struct inpcb *inp = sotoinpcb(so);
5071573Srgrimes	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
5081573Srgrimes
5091573Srgrimes	if (nam->sa_len != sizeof(*addr))
5101573Srgrimes		return EINVAL;
5111573Srgrimes
5121573Srgrimes	if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
5131573Srgrimes				    (addr->sin_family != AF_IMPLINK)) ||
5141573Srgrimes	    (addr->sin_addr.s_addr &&
5151573Srgrimes	     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
5161573Srgrimes		return EADDRNOTAVAIL;
5171573Srgrimes	inp->inp_laddr = addr->sin_addr;
5181573Srgrimes	return 0;
5191573Srgrimes}
5201573Srgrimes
5211573Srgrimesstatic int
5221573Srgrimesrip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
5231573Srgrimes{
5241573Srgrimes	struct inpcb *inp = sotoinpcb(so);
5251573Srgrimes	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
5261573Srgrimes
5271573Srgrimes	if (nam->sa_len != sizeof(*addr))
5281573Srgrimes		return EINVAL;
5291573Srgrimes	if (TAILQ_EMPTY(&ifnet))
5301573Srgrimes		return EADDRNOTAVAIL;
5311573Srgrimes	if ((addr->sin_family != AF_INET) &&
5321573Srgrimes	    (addr->sin_family != AF_IMPLINK))
5331573Srgrimes		return EAFNOSUPPORT;
5341573Srgrimes	inp->inp_faddr = addr->sin_addr;
5351573Srgrimes	soisconnected(so);
5361573Srgrimes	return 0;
5371573Srgrimes}
5381573Srgrimes
5391573Srgrimesstatic int
5401573Srgrimesrip_shutdown(struct socket *so)
5411573Srgrimes{
5421573Srgrimes	socantsendmore(so);
5431573Srgrimes	return 0;
5441573Srgrimes}
5451573Srgrimes
5461573Srgrimesstatic int
5471573Srgrimesrip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
5481573Srgrimes	 struct mbuf *control, struct proc *p)
5491573Srgrimes{
5501573Srgrimes	struct inpcb *inp = sotoinpcb(so);
5511573Srgrimes	register u_long dst;
5521573Srgrimes
5531573Srgrimes	if (so->so_state & SS_ISCONNECTED) {
5541573Srgrimes		if (nam) {
5551573Srgrimes			m_freem(m);
5561573Srgrimes			return EISCONN;
5571573Srgrimes		}
5581573Srgrimes		dst = inp->inp_faddr.s_addr;
5591573Srgrimes	} else {
5601573Srgrimes		if (nam == NULL) {
5611573Srgrimes			m_freem(m);
5621573Srgrimes			return ENOTCONN;
5631573Srgrimes		}
5641573Srgrimes		dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
5651573Srgrimes	}
5661573Srgrimes	return rip_output(m, so, dst);
5671573Srgrimes}
5681573Srgrimes
5691573Srgrimesstatic int
5701573Srgrimesrip_pcblist(SYSCTL_HANDLER_ARGS)
5711573Srgrimes{
5721573Srgrimes	int error, i, n, s;
5731573Srgrimes	struct inpcb *inp, **inp_list;
5741573Srgrimes	inp_gen_t gencnt;
5751573Srgrimes	struct xinpgen xig;
5761573Srgrimes
5771573Srgrimes	/*
5781573Srgrimes	 * The process of preparing the TCB list is too time-consuming and
5791573Srgrimes	 * resource-intensive to repeat twice on every request.
5801573Srgrimes	 */
5811573Srgrimes	if (req->oldptr == 0) {
5821573Srgrimes		n = ripcbinfo.ipi_count;
5831573Srgrimes		req->oldidx = 2 * (sizeof xig)
5841573Srgrimes			+ (n + n/8) * sizeof(struct xinpcb);
5851573Srgrimes		return 0;
5861573Srgrimes	}
5871573Srgrimes
5881573Srgrimes	if (req->newptr != 0)
5891573Srgrimes		return EPERM;
5901573Srgrimes
5911573Srgrimes	/*
5921573Srgrimes	 * OK, now we're committed to doing something.
5931573Srgrimes	 */
5941573Srgrimes	s = splnet();
5951573Srgrimes	gencnt = ripcbinfo.ipi_gencnt;
5961573Srgrimes	n = ripcbinfo.ipi_count;
5971573Srgrimes	splx(s);
5981573Srgrimes
5991573Srgrimes	xig.xig_len = sizeof xig;
6001573Srgrimes	xig.xig_count = n;
6011573Srgrimes	xig.xig_gen = gencnt;
6021573Srgrimes	xig.xig_sogen = so_gencnt;
6031573Srgrimes	error = SYSCTL_OUT(req, &xig, sizeof xig);
6041573Srgrimes	if (error)
6051573Srgrimes		return error;
6061573Srgrimes
6071573Srgrimes	inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
6081573Srgrimes	if (inp_list == 0)
6091573Srgrimes		return ENOMEM;
6101573Srgrimes
6111573Srgrimes	s = splnet();
6121573Srgrimes	for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
6131573Srgrimes	     inp = inp->inp_list.le_next) {
6141573Srgrimes		if (inp->inp_gencnt <= gencnt)
6151573Srgrimes			inp_list[i++] = inp;
6161573Srgrimes	}
6171573Srgrimes	splx(s);
6181573Srgrimes	n = i;
6191573Srgrimes
6201573Srgrimes	error = 0;
6211573Srgrimes	for (i = 0; i < n; i++) {
6221573Srgrimes		inp = inp_list[i];
6231573Srgrimes		if (inp->inp_gencnt <= gencnt) {
6241573Srgrimes			struct xinpcb xi;
6251573Srgrimes			xi.xi_len = sizeof xi;
6261573Srgrimes			/* XXX should avoid extra copy */
6271573Srgrimes			bcopy(inp, &xi.xi_inp, sizeof *inp);
6281573Srgrimes			if (inp->inp_socket)
6291573Srgrimes				sotoxsocket(inp->inp_socket, &xi.xi_socket);
6301573Srgrimes			error = SYSCTL_OUT(req, &xi, sizeof xi);
6311573Srgrimes		}
6321573Srgrimes	}
6331573Srgrimes	if (!error) {
6341573Srgrimes		/*
6351573Srgrimes		 * Give the user an updated idea of our state.
6361573Srgrimes		 * If the generation differs from what we told
6371573Srgrimes		 * her before, she knows that something happened
6381573Srgrimes		 * while we were processing this request, and it
6391573Srgrimes		 * might be necessary to retry.
6401573Srgrimes		 */
6411573Srgrimes		s = splnet();
6421573Srgrimes		xig.xig_gen = ripcbinfo.ipi_gencnt;
6431573Srgrimes		xig.xig_sogen = so_gencnt;
6441573Srgrimes		xig.xig_count = ripcbinfo.ipi_count;
6451573Srgrimes		splx(s);
6461573Srgrimes		error = SYSCTL_OUT(req, &xig, sizeof xig);
6471573Srgrimes	}
6481573Srgrimes	free(inp_list, M_TEMP);
6491573Srgrimes	return error;
6501573Srgrimes}
6511573Srgrimes
6521573SrgrimesSYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
6531573Srgrimes	    rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
6541573Srgrimes
6551573Srgrimesstruct pr_usrreqs rip_usrreqs = {
6561573Srgrimes	rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
6571573Srgrimes	pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
6581573Srgrimes	pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
6591573Srgrimes	pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
6601573Srgrimes	in_setsockaddr, sosend, soreceive, sopoll
6611573Srgrimes};
6621573Srgrimes