1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 3325f26ad8SGarrett Wollman * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 376a800098SYoshinobu Inoue #include "opt_inet6.h" 386a800098SYoshinobu Inoue #include "opt_ipsec.h" 396a800098SYoshinobu Inoue 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41117bcae7SGarrett Wollman #include <sys/systm.h> 42117bcae7SGarrett Wollman #include <sys/kernel.h> 43df8bae1dSRodney W. Grimes #include <sys/malloc.h> 44df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 45a29f300eSGarrett Wollman #include <sys/proc.h> 46df8bae1dSRodney W. Grimes #include <sys/protosw.h> 47117bcae7SGarrett Wollman #include <sys/socket.h> 48df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 49117bcae7SGarrett Wollman #include <sys/sysctl.h> 508781d8e9SBruce Evans 513d4d47f3SGarrett Wollman #include <vm/vm_zone.h> 52df8bae1dSRodney W. Grimes 53df8bae1dSRodney W. Grimes #include <net/if.h> 54df8bae1dSRodney W. Grimes #include <net/route.h> 55df8bae1dSRodney W. Grimes 565e2d0696SGarrett Wollman #define _IP_VHL 57df8bae1dSRodney W. Grimes #include <netinet/in.h> 58df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 59df8bae1dSRodney W. Grimes #include <netinet/ip.h> 60c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h> 61c1f8a6ceSDavid Greenman #include <netinet/in_var.h> 62df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 63df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h> 64df8bae1dSRodney W. Grimes 65100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h> 66100ba1a6SJordan K. Hubbard 676a800098SYoshinobu Inoue #ifdef IPSEC 686a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 696a800098SYoshinobu Inoue #endif /*IPSEC*/ 706a800098SYoshinobu Inoue 71b715f178SLuigi Rizzo #include "opt_ipdn.h" 72b715f178SLuigi Rizzo #ifdef DUMMYNET 73b715f178SLuigi Rizzo #include <netinet/ip_dummynet.h> 74b715f178SLuigi Rizzo #endif 75f9493383SGarrett Wollman 7682cd038dSYoshinobu Inoue struct inpcbhead ripcb; 7782cd038dSYoshinobu Inoue struct inpcbinfo ripcbinfo; 78df8bae1dSRodney W. Grimes 79df8bae1dSRodney W. Grimes /* 80df8bae1dSRodney W. Grimes * Nominal space allocated to a raw ip socket. 81df8bae1dSRodney W. Grimes */ 82df8bae1dSRodney W. Grimes #define RIPSNDQ 8192 83df8bae1dSRodney W. Grimes #define RIPRCVQ 8192 84df8bae1dSRodney W. Grimes 85df8bae1dSRodney W. Grimes /* 86df8bae1dSRodney W. Grimes * Raw interface to IP protocol. 87df8bae1dSRodney W. Grimes */ 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes /* 90df8bae1dSRodney W. Grimes * Initialize raw connection block q. 91df8bae1dSRodney W. Grimes */ 92df8bae1dSRodney W. Grimes void 93df8bae1dSRodney W. Grimes rip_init() 94df8bae1dSRodney W. Grimes { 9515bd2b43SDavid Greenman LIST_INIT(&ripcb); 9615bd2b43SDavid Greenman ripcbinfo.listhead = &ripcb; 9715bd2b43SDavid Greenman /* 9815bd2b43SDavid Greenman * XXX We don't use the hash list for raw IP, but it's easier 9915bd2b43SDavid Greenman * to allocate a one entry hash list than it is to check all 10015bd2b43SDavid Greenman * over the place for hashbase == NULL. 10115bd2b43SDavid Greenman */ 102ddd79a97SDavid Greenman ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask); 103c3229e05SDavid Greenman ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask); 1043d4d47f3SGarrett Wollman ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb), 10598271db4SGarrett Wollman maxsockets, ZONE_INTERRUPT, 0); 106df8bae1dSRodney W. Grimes } 107df8bae1dSRodney W. Grimes 108f6d24a78SPoul-Henning Kamp static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 109df8bae1dSRodney W. Grimes /* 110df8bae1dSRodney W. Grimes * Setup generic address and protocol structures 111df8bae1dSRodney W. Grimes * for raw_input routine, then pass them along with 112df8bae1dSRodney W. Grimes * mbuf chain. 113df8bae1dSRodney W. Grimes */ 114df8bae1dSRodney W. Grimes void 1156a800098SYoshinobu Inoue rip_input(m, off, proto) 116df8bae1dSRodney W. Grimes struct mbuf *m; 1176a800098SYoshinobu Inoue int off, proto; 118df8bae1dSRodney W. Grimes { 119df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 120df8bae1dSRodney W. Grimes register struct inpcb *inp; 12182c23ebaSBill Fenner struct inpcb *last = 0; 12282c23ebaSBill Fenner struct mbuf *opts = 0; 123df8bae1dSRodney W. Grimes 124df8bae1dSRodney W. Grimes ripsrc.sin_addr = ip->ip_src; 1256a800098SYoshinobu Inoue LIST_FOREACH(inp, &ripcb, inp_list) { 1266a800098SYoshinobu Inoue #ifdef INET6 1276a800098SYoshinobu Inoue if ((inp->inp_vflag & INP_IPV4) == 0) 1286a800098SYoshinobu Inoue continue; 1296a800098SYoshinobu Inoue #endif 1306a800098SYoshinobu Inoue if (inp->inp_ip_p && inp->inp_ip_p != proto) 131df8bae1dSRodney W. Grimes continue; 132df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr && 133d99c7a23SGarrett Wollman inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 134df8bae1dSRodney W. Grimes continue; 135df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr && 136d99c7a23SGarrett Wollman inp->inp_faddr.s_addr != ip->ip_src.s_addr) 137df8bae1dSRodney W. Grimes continue; 138df8bae1dSRodney W. Grimes if (last) { 139623ae52eSPoul-Henning Kamp struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 140623ae52eSPoul-Henning Kamp if (n) { 14182c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS || 14282c23ebaSBill Fenner last->inp_socket->so_options & SO_TIMESTAMP) 14382c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, n); 14482c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 145623ae52eSPoul-Henning Kamp (struct sockaddr *)&ripsrc, n, 14682c23ebaSBill Fenner opts) == 0) { 147df8bae1dSRodney W. Grimes /* should notify about lost packet */ 148df8bae1dSRodney W. Grimes m_freem(n); 14982c23ebaSBill Fenner if (opts) 15082c23ebaSBill Fenner m_freem(opts); 15182c23ebaSBill Fenner } else 15282c23ebaSBill Fenner sorwakeup(last->inp_socket); 15382c23ebaSBill Fenner opts = 0; 154df8bae1dSRodney W. Grimes } 155df8bae1dSRodney W. Grimes } 15682c23ebaSBill Fenner last = inp; 157df8bae1dSRodney W. Grimes } 158df8bae1dSRodney W. Grimes if (last) { 15982c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS || 16082c23ebaSBill Fenner last->inp_socket->so_options & SO_TIMESTAMP) 16182c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, m); 16282c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 16382c23ebaSBill Fenner (struct sockaddr *)&ripsrc, m, opts) == 0) { 164df8bae1dSRodney W. Grimes m_freem(m); 16582c23ebaSBill Fenner if (opts) 16682c23ebaSBill Fenner m_freem(opts); 16782c23ebaSBill Fenner } else 16882c23ebaSBill Fenner sorwakeup(last->inp_socket); 169df8bae1dSRodney W. Grimes } else { 170df8bae1dSRodney W. Grimes m_freem(m); 171df8bae1dSRodney W. Grimes ipstat.ips_noproto++; 172df8bae1dSRodney W. Grimes ipstat.ips_delivered--; 173df8bae1dSRodney W. Grimes } 174df8bae1dSRodney W. Grimes } 175df8bae1dSRodney W. Grimes 176df8bae1dSRodney W. Grimes /* 177df8bae1dSRodney W. Grimes * Generate IP header and pass packet to ip_output. 178df8bae1dSRodney W. Grimes * Tack on options user may have setup with control call. 179df8bae1dSRodney W. Grimes */ 180df8bae1dSRodney W. Grimes int 181df8bae1dSRodney W. Grimes rip_output(m, so, dst) 182d25f3712SBrian Feldman struct mbuf *m; 183df8bae1dSRodney W. Grimes struct socket *so; 184df8bae1dSRodney W. Grimes u_long dst; 185df8bae1dSRodney W. Grimes { 186df8bae1dSRodney W. Grimes register struct ip *ip; 187df8bae1dSRodney W. Grimes register struct inpcb *inp = sotoinpcb(so); 188df8bae1dSRodney W. Grimes int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 189df8bae1dSRodney W. Grimes 190df8bae1dSRodney W. Grimes /* 191df8bae1dSRodney W. Grimes * If the user handed us a complete IP packet, use it. 192df8bae1dSRodney W. Grimes * Otherwise, allocate an mbuf for a header and fill it in. 193df8bae1dSRodney W. Grimes */ 194df8bae1dSRodney W. Grimes if ((inp->inp_flags & INP_HDRINCL) == 0) { 195430d30d8SBill Fenner if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { 196430d30d8SBill Fenner m_freem(m); 197430d30d8SBill Fenner return(EMSGSIZE); 198430d30d8SBill Fenner } 199df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof(struct ip), M_WAIT); 200df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 201df8bae1dSRodney W. Grimes ip->ip_tos = 0; 202df8bae1dSRodney W. Grimes ip->ip_off = 0; 203ca98b82cSDavid Greenman ip->ip_p = inp->inp_ip_p; 204df8bae1dSRodney W. Grimes ip->ip_len = m->m_pkthdr.len; 205df8bae1dSRodney W. Grimes ip->ip_src = inp->inp_laddr; 206df8bae1dSRodney W. Grimes ip->ip_dst.s_addr = dst; 207df8bae1dSRodney W. Grimes ip->ip_ttl = MAXTTL; 208df8bae1dSRodney W. Grimes } else { 209430d30d8SBill Fenner if (m->m_pkthdr.len > IP_MAXPACKET) { 210430d30d8SBill Fenner m_freem(m); 211430d30d8SBill Fenner return(EMSGSIZE); 212430d30d8SBill Fenner } 213df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 214072b9b24SPaul Traina /* don't allow both user specified and setsockopt options, 215072b9b24SPaul Traina and don't allow packet length sizes that will crash */ 2165e2d0696SGarrett Wollman if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) 2175e2d0696SGarrett Wollman && inp->inp_options) 21891108995SBill Fenner || (ip->ip_len > m->m_pkthdr.len) 21991108995SBill Fenner || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) { 220072b9b24SPaul Traina m_freem(m); 221072b9b24SPaul Traina return EINVAL; 222072b9b24SPaul Traina } 223df8bae1dSRodney W. Grimes if (ip->ip_id == 0) 224df8bae1dSRodney W. Grimes ip->ip_id = htons(ip_id++); 225df8bae1dSRodney W. Grimes /* XXX prevent ip_output from overwriting header fields */ 226df8bae1dSRodney W. Grimes flags |= IP_RAWOUTPUT; 227df8bae1dSRodney W. Grimes ipstat.ips_rawout++; 228df8bae1dSRodney W. Grimes } 2296a800098SYoshinobu Inoue 2306a800098SYoshinobu Inoue #ifdef IPSEC 2316a800098SYoshinobu Inoue m->m_pkthdr.rcvif = (struct ifnet *)so; /*XXX*/ 2326a800098SYoshinobu Inoue #endif /*IPSEC*/ 2336a800098SYoshinobu Inoue 2346a800098SYoshinobu Inoue return (ip_output(m, inp->inp_options, &inp->inp_route, 2356a800098SYoshinobu Inoue flags | IP_SOCKINMRCVIF, 236072b9b24SPaul Traina inp->inp_moptions)); 237df8bae1dSRodney W. Grimes } 238df8bae1dSRodney W. Grimes 239df8bae1dSRodney W. Grimes /* 240df8bae1dSRodney W. Grimes * Raw IP socket option processing. 241df8bae1dSRodney W. Grimes */ 242df8bae1dSRodney W. Grimes int 243cfe8b629SGarrett Wollman rip_ctloutput(so, sopt) 244df8bae1dSRodney W. Grimes struct socket *so; 245cfe8b629SGarrett Wollman struct sockopt *sopt; 246df8bae1dSRodney W. Grimes { 247cfe8b629SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 248cfe8b629SGarrett Wollman int error, optval; 249df8bae1dSRodney W. Grimes 250cfe8b629SGarrett Wollman if (sopt->sopt_level != IPPROTO_IP) 251df8bae1dSRodney W. Grimes return (EINVAL); 252df8bae1dSRodney W. Grimes 25325f26ad8SGarrett Wollman error = 0; 254cfe8b629SGarrett Wollman 255cfe8b629SGarrett Wollman switch (sopt->sopt_dir) { 256cfe8b629SGarrett Wollman case SOPT_GET: 257cfe8b629SGarrett Wollman switch (sopt->sopt_name) { 258cfe8b629SGarrett Wollman case IP_HDRINCL: 259cfe8b629SGarrett Wollman optval = inp->inp_flags & INP_HDRINCL; 260cfe8b629SGarrett Wollman error = sooptcopyout(sopt, &optval, sizeof optval); 261cfe8b629SGarrett Wollman break; 262df8bae1dSRodney W. Grimes 26309bb5f75SPoul-Henning Kamp case IP_FW_GET: 264cfe8b629SGarrett Wollman if (ip_fw_ctl_ptr == 0) 265cfe8b629SGarrett Wollman error = ENOPROTOOPT; 266cfe8b629SGarrett Wollman else 267cfe8b629SGarrett Wollman error = ip_fw_ctl_ptr(sopt); 268cfe8b629SGarrett Wollman break; 2694dd1662bSUgen J.S. Antsilevich 270b715f178SLuigi Rizzo #ifdef DUMMYNET 271b715f178SLuigi Rizzo case IP_DUMMYNET_GET: 272b715f178SLuigi Rizzo if (ip_dn_ctl_ptr == NULL) 273b715f178SLuigi Rizzo error = ENOPROTOOPT ; 274b715f178SLuigi Rizzo else 275b715f178SLuigi Rizzo error = ip_dn_ctl_ptr(sopt); 276b715f178SLuigi Rizzo break ; 277b715f178SLuigi Rizzo #endif /* DUMMYNET */ 2781c5de19aSGarrett Wollman 2791c5de19aSGarrett Wollman case MRT_INIT: 2801c5de19aSGarrett Wollman case MRT_DONE: 2811c5de19aSGarrett Wollman case MRT_ADD_VIF: 2821c5de19aSGarrett Wollman case MRT_DEL_VIF: 2831c5de19aSGarrett Wollman case MRT_ADD_MFC: 2841c5de19aSGarrett Wollman case MRT_DEL_MFC: 2851c5de19aSGarrett Wollman case MRT_VERSION: 2861c5de19aSGarrett Wollman case MRT_ASSERT: 287cfe8b629SGarrett Wollman error = ip_mrouter_get(so, sopt); 288cfe8b629SGarrett Wollman break; 289cfe8b629SGarrett Wollman 290cfe8b629SGarrett Wollman default: 291cfe8b629SGarrett Wollman error = ip_ctloutput(so, sopt); 292cfe8b629SGarrett Wollman break; 293df8bae1dSRodney W. Grimes } 294cfe8b629SGarrett Wollman break; 295cfe8b629SGarrett Wollman 296cfe8b629SGarrett Wollman case SOPT_SET: 297cfe8b629SGarrett Wollman switch (sopt->sopt_name) { 298cfe8b629SGarrett Wollman case IP_HDRINCL: 299cfe8b629SGarrett Wollman error = sooptcopyin(sopt, &optval, sizeof optval, 300cfe8b629SGarrett Wollman sizeof optval); 301cfe8b629SGarrett Wollman if (error) 302cfe8b629SGarrett Wollman break; 303cfe8b629SGarrett Wollman if (optval) 304cfe8b629SGarrett Wollman inp->inp_flags |= INP_HDRINCL; 305cfe8b629SGarrett Wollman else 306cfe8b629SGarrett Wollman inp->inp_flags &= ~INP_HDRINCL; 307cfe8b629SGarrett Wollman break; 308cfe8b629SGarrett Wollman 309cfe8b629SGarrett Wollman case IP_FW_ADD: 310cfe8b629SGarrett Wollman case IP_FW_DEL: 311cfe8b629SGarrett Wollman case IP_FW_FLUSH: 312cfe8b629SGarrett Wollman case IP_FW_ZERO: 3130b6c1a83SBrian Feldman case IP_FW_RESETLOG: 314cfe8b629SGarrett Wollman if (ip_fw_ctl_ptr == 0) 315cfe8b629SGarrett Wollman error = ENOPROTOOPT; 316cfe8b629SGarrett Wollman else 317cfe8b629SGarrett Wollman error = ip_fw_ctl_ptr(sopt); 318cfe8b629SGarrett Wollman break; 319cfe8b629SGarrett Wollman 320b715f178SLuigi Rizzo #ifdef DUMMYNET 321b715f178SLuigi Rizzo case IP_DUMMYNET_CONFIGURE: 322b715f178SLuigi Rizzo case IP_DUMMYNET_DEL: 323b715f178SLuigi Rizzo case IP_DUMMYNET_FLUSH: 324b715f178SLuigi Rizzo if (ip_dn_ctl_ptr == NULL) 325b715f178SLuigi Rizzo error = ENOPROTOOPT ; 326b715f178SLuigi Rizzo else 327b715f178SLuigi Rizzo error = ip_dn_ctl_ptr(sopt); 328b715f178SLuigi Rizzo break ; 329b715f178SLuigi Rizzo #endif 330cfe8b629SGarrett Wollman 331cfe8b629SGarrett Wollman case IP_RSVP_ON: 332cfe8b629SGarrett Wollman error = ip_rsvp_init(so); 333cfe8b629SGarrett Wollman break; 334cfe8b629SGarrett Wollman 335cfe8b629SGarrett Wollman case IP_RSVP_OFF: 336cfe8b629SGarrett Wollman error = ip_rsvp_done(); 337cfe8b629SGarrett Wollman break; 338cfe8b629SGarrett Wollman 339cfe8b629SGarrett Wollman /* XXX - should be combined */ 340cfe8b629SGarrett Wollman case IP_RSVP_VIF_ON: 341cfe8b629SGarrett Wollman error = ip_rsvp_vif_init(so, sopt); 342cfe8b629SGarrett Wollman break; 343cfe8b629SGarrett Wollman 344cfe8b629SGarrett Wollman case IP_RSVP_VIF_OFF: 345cfe8b629SGarrett Wollman error = ip_rsvp_vif_done(so, sopt); 346cfe8b629SGarrett Wollman break; 347cfe8b629SGarrett Wollman 348cfe8b629SGarrett Wollman case MRT_INIT: 349cfe8b629SGarrett Wollman case MRT_DONE: 350cfe8b629SGarrett Wollman case MRT_ADD_VIF: 351cfe8b629SGarrett Wollman case MRT_DEL_VIF: 352cfe8b629SGarrett Wollman case MRT_ADD_MFC: 353cfe8b629SGarrett Wollman case MRT_DEL_MFC: 354cfe8b629SGarrett Wollman case MRT_VERSION: 355cfe8b629SGarrett Wollman case MRT_ASSERT: 356cfe8b629SGarrett Wollman error = ip_mrouter_set(so, sopt); 357cfe8b629SGarrett Wollman break; 358cfe8b629SGarrett Wollman 359cfe8b629SGarrett Wollman default: 360cfe8b629SGarrett Wollman error = ip_ctloutput(so, sopt); 361cfe8b629SGarrett Wollman break; 362cfe8b629SGarrett Wollman } 363cfe8b629SGarrett Wollman break; 364cfe8b629SGarrett Wollman } 365cfe8b629SGarrett Wollman 366cfe8b629SGarrett Wollman return (error); 367df8bae1dSRodney W. Grimes } 368df8bae1dSRodney W. Grimes 36939191c8eSGarrett Wollman /* 37039191c8eSGarrett Wollman * This function exists solely to receive the PRC_IFDOWN messages which 37139191c8eSGarrett Wollman * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa, 37239191c8eSGarrett Wollman * and calls in_ifadown() to remove all routes corresponding to that address. 37339191c8eSGarrett Wollman * It also receives the PRC_IFUP messages from if_up() and reinstalls the 37439191c8eSGarrett Wollman * interface routes. 37539191c8eSGarrett Wollman */ 37639191c8eSGarrett Wollman void 37739191c8eSGarrett Wollman rip_ctlinput(cmd, sa, vip) 37839191c8eSGarrett Wollman int cmd; 37939191c8eSGarrett Wollman struct sockaddr *sa; 38039191c8eSGarrett Wollman void *vip; 38139191c8eSGarrett Wollman { 38239191c8eSGarrett Wollman struct in_ifaddr *ia; 38339191c8eSGarrett Wollman struct ifnet *ifp; 38439191c8eSGarrett Wollman int err; 38539191c8eSGarrett Wollman int flags; 38639191c8eSGarrett Wollman 38739191c8eSGarrett Wollman switch (cmd) { 38839191c8eSGarrett Wollman case PRC_IFDOWN: 38939191c8eSGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 39039191c8eSGarrett Wollman ia = ia->ia_link.tqe_next) { 39139191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa 39239191c8eSGarrett Wollman && (ia->ia_flags & IFA_ROUTE)) { 39339191c8eSGarrett Wollman /* 39439191c8eSGarrett Wollman * in_ifscrub kills the interface route. 39539191c8eSGarrett Wollman */ 39639191c8eSGarrett Wollman in_ifscrub(ia->ia_ifp, ia); 39739191c8eSGarrett Wollman /* 39839191c8eSGarrett Wollman * in_ifadown gets rid of all the rest of 39939191c8eSGarrett Wollman * the routes. This is not quite the right 40039191c8eSGarrett Wollman * thing to do, but at least if we are running 40139191c8eSGarrett Wollman * a routing process they will come back. 40239191c8eSGarrett Wollman */ 40339191c8eSGarrett Wollman in_ifadown(&ia->ia_ifa); 40439191c8eSGarrett Wollman break; 40539191c8eSGarrett Wollman } 40639191c8eSGarrett Wollman } 40739191c8eSGarrett Wollman break; 40839191c8eSGarrett Wollman 40939191c8eSGarrett Wollman case PRC_IFUP: 41039191c8eSGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 41139191c8eSGarrett Wollman ia = ia->ia_link.tqe_next) { 41239191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa) 41339191c8eSGarrett Wollman break; 41439191c8eSGarrett Wollman } 41539191c8eSGarrett Wollman if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) 41639191c8eSGarrett Wollman return; 41739191c8eSGarrett Wollman flags = RTF_UP; 41839191c8eSGarrett Wollman ifp = ia->ia_ifa.ifa_ifp; 41939191c8eSGarrett Wollman 42039191c8eSGarrett Wollman if ((ifp->if_flags & IFF_LOOPBACK) 42139191c8eSGarrett Wollman || (ifp->if_flags & IFF_POINTOPOINT)) 42239191c8eSGarrett Wollman flags |= RTF_HOST; 42339191c8eSGarrett Wollman 42439191c8eSGarrett Wollman err = rtinit(&ia->ia_ifa, RTM_ADD, flags); 42539191c8eSGarrett Wollman if (err == 0) 42639191c8eSGarrett Wollman ia->ia_flags |= IFA_ROUTE; 42739191c8eSGarrett Wollman break; 42839191c8eSGarrett Wollman } 42939191c8eSGarrett Wollman } 43039191c8eSGarrett Wollman 43182cd038dSYoshinobu Inoue u_long rip_sendspace = RIPSNDQ; 43282cd038dSYoshinobu Inoue u_long rip_recvspace = RIPRCVQ; 433df8bae1dSRodney W. Grimes 4343d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, 4353d177f46SBill Fumerola &rip_sendspace, 0, "Maximum outgoing raw IP datagram size"); 4363d177f46SBill Fumerola SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, 4373d177f46SBill Fumerola &rip_recvspace, 0, "Maximum incoming raw IP datagram size"); 438117bcae7SGarrett Wollman 439117bcae7SGarrett Wollman static int 440a29f300eSGarrett Wollman rip_attach(struct socket *so, int proto, struct proc *p) 441df8bae1dSRodney W. Grimes { 442117bcae7SGarrett Wollman struct inpcb *inp; 44386b3ebceSDavid Greenman int error, s; 444c1f8a6ceSDavid Greenman 445117bcae7SGarrett Wollman inp = sotoinpcb(so); 446df8bae1dSRodney W. Grimes if (inp) 447df8bae1dSRodney W. Grimes panic("rip_attach"); 448f711d546SPoul-Henning Kamp if (p && (error = suser(p)) != 0) 449a29f300eSGarrett Wollman return error; 450117bcae7SGarrett Wollman 4516a800098SYoshinobu Inoue error = soreserve(so, rip_sendspace, rip_recvspace); 4526a800098SYoshinobu Inoue if (error) 4536a800098SYoshinobu Inoue return error; 45486b3ebceSDavid Greenman s = splnet(); 45586b3ebceSDavid Greenman error = in_pcballoc(so, &ripcbinfo, p); 45686b3ebceSDavid Greenman splx(s); 45786b3ebceSDavid Greenman if (error) 45886b3ebceSDavid Greenman return error; 459df8bae1dSRodney W. Grimes inp = (struct inpcb *)so->so_pcb; 4606a800098SYoshinobu Inoue inp->inp_vflag |= INP_IPV4; 461ca98b82cSDavid Greenman inp->inp_ip_p = proto; 4626a800098SYoshinobu Inoue #ifdef IPSEC 4636a800098SYoshinobu Inoue error = ipsec_init_policy(so, &inp->inp_sp); 4646a800098SYoshinobu Inoue if (error != 0) { 4656a800098SYoshinobu Inoue in_pcbdetach(inp); 4666a800098SYoshinobu Inoue return error; 4676a800098SYoshinobu Inoue } 4686a800098SYoshinobu Inoue #endif /*IPSEC*/ 469117bcae7SGarrett Wollman return 0; 470df8bae1dSRodney W. Grimes } 471117bcae7SGarrett Wollman 472117bcae7SGarrett Wollman static int 473117bcae7SGarrett Wollman rip_detach(struct socket *so) 474117bcae7SGarrett Wollman { 475117bcae7SGarrett Wollman struct inpcb *inp; 476117bcae7SGarrett Wollman 477117bcae7SGarrett Wollman inp = sotoinpcb(so); 478df8bae1dSRodney W. Grimes if (inp == 0) 479df8bae1dSRodney W. Grimes panic("rip_detach"); 480df8bae1dSRodney W. Grimes if (so == ip_mrouter) 481df8bae1dSRodney W. Grimes ip_mrouter_done(); 482b4489dc3SGarrett Wollman ip_rsvp_force_done(so); 483838ecf42SGarrett Wollman if (so == ip_rsvpd) 484838ecf42SGarrett Wollman ip_rsvp_done(); 485df8bae1dSRodney W. Grimes in_pcbdetach(inp); 486117bcae7SGarrett Wollman return 0; 487117bcae7SGarrett Wollman } 488df8bae1dSRodney W. Grimes 489117bcae7SGarrett Wollman static int 490117bcae7SGarrett Wollman rip_abort(struct socket *so) 491df8bae1dSRodney W. Grimes { 492117bcae7SGarrett Wollman soisdisconnected(so); 493117bcae7SGarrett Wollman return rip_detach(so); 494117bcae7SGarrett Wollman } 495117bcae7SGarrett Wollman 496117bcae7SGarrett Wollman static int 497117bcae7SGarrett Wollman rip_disconnect(struct socket *so) 498117bcae7SGarrett Wollman { 499117bcae7SGarrett Wollman if ((so->so_state & SS_ISCONNECTED) == 0) 500117bcae7SGarrett Wollman return ENOTCONN; 501117bcae7SGarrett Wollman return rip_abort(so); 502117bcae7SGarrett Wollman } 503117bcae7SGarrett Wollman 504117bcae7SGarrett Wollman static int 50557bf258eSGarrett Wollman rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 506117bcae7SGarrett Wollman { 507117bcae7SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 50857bf258eSGarrett Wollman struct sockaddr_in *addr = (struct sockaddr_in *)nam; 509df8bae1dSRodney W. Grimes 51057bf258eSGarrett Wollman if (nam->sa_len != sizeof(*addr)) 511117bcae7SGarrett Wollman return EINVAL; 512117bcae7SGarrett Wollman 513117bcae7SGarrett Wollman if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) && 514df8bae1dSRodney W. Grimes (addr->sin_family != AF_IMPLINK)) || 515df8bae1dSRodney W. Grimes (addr->sin_addr.s_addr && 516117bcae7SGarrett Wollman ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 517117bcae7SGarrett Wollman return EADDRNOTAVAIL; 518df8bae1dSRodney W. Grimes inp->inp_laddr = addr->sin_addr; 519117bcae7SGarrett Wollman return 0; 520df8bae1dSRodney W. Grimes } 521117bcae7SGarrett Wollman 522117bcae7SGarrett Wollman static int 52357bf258eSGarrett Wollman rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 524df8bae1dSRodney W. Grimes { 525117bcae7SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 52657bf258eSGarrett Wollman struct sockaddr_in *addr = (struct sockaddr_in *)nam; 527df8bae1dSRodney W. Grimes 52857bf258eSGarrett Wollman if (nam->sa_len != sizeof(*addr)) 529117bcae7SGarrett Wollman return EINVAL; 530117bcae7SGarrett Wollman if (TAILQ_EMPTY(&ifnet)) 531117bcae7SGarrett Wollman return EADDRNOTAVAIL; 532df8bae1dSRodney W. Grimes if ((addr->sin_family != AF_INET) && 533117bcae7SGarrett Wollman (addr->sin_family != AF_IMPLINK)) 534117bcae7SGarrett Wollman return EAFNOSUPPORT; 535df8bae1dSRodney W. Grimes inp->inp_faddr = addr->sin_addr; 536df8bae1dSRodney W. Grimes soisconnected(so); 537117bcae7SGarrett Wollman return 0; 538df8bae1dSRodney W. Grimes } 539df8bae1dSRodney W. Grimes 540117bcae7SGarrett Wollman static int 541117bcae7SGarrett Wollman rip_shutdown(struct socket *so) 542df8bae1dSRodney W. Grimes { 543117bcae7SGarrett Wollman socantsendmore(so); 544117bcae7SGarrett Wollman return 0; 545117bcae7SGarrett Wollman } 546117bcae7SGarrett Wollman 547117bcae7SGarrett Wollman static int 54857bf258eSGarrett Wollman rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 549a29f300eSGarrett Wollman struct mbuf *control, struct proc *p) 550117bcae7SGarrett Wollman { 551117bcae7SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 552df8bae1dSRodney W. Grimes register u_long dst; 553df8bae1dSRodney W. Grimes 554df8bae1dSRodney W. Grimes if (so->so_state & SS_ISCONNECTED) { 555df8bae1dSRodney W. Grimes if (nam) { 556117bcae7SGarrett Wollman m_freem(m); 557117bcae7SGarrett Wollman return EISCONN; 558df8bae1dSRodney W. Grimes } 559df8bae1dSRodney W. Grimes dst = inp->inp_faddr.s_addr; 560df8bae1dSRodney W. Grimes } else { 561df8bae1dSRodney W. Grimes if (nam == NULL) { 562117bcae7SGarrett Wollman m_freem(m); 563117bcae7SGarrett Wollman return ENOTCONN; 564df8bae1dSRodney W. Grimes } 56557bf258eSGarrett Wollman dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr; 566df8bae1dSRodney W. Grimes } 567117bcae7SGarrett Wollman return rip_output(m, so, dst); 568df8bae1dSRodney W. Grimes } 569df8bae1dSRodney W. Grimes 57098271db4SGarrett Wollman static int 57182d9ae4eSPoul-Henning Kamp rip_pcblist (SYSCTL_HANDLER_ARGS) 57298271db4SGarrett Wollman { 57398271db4SGarrett Wollman int error, i, n, s; 57498271db4SGarrett Wollman struct inpcb *inp, **inp_list; 57598271db4SGarrett Wollman inp_gen_t gencnt; 57698271db4SGarrett Wollman struct xinpgen xig; 57798271db4SGarrett Wollman 57898271db4SGarrett Wollman /* 57998271db4SGarrett Wollman * The process of preparing the TCB list is too time-consuming and 58098271db4SGarrett Wollman * resource-intensive to repeat twice on every request. 58198271db4SGarrett Wollman */ 58298271db4SGarrett Wollman if (req->oldptr == 0) { 58398271db4SGarrett Wollman n = ripcbinfo.ipi_count; 58498271db4SGarrett Wollman req->oldidx = 2 * (sizeof xig) 58598271db4SGarrett Wollman + (n + n/8) * sizeof(struct xinpcb); 58698271db4SGarrett Wollman return 0; 58798271db4SGarrett Wollman } 58898271db4SGarrett Wollman 58998271db4SGarrett Wollman if (req->newptr != 0) 59098271db4SGarrett Wollman return EPERM; 59198271db4SGarrett Wollman 59298271db4SGarrett Wollman /* 59398271db4SGarrett Wollman * OK, now we're committed to doing something. 59498271db4SGarrett Wollman */ 59598271db4SGarrett Wollman s = splnet(); 59698271db4SGarrett Wollman gencnt = ripcbinfo.ipi_gencnt; 59798271db4SGarrett Wollman n = ripcbinfo.ipi_count; 59898271db4SGarrett Wollman splx(s); 59998271db4SGarrett Wollman 60098271db4SGarrett Wollman xig.xig_len = sizeof xig; 60198271db4SGarrett Wollman xig.xig_count = n; 60298271db4SGarrett Wollman xig.xig_gen = gencnt; 60398271db4SGarrett Wollman xig.xig_sogen = so_gencnt; 60498271db4SGarrett Wollman error = SYSCTL_OUT(req, &xig, sizeof xig); 60598271db4SGarrett Wollman if (error) 60698271db4SGarrett Wollman return error; 60798271db4SGarrett Wollman 60898271db4SGarrett Wollman inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); 60998271db4SGarrett Wollman if (inp_list == 0) 61098271db4SGarrett Wollman return ENOMEM; 61198271db4SGarrett Wollman 61298271db4SGarrett Wollman s = splnet(); 61398271db4SGarrett Wollman for (inp = ripcbinfo.listhead->lh_first, i = 0; inp && i < n; 61498271db4SGarrett Wollman inp = inp->inp_list.le_next) { 61598271db4SGarrett Wollman if (inp->inp_gencnt <= gencnt) 61698271db4SGarrett Wollman inp_list[i++] = inp; 61798271db4SGarrett Wollman } 61898271db4SGarrett Wollman splx(s); 61998271db4SGarrett Wollman n = i; 62098271db4SGarrett Wollman 62198271db4SGarrett Wollman error = 0; 62298271db4SGarrett Wollman for (i = 0; i < n; i++) { 62398271db4SGarrett Wollman inp = inp_list[i]; 62498271db4SGarrett Wollman if (inp->inp_gencnt <= gencnt) { 62598271db4SGarrett Wollman struct xinpcb xi; 62698271db4SGarrett Wollman xi.xi_len = sizeof xi; 62798271db4SGarrett Wollman /* XXX should avoid extra copy */ 62898271db4SGarrett Wollman bcopy(inp, &xi.xi_inp, sizeof *inp); 62998271db4SGarrett Wollman if (inp->inp_socket) 63098271db4SGarrett Wollman sotoxsocket(inp->inp_socket, &xi.xi_socket); 63198271db4SGarrett Wollman error = SYSCTL_OUT(req, &xi, sizeof xi); 63298271db4SGarrett Wollman } 63398271db4SGarrett Wollman } 63498271db4SGarrett Wollman if (!error) { 63598271db4SGarrett Wollman /* 63698271db4SGarrett Wollman * Give the user an updated idea of our state. 63798271db4SGarrett Wollman * If the generation differs from what we told 63898271db4SGarrett Wollman * her before, she knows that something happened 63998271db4SGarrett Wollman * while we were processing this request, and it 64098271db4SGarrett Wollman * might be necessary to retry. 64198271db4SGarrett Wollman */ 64298271db4SGarrett Wollman s = splnet(); 64398271db4SGarrett Wollman xig.xig_gen = ripcbinfo.ipi_gencnt; 64498271db4SGarrett Wollman xig.xig_sogen = so_gencnt; 64598271db4SGarrett Wollman xig.xig_count = ripcbinfo.ipi_count; 64698271db4SGarrett Wollman splx(s); 64798271db4SGarrett Wollman error = SYSCTL_OUT(req, &xig, sizeof xig); 64898271db4SGarrett Wollman } 64998271db4SGarrett Wollman free(inp_list, M_TEMP); 65098271db4SGarrett Wollman return error; 65198271db4SGarrett Wollman } 65298271db4SGarrett Wollman 65398271db4SGarrett Wollman SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0, 65498271db4SGarrett Wollman rip_pcblist, "S,xinpcb", "List of active raw IP sockets"); 65598271db4SGarrett Wollman 656117bcae7SGarrett Wollman struct pr_usrreqs rip_usrreqs = { 657117bcae7SGarrett Wollman rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect, 658117bcae7SGarrett Wollman pru_connect2_notsupp, in_control, rip_detach, rip_disconnect, 659117bcae7SGarrett Wollman pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, 660117bcae7SGarrett Wollman pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown, 661f8f6cbbaSPeter Wemm in_setsockaddr, sosend, soreceive, sopoll 662117bcae7SGarrett Wollman }; 663