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