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