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 343d4d47f3SGarrett Wollman * $Id: raw_ip.c,v 1.51 1998/01/27 09:15:07 davidg Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38117bcae7SGarrett Wollman #include <sys/systm.h> 39117bcae7SGarrett Wollman #include <sys/kernel.h> 40df8bae1dSRodney W. Grimes #include <sys/malloc.h> 41df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 42a29f300eSGarrett Wollman #include <sys/proc.h> 43df8bae1dSRodney W. Grimes #include <sys/protosw.h> 44117bcae7SGarrett Wollman #include <sys/socket.h> 45df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 46117bcae7SGarrett Wollman #include <sys/sysctl.h> 473d4d47f3SGarrett Wollman #include <vm/vm_zone.h> 48df8bae1dSRodney W. Grimes 49df8bae1dSRodney W. Grimes #include <net/if.h> 50df8bae1dSRodney W. Grimes #include <net/route.h> 51df8bae1dSRodney W. Grimes 525e2d0696SGarrett Wollman #define _IP_VHL 53df8bae1dSRodney W. Grimes #include <netinet/in.h> 54df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 55df8bae1dSRodney W. Grimes #include <netinet/ip.h> 56c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h> 57c1f8a6ceSDavid Greenman #include <netinet/in_var.h> 58df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 59df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h> 60df8bae1dSRodney W. Grimes 61100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h> 62100ba1a6SJordan K. Hubbard 63f9493383SGarrett Wollman #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 64f9493383SGarrett Wollman #undef COMPAT_IPFW 65f9493383SGarrett Wollman #define COMPAT_IPFW 1 66f9493383SGarrett Wollman #else 67f9493383SGarrett Wollman #undef COMPAT_IPFW 68f9493383SGarrett Wollman #endif 69f9493383SGarrett Wollman 70f6d24a78SPoul-Henning Kamp static struct inpcbhead ripcb; 71f6d24a78SPoul-Henning Kamp static struct inpcbinfo ripcbinfo; 72df8bae1dSRodney W. Grimes 73df8bae1dSRodney W. Grimes /* 74df8bae1dSRodney W. Grimes * Nominal space allocated to a raw ip socket. 75df8bae1dSRodney W. Grimes */ 76df8bae1dSRodney W. Grimes #define RIPSNDQ 8192 77df8bae1dSRodney W. Grimes #define RIPRCVQ 8192 78df8bae1dSRodney W. Grimes 79df8bae1dSRodney W. Grimes /* 80df8bae1dSRodney W. Grimes * Raw interface to IP protocol. 81df8bae1dSRodney W. Grimes */ 82df8bae1dSRodney W. Grimes 83df8bae1dSRodney W. Grimes /* 84df8bae1dSRodney W. Grimes * Initialize raw connection block q. 85df8bae1dSRodney W. Grimes */ 86df8bae1dSRodney W. Grimes void 87df8bae1dSRodney W. Grimes rip_init() 88df8bae1dSRodney W. Grimes { 8915bd2b43SDavid Greenman LIST_INIT(&ripcb); 9015bd2b43SDavid Greenman ripcbinfo.listhead = &ripcb; 9115bd2b43SDavid Greenman /* 9215bd2b43SDavid Greenman * XXX We don't use the hash list for raw IP, but it's easier 9315bd2b43SDavid Greenman * to allocate a one entry hash list than it is to check all 9415bd2b43SDavid Greenman * over the place for hashbase == NULL. 9515bd2b43SDavid Greenman */ 96ddd79a97SDavid Greenman ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask); 97c3229e05SDavid Greenman ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask); 983d4d47f3SGarrett Wollman ripcbinfo.ipi_zone = zinit("ripcb", sizeof(struct inpcb), 993d4d47f3SGarrett Wollman nmbclusters/4, ZONE_INTERRUPT, 0); 100df8bae1dSRodney W. Grimes } 101df8bae1dSRodney W. Grimes 102f6d24a78SPoul-Henning Kamp static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 103df8bae1dSRodney W. Grimes /* 104df8bae1dSRodney W. Grimes * Setup generic address and protocol structures 105df8bae1dSRodney W. Grimes * for raw_input routine, then pass them along with 106df8bae1dSRodney W. Grimes * mbuf chain. 107df8bae1dSRodney W. Grimes */ 108df8bae1dSRodney W. Grimes void 109e62b8c49SBill Fenner rip_input(m, iphlen) 110df8bae1dSRodney W. Grimes struct mbuf *m; 111e62b8c49SBill Fenner int iphlen; 112df8bae1dSRodney W. Grimes { 113df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 114df8bae1dSRodney W. Grimes register struct inpcb *inp; 11582c23ebaSBill Fenner struct inpcb *last = 0; 11682c23ebaSBill Fenner struct mbuf *opts = 0; 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes ripsrc.sin_addr = ip->ip_src; 11915bd2b43SDavid Greenman for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { 120ca98b82cSDavid Greenman if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p) 121df8bae1dSRodney W. Grimes continue; 122df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr && 123d99c7a23SGarrett Wollman inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 124df8bae1dSRodney W. Grimes continue; 125df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr && 126d99c7a23SGarrett Wollman inp->inp_faddr.s_addr != ip->ip_src.s_addr) 127df8bae1dSRodney W. Grimes continue; 128df8bae1dSRodney W. Grimes if (last) { 129623ae52eSPoul-Henning Kamp struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 130623ae52eSPoul-Henning Kamp if (n) { 13182c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS || 13282c23ebaSBill Fenner last->inp_socket->so_options & SO_TIMESTAMP) 13382c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, n); 13482c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 135623ae52eSPoul-Henning Kamp (struct sockaddr *)&ripsrc, n, 13682c23ebaSBill Fenner opts) == 0) { 137df8bae1dSRodney W. Grimes /* should notify about lost packet */ 138df8bae1dSRodney W. Grimes m_freem(n); 13982c23ebaSBill Fenner if (opts) 14082c23ebaSBill Fenner m_freem(opts); 14182c23ebaSBill Fenner } else 14282c23ebaSBill Fenner sorwakeup(last->inp_socket); 14382c23ebaSBill Fenner opts = 0; 144df8bae1dSRodney W. Grimes } 145df8bae1dSRodney W. Grimes } 14682c23ebaSBill Fenner last = inp; 147df8bae1dSRodney W. Grimes } 148df8bae1dSRodney W. Grimes if (last) { 14982c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS || 15082c23ebaSBill Fenner last->inp_socket->so_options & SO_TIMESTAMP) 15182c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, m); 15282c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 15382c23ebaSBill Fenner (struct sockaddr *)&ripsrc, m, opts) == 0) { 154df8bae1dSRodney W. Grimes m_freem(m); 15582c23ebaSBill Fenner if (opts) 15682c23ebaSBill Fenner m_freem(opts); 15782c23ebaSBill Fenner } else 15882c23ebaSBill Fenner sorwakeup(last->inp_socket); 159df8bae1dSRodney W. Grimes } else { 160df8bae1dSRodney W. Grimes m_freem(m); 161df8bae1dSRodney W. Grimes ipstat.ips_noproto++; 162df8bae1dSRodney W. Grimes ipstat.ips_delivered--; 163df8bae1dSRodney W. Grimes } 164df8bae1dSRodney W. Grimes } 165df8bae1dSRodney W. Grimes 166df8bae1dSRodney W. Grimes /* 167df8bae1dSRodney W. Grimes * Generate IP header and pass packet to ip_output. 168df8bae1dSRodney W. Grimes * Tack on options user may have setup with control call. 169df8bae1dSRodney W. Grimes */ 170df8bae1dSRodney W. Grimes int 171df8bae1dSRodney W. Grimes rip_output(m, so, dst) 172df8bae1dSRodney W. Grimes register struct mbuf *m; 173df8bae1dSRodney W. Grimes struct socket *so; 174df8bae1dSRodney W. Grimes u_long dst; 175df8bae1dSRodney W. Grimes { 176df8bae1dSRodney W. Grimes register struct ip *ip; 177df8bae1dSRodney W. Grimes register struct inpcb *inp = sotoinpcb(so); 178df8bae1dSRodney W. Grimes int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 179df8bae1dSRodney W. Grimes 180df8bae1dSRodney W. Grimes /* 181df8bae1dSRodney W. Grimes * If the user handed us a complete IP packet, use it. 182df8bae1dSRodney W. Grimes * Otherwise, allocate an mbuf for a header and fill it in. 183df8bae1dSRodney W. Grimes */ 184df8bae1dSRodney W. Grimes if ((inp->inp_flags & INP_HDRINCL) == 0) { 185430d30d8SBill Fenner if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { 186430d30d8SBill Fenner m_freem(m); 187430d30d8SBill Fenner return(EMSGSIZE); 188430d30d8SBill Fenner } 189df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof(struct ip), M_WAIT); 190df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 191df8bae1dSRodney W. Grimes ip->ip_tos = 0; 192df8bae1dSRodney W. Grimes ip->ip_off = 0; 193ca98b82cSDavid Greenman ip->ip_p = inp->inp_ip_p; 194df8bae1dSRodney W. Grimes ip->ip_len = m->m_pkthdr.len; 195df8bae1dSRodney W. Grimes ip->ip_src = inp->inp_laddr; 196df8bae1dSRodney W. Grimes ip->ip_dst.s_addr = dst; 197df8bae1dSRodney W. Grimes ip->ip_ttl = MAXTTL; 198df8bae1dSRodney W. Grimes } else { 199430d30d8SBill Fenner if (m->m_pkthdr.len > IP_MAXPACKET) { 200430d30d8SBill Fenner m_freem(m); 201430d30d8SBill Fenner return(EMSGSIZE); 202430d30d8SBill Fenner } 203df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 204072b9b24SPaul Traina /* don't allow both user specified and setsockopt options, 205072b9b24SPaul Traina and don't allow packet length sizes that will crash */ 2065e2d0696SGarrett Wollman if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) 2075e2d0696SGarrett Wollman && inp->inp_options) 20891108995SBill Fenner || (ip->ip_len > m->m_pkthdr.len) 20991108995SBill Fenner || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) { 210072b9b24SPaul Traina m_freem(m); 211072b9b24SPaul Traina return EINVAL; 212072b9b24SPaul Traina } 213df8bae1dSRodney W. Grimes if (ip->ip_id == 0) 214df8bae1dSRodney W. Grimes ip->ip_id = htons(ip_id++); 215df8bae1dSRodney W. Grimes /* XXX prevent ip_output from overwriting header fields */ 216df8bae1dSRodney W. Grimes flags |= IP_RAWOUTPUT; 217df8bae1dSRodney W. Grimes ipstat.ips_rawout++; 218df8bae1dSRodney W. Grimes } 219072b9b24SPaul Traina return (ip_output(m, inp->inp_options, &inp->inp_route, flags, 220072b9b24SPaul Traina inp->inp_moptions)); 221df8bae1dSRodney W. Grimes } 222df8bae1dSRodney W. Grimes 223df8bae1dSRodney W. Grimes /* 224df8bae1dSRodney W. Grimes * Raw IP socket option processing. 225df8bae1dSRodney W. Grimes */ 226df8bae1dSRodney W. Grimes int 227a29f300eSGarrett Wollman rip_ctloutput(op, so, level, optname, m, p) 228df8bae1dSRodney W. Grimes int op; 229df8bae1dSRodney W. Grimes struct socket *so; 230df8bae1dSRodney W. Grimes int level, optname; 231df8bae1dSRodney W. Grimes struct mbuf **m; 232a29f300eSGarrett Wollman struct proc *p; 233df8bae1dSRodney W. Grimes { 234df8bae1dSRodney W. Grimes register struct inpcb *inp = sotoinpcb(so); 235df8bae1dSRodney W. Grimes register int error; 236df8bae1dSRodney W. Grimes 237aedcdea1SDavid Greenman if (level != IPPROTO_IP) { 238aedcdea1SDavid Greenman if (op == PRCO_SETOPT && *m) 239aedcdea1SDavid Greenman (void)m_free(*m); 240df8bae1dSRodney W. Grimes return (EINVAL); 241aedcdea1SDavid Greenman } 242df8bae1dSRodney W. Grimes 243df8bae1dSRodney W. Grimes switch (optname) { 244df8bae1dSRodney W. Grimes 245df8bae1dSRodney W. Grimes case IP_HDRINCL: 24625f26ad8SGarrett Wollman error = 0; 247df8bae1dSRodney W. Grimes if (op == PRCO_SETOPT) { 24825f26ad8SGarrett Wollman if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 24925f26ad8SGarrett Wollman error = EINVAL; 25025f26ad8SGarrett Wollman else if (*mtod(*m, int *)) 251df8bae1dSRodney W. Grimes inp->inp_flags |= INP_HDRINCL; 252df8bae1dSRodney W. Grimes else 253df8bae1dSRodney W. Grimes inp->inp_flags &= ~INP_HDRINCL; 25425f26ad8SGarrett Wollman if (*m) 255df8bae1dSRodney W. Grimes (void)m_free(*m); 256df8bae1dSRodney W. Grimes } else { 25725f26ad8SGarrett Wollman *m = m_get(M_WAIT, MT_SOOPTS); 258df8bae1dSRodney W. Grimes (*m)->m_len = sizeof (int); 259df8bae1dSRodney W. Grimes *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 260df8bae1dSRodney W. Grimes } 26125f26ad8SGarrett Wollman return (error); 262df8bae1dSRodney W. Grimes 263f9493383SGarrett Wollman #ifdef COMPAT_IPFW 26409bb5f75SPoul-Henning Kamp case IP_FW_GET: 26509bb5f75SPoul-Henning Kamp if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) { 26609bb5f75SPoul-Henning Kamp if (*m) (void)m_free(*m); 26709bb5f75SPoul-Henning Kamp return(EINVAL); 26809bb5f75SPoul-Henning Kamp } 26909bb5f75SPoul-Henning Kamp return (*ip_fw_ctl_ptr)(optname, m); 270fed1c7e9SSøren Schmidt 2714dd1662bSUgen J.S. Antsilevich case IP_FW_ADD: 2724dd1662bSUgen J.S. Antsilevich case IP_FW_DEL: 273100ba1a6SJordan K. Hubbard case IP_FW_FLUSH: 274e7319babSPoul-Henning Kamp case IP_FW_ZERO: 27509bb5f75SPoul-Henning Kamp if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) { 27609bb5f75SPoul-Henning Kamp if (*m) (void)m_free(*m); 2774dd1662bSUgen J.S. Antsilevich return(EINVAL); 2784dd1662bSUgen J.S. Antsilevich } 27909bb5f75SPoul-Henning Kamp return (*ip_fw_ctl_ptr)(optname, m); 2804dd1662bSUgen J.S. Antsilevich 281fed1c7e9SSøren Schmidt case IP_NAT: 282fed1c7e9SSøren Schmidt if (ip_nat_ctl_ptr == NULL) { 283fed1c7e9SSøren Schmidt if (*m) (void)m_free(*m); 284fed1c7e9SSøren Schmidt return(EINVAL); 285fed1c7e9SSøren Schmidt } 2868f52c187SSøren Schmidt return (*ip_nat_ctl_ptr)(op, m); 287fed1c7e9SSøren Schmidt 28858938916SGarrett Wollman #endif 289f0068c4aSGarrett Wollman case IP_RSVP_ON: 290479bb8daSGarrett Wollman return ip_rsvp_init(so); 291f0068c4aSGarrett Wollman break; 292f0068c4aSGarrett Wollman 293f0068c4aSGarrett Wollman case IP_RSVP_OFF: 294479bb8daSGarrett Wollman return ip_rsvp_done(); 295f0068c4aSGarrett Wollman break; 296f0068c4aSGarrett Wollman 2971c5de19aSGarrett Wollman case IP_RSVP_VIF_ON: 2981c5de19aSGarrett Wollman return ip_rsvp_vif_init(so, *m); 2991c5de19aSGarrett Wollman 3001c5de19aSGarrett Wollman case IP_RSVP_VIF_OFF: 3011c5de19aSGarrett Wollman return ip_rsvp_vif_done(so, *m); 3021c5de19aSGarrett Wollman 3031c5de19aSGarrett Wollman case MRT_INIT: 3041c5de19aSGarrett Wollman case MRT_DONE: 3051c5de19aSGarrett Wollman case MRT_ADD_VIF: 3061c5de19aSGarrett Wollman case MRT_DEL_VIF: 3071c5de19aSGarrett Wollman case MRT_ADD_MFC: 3081c5de19aSGarrett Wollman case MRT_DEL_MFC: 3091c5de19aSGarrett Wollman case MRT_VERSION: 3101c5de19aSGarrett Wollman case MRT_ASSERT: 311df8bae1dSRodney W. Grimes if (op == PRCO_SETOPT) { 3121c5de19aSGarrett Wollman error = ip_mrouter_set(optname, so, *m); 313df8bae1dSRodney W. Grimes if (*m) 314df8bae1dSRodney W. Grimes (void)m_free(*m); 3151c5de19aSGarrett Wollman } else if (op == PRCO_GETOPT) { 3161c5de19aSGarrett Wollman error = ip_mrouter_get(optname, so, m); 317df8bae1dSRodney W. Grimes } else 318df8bae1dSRodney W. Grimes error = EINVAL; 319df8bae1dSRodney W. Grimes return (error); 320df8bae1dSRodney W. Grimes } 321a29f300eSGarrett Wollman return (ip_ctloutput(op, so, level, optname, m, p)); 322df8bae1dSRodney W. Grimes } 323df8bae1dSRodney W. Grimes 32439191c8eSGarrett Wollman /* 32539191c8eSGarrett Wollman * This function exists solely to receive the PRC_IFDOWN messages which 32639191c8eSGarrett Wollman * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa, 32739191c8eSGarrett Wollman * and calls in_ifadown() to remove all routes corresponding to that address. 32839191c8eSGarrett Wollman * It also receives the PRC_IFUP messages from if_up() and reinstalls the 32939191c8eSGarrett Wollman * interface routes. 33039191c8eSGarrett Wollman */ 33139191c8eSGarrett Wollman void 33239191c8eSGarrett Wollman rip_ctlinput(cmd, sa, vip) 33339191c8eSGarrett Wollman int cmd; 33439191c8eSGarrett Wollman struct sockaddr *sa; 33539191c8eSGarrett Wollman void *vip; 33639191c8eSGarrett Wollman { 33739191c8eSGarrett Wollman struct in_ifaddr *ia; 33839191c8eSGarrett Wollman struct ifnet *ifp; 33939191c8eSGarrett Wollman int err; 34039191c8eSGarrett Wollman int flags; 34139191c8eSGarrett Wollman 34239191c8eSGarrett Wollman switch(cmd) { 34339191c8eSGarrett Wollman case PRC_IFDOWN: 34439191c8eSGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 34539191c8eSGarrett Wollman ia = ia->ia_link.tqe_next) { 34639191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa 34739191c8eSGarrett Wollman && (ia->ia_flags & IFA_ROUTE)) { 34839191c8eSGarrett Wollman /* 34939191c8eSGarrett Wollman * in_ifscrub kills the interface route. 35039191c8eSGarrett Wollman */ 35139191c8eSGarrett Wollman in_ifscrub(ia->ia_ifp, ia); 35239191c8eSGarrett Wollman /* 35339191c8eSGarrett Wollman * in_ifadown gets rid of all the rest of 35439191c8eSGarrett Wollman * the routes. This is not quite the right 35539191c8eSGarrett Wollman * thing to do, but at least if we are running 35639191c8eSGarrett Wollman * a routing process they will come back. 35739191c8eSGarrett Wollman */ 35839191c8eSGarrett Wollman in_ifadown(&ia->ia_ifa); 35939191c8eSGarrett Wollman break; 36039191c8eSGarrett Wollman } 36139191c8eSGarrett Wollman } 36239191c8eSGarrett Wollman break; 36339191c8eSGarrett Wollman 36439191c8eSGarrett Wollman case PRC_IFUP: 36539191c8eSGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 36639191c8eSGarrett Wollman ia = ia->ia_link.tqe_next) { 36739191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa) 36839191c8eSGarrett Wollman break; 36939191c8eSGarrett Wollman } 37039191c8eSGarrett Wollman if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) 37139191c8eSGarrett Wollman return; 37239191c8eSGarrett Wollman flags = RTF_UP; 37339191c8eSGarrett Wollman ifp = ia->ia_ifa.ifa_ifp; 37439191c8eSGarrett Wollman 37539191c8eSGarrett Wollman if ((ifp->if_flags & IFF_LOOPBACK) 37639191c8eSGarrett Wollman || (ifp->if_flags & IFF_POINTOPOINT)) 37739191c8eSGarrett Wollman flags |= RTF_HOST; 37839191c8eSGarrett Wollman 37939191c8eSGarrett Wollman err = rtinit(&ia->ia_ifa, RTM_ADD, flags); 38039191c8eSGarrett Wollman if (err == 0) 38139191c8eSGarrett Wollman ia->ia_flags |= IFA_ROUTE; 38239191c8eSGarrett Wollman break; 38339191c8eSGarrett Wollman } 38439191c8eSGarrett Wollman } 38539191c8eSGarrett Wollman 386117bcae7SGarrett Wollman static u_long rip_sendspace = RIPSNDQ; 387117bcae7SGarrett Wollman static u_long rip_recvspace = RIPRCVQ; 388df8bae1dSRodney W. Grimes 389117bcae7SGarrett Wollman SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, &rip_sendspace, 390117bcae7SGarrett Wollman 0, ""); 391117bcae7SGarrett Wollman SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, &rip_recvspace, 392117bcae7SGarrett Wollman 0, ""); 393117bcae7SGarrett Wollman 394117bcae7SGarrett Wollman static int 395a29f300eSGarrett Wollman rip_attach(struct socket *so, int proto, struct proc *p) 396df8bae1dSRodney W. Grimes { 397117bcae7SGarrett Wollman struct inpcb *inp; 39886b3ebceSDavid Greenman int error, s; 399c1f8a6ceSDavid Greenman 400117bcae7SGarrett Wollman inp = sotoinpcb(so); 401df8bae1dSRodney W. Grimes if (inp) 402df8bae1dSRodney W. Grimes panic("rip_attach"); 403a29f300eSGarrett Wollman if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 404a29f300eSGarrett Wollman return error; 405117bcae7SGarrett Wollman 40686b3ebceSDavid Greenman s = splnet(); 40786b3ebceSDavid Greenman error = in_pcballoc(so, &ripcbinfo, p); 40886b3ebceSDavid Greenman splx(s); 40986b3ebceSDavid Greenman if (error) 41086b3ebceSDavid Greenman return error; 41186b3ebceSDavid Greenman error = soreserve(so, rip_sendspace, rip_recvspace); 41286b3ebceSDavid Greenman if (error) 413117bcae7SGarrett Wollman return error; 414df8bae1dSRodney W. Grimes inp = (struct inpcb *)so->so_pcb; 415ca98b82cSDavid Greenman inp->inp_ip_p = proto; 416117bcae7SGarrett Wollman return 0; 417df8bae1dSRodney W. Grimes } 418117bcae7SGarrett Wollman 419117bcae7SGarrett Wollman static int 420117bcae7SGarrett Wollman rip_detach(struct socket *so) 421117bcae7SGarrett Wollman { 422117bcae7SGarrett Wollman struct inpcb *inp; 423117bcae7SGarrett Wollman 424117bcae7SGarrett Wollman inp = sotoinpcb(so); 425df8bae1dSRodney W. Grimes if (inp == 0) 426df8bae1dSRodney W. Grimes panic("rip_detach"); 427df8bae1dSRodney W. Grimes if (so == ip_mrouter) 428df8bae1dSRodney W. Grimes ip_mrouter_done(); 429b4489dc3SGarrett Wollman ip_rsvp_force_done(so); 430838ecf42SGarrett Wollman if (so == ip_rsvpd) 431838ecf42SGarrett Wollman ip_rsvp_done(); 432df8bae1dSRodney W. Grimes in_pcbdetach(inp); 433117bcae7SGarrett Wollman return 0; 434117bcae7SGarrett Wollman } 435df8bae1dSRodney W. Grimes 436117bcae7SGarrett Wollman static int 437117bcae7SGarrett Wollman rip_abort(struct socket *so) 438df8bae1dSRodney W. Grimes { 439117bcae7SGarrett Wollman soisdisconnected(so); 440117bcae7SGarrett Wollman return rip_detach(so); 441117bcae7SGarrett Wollman } 442117bcae7SGarrett Wollman 443117bcae7SGarrett Wollman static int 444117bcae7SGarrett Wollman rip_disconnect(struct socket *so) 445117bcae7SGarrett Wollman { 446117bcae7SGarrett Wollman if ((so->so_state & SS_ISCONNECTED) == 0) 447117bcae7SGarrett Wollman return ENOTCONN; 448117bcae7SGarrett Wollman return rip_abort(so); 449117bcae7SGarrett Wollman } 450117bcae7SGarrett Wollman 451117bcae7SGarrett Wollman static int 45257bf258eSGarrett Wollman rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 453117bcae7SGarrett Wollman { 454117bcae7SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 45557bf258eSGarrett Wollman struct sockaddr_in *addr = (struct sockaddr_in *)nam; 456df8bae1dSRodney W. Grimes 45757bf258eSGarrett Wollman if (nam->sa_len != sizeof(*addr)) 458117bcae7SGarrett Wollman return EINVAL; 459117bcae7SGarrett Wollman 460117bcae7SGarrett Wollman if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) && 461df8bae1dSRodney W. Grimes (addr->sin_family != AF_IMPLINK)) || 462df8bae1dSRodney W. Grimes (addr->sin_addr.s_addr && 463117bcae7SGarrett Wollman ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 464117bcae7SGarrett Wollman return EADDRNOTAVAIL; 465df8bae1dSRodney W. Grimes inp->inp_laddr = addr->sin_addr; 466117bcae7SGarrett Wollman return 0; 467df8bae1dSRodney W. Grimes } 468117bcae7SGarrett Wollman 469117bcae7SGarrett Wollman static int 47057bf258eSGarrett Wollman rip_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 471df8bae1dSRodney W. Grimes { 472117bcae7SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 47357bf258eSGarrett Wollman struct sockaddr_in *addr = (struct sockaddr_in *)nam; 474df8bae1dSRodney W. Grimes 47557bf258eSGarrett Wollman if (nam->sa_len != sizeof(*addr)) 476117bcae7SGarrett Wollman return EINVAL; 477117bcae7SGarrett Wollman if (TAILQ_EMPTY(&ifnet)) 478117bcae7SGarrett Wollman return EADDRNOTAVAIL; 479df8bae1dSRodney W. Grimes if ((addr->sin_family != AF_INET) && 480117bcae7SGarrett Wollman (addr->sin_family != AF_IMPLINK)) 481117bcae7SGarrett Wollman return EAFNOSUPPORT; 482df8bae1dSRodney W. Grimes inp->inp_faddr = addr->sin_addr; 483df8bae1dSRodney W. Grimes soisconnected(so); 484117bcae7SGarrett Wollman return 0; 485df8bae1dSRodney W. Grimes } 486df8bae1dSRodney W. Grimes 487117bcae7SGarrett Wollman static int 488117bcae7SGarrett Wollman rip_shutdown(struct socket *so) 489df8bae1dSRodney W. Grimes { 490117bcae7SGarrett Wollman socantsendmore(so); 491117bcae7SGarrett Wollman return 0; 492117bcae7SGarrett Wollman } 493117bcae7SGarrett Wollman 494117bcae7SGarrett Wollman static int 49557bf258eSGarrett Wollman rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 496a29f300eSGarrett Wollman struct mbuf *control, struct proc *p) 497117bcae7SGarrett Wollman { 498117bcae7SGarrett Wollman struct inpcb *inp = sotoinpcb(so); 499df8bae1dSRodney W. Grimes register u_long dst; 500df8bae1dSRodney W. Grimes 501df8bae1dSRodney W. Grimes if (so->so_state & SS_ISCONNECTED) { 502df8bae1dSRodney W. Grimes if (nam) { 503117bcae7SGarrett Wollman m_freem(m); 504117bcae7SGarrett Wollman return EISCONN; 505df8bae1dSRodney W. Grimes } 506df8bae1dSRodney W. Grimes dst = inp->inp_faddr.s_addr; 507df8bae1dSRodney W. Grimes } else { 508df8bae1dSRodney W. Grimes if (nam == NULL) { 509117bcae7SGarrett Wollman m_freem(m); 510117bcae7SGarrett Wollman return ENOTCONN; 511df8bae1dSRodney W. Grimes } 51257bf258eSGarrett Wollman dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr; 513df8bae1dSRodney W. Grimes } 514117bcae7SGarrett Wollman return rip_output(m, so, dst); 515df8bae1dSRodney W. Grimes } 516df8bae1dSRodney W. Grimes 517117bcae7SGarrett Wollman struct pr_usrreqs rip_usrreqs = { 518117bcae7SGarrett Wollman rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect, 519117bcae7SGarrett Wollman pru_connect2_notsupp, in_control, rip_detach, rip_disconnect, 520117bcae7SGarrett Wollman pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, 521117bcae7SGarrett Wollman pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown, 522f8f6cbbaSPeter Wemm in_setsockaddr, sosend, soreceive, sopoll 523117bcae7SGarrett Wollman }; 524