raw_ip.c revision 65837
11541Srgrimes/*
222521Sdyson * Copyright (c) 1982, 1986, 1988, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
3322521Sdyson *	@(#)raw_ip.c	8.7 (Berkeley) 5/15/95
3430434Sphk * $FreeBSD: head/sys/netinet/raw_ip.c 65837 2000-09-14 14:42:04Z ru $
351541Srgrimes */
361541Srgrimes
371541Srgrimes#include "opt_inet6.h"
3822521Sdyson#include "opt_ipsec.h"
3918020Sbde
4022600Smpp#include <sys/param.h>
4130354Sphk#include <sys/systm.h>
421541Srgrimes#include <sys/kernel.h>
431541Srgrimes#include <sys/malloc.h>
441541Srgrimes#include <sys/mbuf.h>
4524205Sbde#include <sys/proc.h>
4624131Sbde#include <sys/protosw.h>
471541Srgrimes#include <sys/socket.h>
4829362Speter#include <sys/socketvar.h>
497090Sbde#include <sys/sysctl.h>
501541Srgrimes
511541Srgrimes#include <vm/vm_zone.h>
521541Srgrimes
531541Srgrimes#include <net/if.h>
541541Srgrimes#include <net/route.h>
551541Srgrimes
561541Srgrimes#define _IP_VHL
571541Srgrimes#include <netinet/in.h>
581541Srgrimes#include <netinet/in_systm.h>
591541Srgrimes#include <netinet/ip.h>
601541Srgrimes#include <netinet/in_pcb.h>
611541Srgrimes#include <netinet/in_var.h>
621541Srgrimes#include <netinet/ip_var.h>
6312820Sphk#include <netinet/ip_mroute.h>
6412820Sphk
6512820Sphk#include <netinet/ip_fw.h>
6612158Sbde
6712820Sphk#ifdef IPSEC
6830431Sphk#include <netinet6/ipsec.h>
6930431Sphk#endif /*IPSEC*/
7030431Sphk
7130431Sphk#include "opt_ipdn.h"
7230434Sphk#ifdef DUMMYNET
7330431Sphk#include <netinet/ip_dummynet.h>
7430431Sphk#endif
7530431Sphk
7630431Sphkstruct	inpcbhead ripcb;
7730431Sphkstruct	inpcbinfo ripcbinfo;
7830431Sphk
7930434Sphk/*
8030431Sphk * Nominal space allocated to a raw ip socket.
8130434Sphk */
8230431Sphk#define	RIPSNDQ		8192
8330431Sphk#define	RIPRCVQ		8192
8430431Sphk
8530431Sphk/*
8630431Sphk * Raw interface to IP protocol.
8730431Sphk */
8830431Sphk
8930431Sphk/*
9030434Sphk * Initialize raw connection block q.
9130431Sphk */
9230431Sphkvoid
9330431Sphkrip_init()
9430431Sphk{
9530434Sphk	LIST_INIT(&ripcb);
9630431Sphk	ripcbinfo.listhead = &ripcb;
9730431Sphk	/*
9830431Sphk	 * XXX We don't use the hash list for raw IP, but it's easier
9930431Sphk	 * to allocate a one entry hash list than it is to check all
10030431Sphk	 * over the place for hashbase == NULL.
10130431Sphk	 */
10230431Sphk	ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
10330434Sphk	ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask);
10430431Sphk	ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb),
10530434Sphk				   maxsockets, ZONE_INTERRUPT, 0);
10630431Sphk}
10730431Sphk
10830431Sphkstatic struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
10930431Sphk/*
11030431Sphk * Setup generic address and protocol structures
11112158Sbde * for raw_input routine, then pass them along with
1121541Srgrimes * mbuf chain.
11312820Sphk */
1141541Srgrimesvoid
1151541Srgrimesrip_input(m, off, proto)
1162946Swollman	struct mbuf *m;
1172946Swollman	int off, proto;
1181541Srgrimes{
1191541Srgrimes	register struct ip *ip = mtod(m, struct ip *);
1201541Srgrimes	register struct inpcb *inp;
1211541Srgrimes	struct inpcb *last = 0;
1221549Srgrimes	struct mbuf *opts = 0;
1231541Srgrimes
1241541Srgrimes	ripsrc.sin_addr = ip->ip_src;
1251541Srgrimes	LIST_FOREACH(inp, &ripcb, inp_list) {
1261541Srgrimes#ifdef INET6
1271541Srgrimes		if ((inp->inp_vflag & INP_IPV4) == 0)
1281541Srgrimes			continue;
1291541Srgrimes#endif
1308876Srgrimes		if (inp->inp_ip_p && inp->inp_ip_p != proto)
1311541Srgrimes			continue;
1321541Srgrimes		if (inp->inp_laddr.s_addr &&
1331541Srgrimes                  inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
1341541Srgrimes			continue;
1351541Srgrimes		if (inp->inp_faddr.s_addr &&
1361541Srgrimes                  inp->inp_faddr.s_addr != ip->ip_src.s_addr)
1371541Srgrimes			continue;
1381541Srgrimes		if (last) {
1391541Srgrimes			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
1401549Srgrimes			if (n) {
1411541Srgrimes				if (last->inp_flags & INP_CONTROLOPTS ||
1421541Srgrimes				    last->inp_socket->so_options & SO_TIMESTAMP)
1431541Srgrimes				    ip_savecontrol(last, &opts, ip, n);
1441541Srgrimes				if (sbappendaddr(&last->inp_socket->so_rcv,
1451541Srgrimes				    (struct sockaddr *)&ripsrc, n,
1461541Srgrimes				    opts) == 0) {
1471541Srgrimes					/* should notify about lost packet */
1481541Srgrimes					m_freem(n);
14922521Sdyson					if (opts)
15022521Sdyson					    m_freem(opts);
15122521Sdyson				} else
1521541Srgrimes					sorwakeup(last->inp_socket);
1531541Srgrimes				opts = 0;
1541541Srgrimes			}
1551541Srgrimes		}
1561541Srgrimes		last = inp;
1571541Srgrimes	}
1581541Srgrimes	if (last) {
15922521Sdyson		if (last->inp_flags & INP_CONTROLOPTS ||
1603311Sphk		    last->inp_socket->so_options & SO_TIMESTAMP)
1611541Srgrimes			ip_savecontrol(last, &opts, ip, m);
1621541Srgrimes		if (sbappendaddr(&last->inp_socket->so_rcv,
1631541Srgrimes		    (struct sockaddr *)&ripsrc, m, opts) == 0) {
1641541Srgrimes			m_freem(m);
1651541Srgrimes			if (opts)
16622521Sdyson			    m_freem(opts);
1673311Sphk		} else
1681541Srgrimes			sorwakeup(last->inp_socket);
1691541Srgrimes	} else {
1701541Srgrimes		m_freem(m);
1711541Srgrimes              ipstat.ips_noproto++;
1721541Srgrimes              ipstat.ips_delivered--;
1731541Srgrimes      }
1748876Srgrimes}
1753311Sphk
1761541Srgrimes/*
1771541Srgrimes * Generate IP header and pass packet to ip_output.
1781541Srgrimes * Tack on options user may have setup with control call.
1791541Srgrimes */
1801541Srgrimesint
1811541Srgrimesrip_output(m, so, dst)
1821541Srgrimes	struct mbuf *m;
1831541Srgrimes	struct socket *so;
1841541Srgrimes	u_long dst;
1851541Srgrimes{
18622521Sdyson	register struct ip *ip;
18722521Sdyson	register struct inpcb *inp = sotoinpcb(so);
18822521Sdyson	int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
1899973Sjkh
1909973Sjkh	/*
1919973Sjkh	 * If the user handed us a complete IP packet, use it.
1929973Sjkh	 * Otherwise, allocate an mbuf for a header and fill it in.
19322521Sdyson	 */
19422521Sdyson	if ((inp->inp_flags & INP_HDRINCL) == 0) {
19522521Sdyson		if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
19622521Sdyson			m_freem(m);
1979973Sjkh			return(EMSGSIZE);
1989973Sjkh		}
1999973Sjkh		M_PREPEND(m, sizeof(struct ip), M_WAIT);
2009973Sjkh		ip = mtod(m, struct ip *);
2019973Sjkh		ip->ip_tos = 0;
20222521Sdyson		ip->ip_off = 0;
20322521Sdyson		ip->ip_p = inp->inp_ip_p;
20422521Sdyson		ip->ip_len = m->m_pkthdr.len;
20522521Sdyson		ip->ip_src = inp->inp_laddr;
20622521Sdyson		ip->ip_dst.s_addr = dst;
20722521Sdyson		ip->ip_ttl = MAXTTL;
20822521Sdyson	} else {
20922521Sdyson		if (m->m_pkthdr.len > IP_MAXPACKET) {
2101541Srgrimes			m_freem(m);
21122521Sdyson			return(EMSGSIZE);
21222521Sdyson		}
21322521Sdyson		ip = mtod(m, struct ip *);
21422521Sdyson		/* don't allow both user specified and setsockopt options,
21522521Sdyson		   and don't allow packet length sizes that will crash */
21622521Sdyson		if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2))
2179973Sjkh		     && inp->inp_options)
2181541Srgrimes		    || (ip->ip_len > m->m_pkthdr.len)
2191541Srgrimes		    || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) {
22022521Sdyson			m_freem(m);
2211541Srgrimes			return EINVAL;
2221541Srgrimes		}
22322521Sdyson		if (ip->ip_id == 0)
2241541Srgrimes			ip->ip_id = htons(ip_id++);
22522521Sdyson		/* XXX prevent ip_output from overwriting header fields */
2261541Srgrimes		flags |= IP_RAWOUTPUT;
2271541Srgrimes		ipstat.ips_rawout++;
2281541Srgrimes	}
22922521Sdyson
23022521Sdyson#ifdef IPSEC
23122521Sdyson	ipsec_setsocket(m, so);
2321541Srgrimes#endif /*IPSEC*/
2331541Srgrimes
2341541Srgrimes	return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
2351541Srgrimes			  inp->inp_moptions));
2361541Srgrimes}
2371541Srgrimes
2381541Srgrimes/*
2391549Srgrimes * Raw IP socket option processing.
2401541Srgrimes */
2411541Srgrimesint
2421541Srgrimesrip_ctloutput(so, sopt)
2431541Srgrimes	struct socket *so;
2441541Srgrimes	struct sockopt *sopt;
2451541Srgrimes{
2461541Srgrimes	struct	inpcb *inp = sotoinpcb(so);
2471541Srgrimes	int	error, optval;
24822521Sdyson
24922521Sdyson	if (sopt->sopt_level != IPPROTO_IP)
25022521Sdyson		return (EINVAL);
2511541Srgrimes
2521541Srgrimes	error = 0;
2531541Srgrimes
2541541Srgrimes	switch (sopt->sopt_dir) {
2551541Srgrimes	case SOPT_GET:
2561541Srgrimes		switch (sopt->sopt_name) {
2571541Srgrimes		case IP_HDRINCL:
2581541Srgrimes			optval = inp->inp_flags & INP_HDRINCL;
2591541Srgrimes			error = sooptcopyout(sopt, &optval, sizeof optval);
2601541Srgrimes			break;
2611541Srgrimes
26222521Sdyson		case IP_FW_GET:
26328270Swollman			if (ip_fw_ctl_ptr == 0)
26422521Sdyson				error = ENOPROTOOPT;
26522521Sdyson			else
2661541Srgrimes				error = ip_fw_ctl_ptr(sopt);
2671541Srgrimes			break;
2681541Srgrimes
2691541Srgrimes#ifdef DUMMYNET
2701541Srgrimes		case IP_DUMMYNET_GET:
2711541Srgrimes			if (ip_dn_ctl_ptr == NULL)
2721541Srgrimes				error = ENOPROTOOPT ;
2731541Srgrimes			else
2741541Srgrimes				error = ip_dn_ctl_ptr(sopt);
2751541Srgrimes			break ;
2761541Srgrimes#endif /* DUMMYNET */
2771541Srgrimes
2781541Srgrimes		case MRT_INIT:
2791541Srgrimes		case MRT_DONE:
2801549Srgrimes		case MRT_ADD_VIF:
2811541Srgrimes		case MRT_DEL_VIF:
2821541Srgrimes		case MRT_ADD_MFC:
2831541Srgrimes		case MRT_DEL_MFC:
2841541Srgrimes		case MRT_VERSION:
2851541Srgrimes		case MRT_ASSERT:
2861541Srgrimes			error = ip_mrouter_get(so, sopt);
2871541Srgrimes			break;
2881541Srgrimes
2891541Srgrimes		default:
29022521Sdyson			error = ip_ctloutput(so, sopt);
2911541Srgrimes			break;
2921541Srgrimes		}
2931541Srgrimes		break;
2941541Srgrimes
2951541Srgrimes	case SOPT_SET:
2961541Srgrimes		switch (sopt->sopt_name) {
2971541Srgrimes		case IP_HDRINCL:
2981541Srgrimes			error = sooptcopyin(sopt, &optval, sizeof optval,
29922521Sdyson					    sizeof optval);
30028270Swollman			if (error)
30128270Swollman				break;
30222521Sdyson			if (optval)
3031541Srgrimes				inp->inp_flags |= INP_HDRINCL;
3041541Srgrimes			else
3051541Srgrimes				inp->inp_flags &= ~INP_HDRINCL;
3061541Srgrimes			break;
3071541Srgrimes
3081541Srgrimes		case IP_FW_ADD:
3091541Srgrimes		case IP_FW_DEL:
3101541Srgrimes		case IP_FW_FLUSH:
3111541Srgrimes		case IP_FW_ZERO:
3121549Srgrimes		case IP_FW_RESETLOG:
3131541Srgrimes			if (ip_fw_ctl_ptr == 0)
3141541Srgrimes				error = ENOPROTOOPT;
3151541Srgrimes			else
3161541Srgrimes				error = ip_fw_ctl_ptr(sopt);
3171541Srgrimes			break;
3181541Srgrimes
3191541Srgrimes#ifdef DUMMYNET
3201541Srgrimes		case IP_DUMMYNET_CONFIGURE:
3211541Srgrimes		case IP_DUMMYNET_DEL:
3221541Srgrimes		case IP_DUMMYNET_FLUSH:
3231541Srgrimes			if (ip_dn_ctl_ptr == NULL)
32422521Sdyson				error = ENOPROTOOPT ;
3251541Srgrimes			else
3261541Srgrimes				error = ip_dn_ctl_ptr(sopt);
3271541Srgrimes			break ;
32822521Sdyson#endif
3291541Srgrimes
33022521Sdyson		case IP_RSVP_ON:
33122521Sdyson			error = ip_rsvp_init(so);
33222521Sdyson			break;
33322521Sdyson
33422521Sdyson		case IP_RSVP_OFF:
3351541Srgrimes			error = ip_rsvp_done();
33622521Sdyson			break;
33722521Sdyson
33822521Sdyson			/* XXX - should be combined */
33922521Sdyson		case IP_RSVP_VIF_ON:
34022521Sdyson			error = ip_rsvp_vif_init(so, sopt);
3411541Srgrimes			break;
3421541Srgrimes
3431541Srgrimes		case IP_RSVP_VIF_OFF:
3441549Srgrimes			error = ip_rsvp_vif_done(so, sopt);
34529362Speter			break;
34629362Speter
3471541Srgrimes		case MRT_INIT:
34829362Speter		case MRT_DONE:
3491541Srgrimes		case MRT_ADD_VIF:
3501541Srgrimes		case MRT_DEL_VIF:
3511541Srgrimes		case MRT_ADD_MFC:
3521541Srgrimes		case MRT_DEL_MFC:
3531541Srgrimes		case MRT_VERSION:
35429362Speter		case MRT_ASSERT:
3551541Srgrimes			error = ip_mrouter_set(so, sopt);
35629362Speter			break;
3571541Srgrimes
35829362Speter		default:
35929362Speter			error = ip_ctloutput(so, sopt);
36029362Speter			break;
36122521Sdyson		}
36229362Speter		break;
3631541Srgrimes	}
36429362Speter
36529362Speter	return (error);
36629362Speter}
36722521Sdyson
36829362Speter/*
3691541Srgrimes * This function exists solely to receive the PRC_IFDOWN messages which
3701541Srgrimes * are sent by if_down().  It looks for an ifaddr whose ifa_addr is sa,
37122521Sdyson * and calls in_ifadown() to remove all routes corresponding to that address.
37222521Sdyson * It also receives the PRC_IFUP messages from if_up() and reinstalls the
37322521Sdyson * interface routes.
37422521Sdyson */
37522521Sdysonvoid
37622521Sdysonrip_ctlinput(cmd, sa, vip)
37722521Sdyson	int cmd;
37822521Sdyson	struct sockaddr *sa;
37922521Sdyson	void *vip;
38022521Sdyson{
38122521Sdyson	struct in_ifaddr *ia;
38222521Sdyson	struct ifnet *ifp;
3831541Srgrimes	int err;
3841541Srgrimes	int flags;
3851541Srgrimes
3861549Srgrimes	switch (cmd) {
3871541Srgrimes	case PRC_IFDOWN:
3881541Srgrimes		for (ia = in_ifaddrhead.tqh_first; ia;
3891541Srgrimes		     ia = ia->ia_link.tqe_next) {
3901541Srgrimes			if (ia->ia_ifa.ifa_addr == sa
3911541Srgrimes			    && (ia->ia_flags & IFA_ROUTE)) {
3921541Srgrimes				/*
39310551Sdyson				 * in_ifscrub kills the interface route.
39410551Sdyson				 */
3951541Srgrimes				in_ifscrub(ia->ia_ifp, ia);
3961541Srgrimes				/*
3971541Srgrimes				 * in_ifadown gets rid of all the rest of
3981541Srgrimes				 * the routes.  This is not quite the right
3991541Srgrimes				 * thing to do, but at least if we are running
4001541Srgrimes				 * a routing process they will come back.
4011541Srgrimes				 */
4026151Sdg				in_ifadown(&ia->ia_ifa);
4036151Sdg				break;
40410551Sdyson			}
40510551Sdyson		}
4061541Srgrimes		break;
4071541Srgrimes
4081541Srgrimes	case PRC_IFUP:
4091541Srgrimes		for (ia = in_ifaddrhead.tqh_first; ia;
4101541Srgrimes		     ia = ia->ia_link.tqe_next) {
4111541Srgrimes			if (ia->ia_ifa.ifa_addr == sa)
4121541Srgrimes				break;
4131549Srgrimes		}
4141541Srgrimes		if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
4151541Srgrimes			return;
4161541Srgrimes		flags = RTF_UP;
4171541Srgrimes		ifp = ia->ia_ifa.ifa_ifp;
4181541Srgrimes
4191541Srgrimes		if ((ifp->if_flags & IFF_LOOPBACK)
4201541Srgrimes		    || (ifp->if_flags & IFF_POINTOPOINT))
4211541Srgrimes			flags |= RTF_HOST;
4221541Srgrimes
4231541Srgrimes		err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
4241541Srgrimes		if (err == 0)
4251541Srgrimes			ia->ia_flags |= IFA_ROUTE;
42622521Sdyson		break;
42722521Sdyson	}
42822521Sdyson}
42922521Sdyson
43022521Sdysonu_long	rip_sendspace = RIPSNDQ;
4311541Srgrimesu_long	rip_recvspace = RIPRCVQ;
4321541Srgrimes
4331541SrgrimesSYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
4341541Srgrimes    &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
4359973SjkhSYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
4361541Srgrimes    &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
4371541Srgrimes
4381541Srgrimesstatic int
4391541Srgrimesrip_attach(struct socket *so, int proto, struct proc *p)
4401541Srgrimes{
4411541Srgrimes	struct inpcb *inp;
4421541Srgrimes	int error, s;
4431541Srgrimes
4441541Srgrimes	inp = sotoinpcb(so);
4451541Srgrimes	if (inp)
4461541Srgrimes		panic("rip_attach");
4473311Sphk	if (p && (error = suser(p)) != 0)
4481541Srgrimes		return error;
4493311Sphk
4503311Sphk	error = soreserve(so, rip_sendspace, rip_recvspace);
4513311Sphk	if (error)
4523311Sphk		return error;
4533311Sphk	s = splnet();
4543311Sphk	error = in_pcballoc(so, &ripcbinfo, p);
4553311Sphk	splx(s);
4563311Sphk	if (error)
4573311Sphk		return error;
4583311Sphk	inp = (struct inpcb *)so->so_pcb;
4593311Sphk	inp->inp_vflag |= INP_IPV4;
4603311Sphk	inp->inp_ip_p = proto;
4613311Sphk#ifdef IPSEC
4623311Sphk	error = ipsec_init_policy(so, &inp->inp_sp);
4631541Srgrimes	if (error != 0) {
4641541Srgrimes		in_pcbdetach(inp);
46512820Sphk		return error;
4661541Srgrimes	}
4671541Srgrimes#endif /*IPSEC*/
4681541Srgrimes	return 0;
4691541Srgrimes}
4701541Srgrimes
4711541Srgrimesstatic int
4721541Srgrimesrip_detach(struct socket *so)
4731541Srgrimes{
4741541Srgrimes	struct inpcb *inp;
4751549Srgrimes
4761541Srgrimes	inp = sotoinpcb(so);
4771541Srgrimes	if (inp == 0)
4781541Srgrimes		panic("rip_detach");
4791541Srgrimes	if (so == ip_mrouter)
4801541Srgrimes		ip_mrouter_done();
4811549Srgrimes	ip_rsvp_force_done(so);
4821541Srgrimes	if (so == ip_rsvpd)
4831541Srgrimes		ip_rsvp_done();
4841541Srgrimes	in_pcbdetach(inp);
4851541Srgrimes	return 0;
4861541Srgrimes}
4871541Srgrimes
4881541Srgrimesstatic int
4891541Srgrimesrip_abort(struct socket *so)
4901541Srgrimes{
4911541Srgrimes	soisdisconnected(so);
4921541Srgrimes	return rip_detach(so);
4931541Srgrimes}
4941541Srgrimes
4951541Srgrimesstatic int
4961541Srgrimesrip_disconnect(struct socket *so)
4971541Srgrimes{
4981541Srgrimes	if ((so->so_state & SS_ISCONNECTED) == 0)
4991541Srgrimes		return ENOTCONN;
5001541Srgrimes	return rip_abort(so);
5011541Srgrimes}
5021541Srgrimes
5031541Srgrimesstatic int
5041541Srgrimesrip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
5051541Srgrimes{
5061541Srgrimes	struct inpcb *inp = sotoinpcb(so);
5071541Srgrimes	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
5081541Srgrimes
50912820Sphk	if (nam->sa_len != sizeof(*addr))
5101541Srgrimes		return EINVAL;
5111541Srgrimes
5121541Srgrimes	if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) &&
5131541Srgrimes				    (addr->sin_family != AF_IMPLINK)) ||
5141541Srgrimes	    (addr->sin_addr.s_addr &&
5151541Srgrimes	     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
5161541Srgrimes		return EADDRNOTAVAIL;
5171541Srgrimes	inp->inp_laddr = addr->sin_addr;
5181541Srgrimes	return 0;
5191541Srgrimes}
5201549Srgrimes
5211541Srgrimesstatic int
5221541Srgrimesrip_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
5231541Srgrimes{
5241541Srgrimes	struct inpcb *inp = sotoinpcb(so);
5251541Srgrimes	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
5261541Srgrimes
5271541Srgrimes	if (nam->sa_len != sizeof(*addr))
5281541Srgrimes		return EINVAL;
5291541Srgrimes	if (TAILQ_EMPTY(&ifnet))
5301541Srgrimes		return EADDRNOTAVAIL;
53120687Sbde	if ((addr->sin_family != AF_INET) &&
5321541Srgrimes	    (addr->sin_family != AF_IMPLINK))
5331541Srgrimes		return EAFNOSUPPORT;
5341541Srgrimes	inp->inp_faddr = addr->sin_addr;
5351541Srgrimes	soisconnected(so);
5361541Srgrimes	return 0;
5371549Srgrimes}
5381541Srgrimes
5391541Srgrimesstatic int
5401541Srgrimesrip_shutdown(struct socket *so)
5411541Srgrimes{
5421541Srgrimes	socantsendmore(so);
5431541Srgrimes	return 0;
544}
545
546static int
547rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
548	 struct mbuf *control, struct proc *p)
549{
550	struct inpcb *inp = sotoinpcb(so);
551	register u_long dst;
552
553	if (so->so_state & SS_ISCONNECTED) {
554		if (nam) {
555			m_freem(m);
556			return EISCONN;
557		}
558		dst = inp->inp_faddr.s_addr;
559	} else {
560		if (nam == NULL) {
561			m_freem(m);
562			return ENOTCONN;
563		}
564		dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
565	}
566	return rip_output(m, so, dst);
567}
568
569static int
570rip_pcblist(SYSCTL_HANDLER_ARGS)
571{
572	int error, i, n, s;
573	struct inpcb *inp, **inp_list;
574	inp_gen_t gencnt;
575	struct xinpgen xig;
576
577	/*
578	 * The process of preparing the TCB list is too time-consuming and
579	 * resource-intensive to repeat twice on every request.
580	 */
581	if (req->oldptr == 0) {
582		n = ripcbinfo.ipi_count;
583		req->oldidx = 2 * (sizeof xig)
584			+ (n + n/8) * sizeof(struct xinpcb);
585		return 0;
586	}
587
588	if (req->newptr != 0)
589		return EPERM;
590
591	/*
592	 * OK, now we're committed to doing something.
593	 */
594	s = splnet();
595	gencnt = ripcbinfo.ipi_gencnt;
596	n = ripcbinfo.ipi_count;
597	splx(s);
598
599	xig.xig_len = sizeof xig;
600	xig.xig_count = n;
601	xig.xig_gen = gencnt;
602	xig.xig_sogen = so_gencnt;
603	error = SYSCTL_OUT(req, &xig, sizeof xig);
604	if (error)
605		return error;
606
607	inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
608	if (inp_list == 0)
609		return ENOMEM;
610
611	s = splnet();
612	for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n;
613	     inp = inp->inp_list.le_next) {
614		if (inp->inp_gencnt <= gencnt)
615			inp_list[i++] = inp;
616	}
617	splx(s);
618	n = i;
619
620	error = 0;
621	for (i = 0; i < n; i++) {
622		inp = inp_list[i];
623		if (inp->inp_gencnt <= gencnt) {
624			struct xinpcb xi;
625			xi.xi_len = sizeof xi;
626			/* XXX should avoid extra copy */
627			bcopy(inp, &xi.xi_inp, sizeof *inp);
628			if (inp->inp_socket)
629				sotoxsocket(inp->inp_socket, &xi.xi_socket);
630			error = SYSCTL_OUT(req, &xi, sizeof xi);
631		}
632	}
633	if (!error) {
634		/*
635		 * Give the user an updated idea of our state.
636		 * If the generation differs from what we told
637		 * her before, she knows that something happened
638		 * while we were processing this request, and it
639		 * might be necessary to retry.
640		 */
641		s = splnet();
642		xig.xig_gen = ripcbinfo.ipi_gencnt;
643		xig.xig_sogen = so_gencnt;
644		xig.xig_count = ripcbinfo.ipi_count;
645		splx(s);
646		error = SYSCTL_OUT(req, &xig, sizeof xig);
647	}
648	free(inp_list, M_TEMP);
649	return error;
650}
651
652SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0,
653	    rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
654
655struct pr_usrreqs rip_usrreqs = {
656	rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect,
657	pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
658	pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
659	pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown,
660	in_setsockaddr, sosend, soreceive, sopoll
661};
662