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 3439191c8eSGarrett Wollman * $Id$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 382ee45d7dSDavid Greenman #include <sys/queue.h> 39df8bae1dSRodney W. Grimes #include <sys/malloc.h> 40df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 41df8bae1dSRodney W. Grimes #include <sys/socket.h> 42df8bae1dSRodney W. Grimes #include <sys/protosw.h> 43df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 44df8bae1dSRodney W. Grimes #include <sys/errno.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 46df8bae1dSRodney W. Grimes 47df8bae1dSRodney W. Grimes #include <net/if.h> 48df8bae1dSRodney W. Grimes #include <net/route.h> 49df8bae1dSRodney W. Grimes 505e2d0696SGarrett Wollman #define _IP_VHL 51df8bae1dSRodney W. Grimes #include <netinet/in.h> 52df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 53df8bae1dSRodney W. Grimes #include <netinet/ip.h> 54c1f8a6ceSDavid Greenman #include <netinet/in_pcb.h> 55c1f8a6ceSDavid Greenman #include <netinet/in_var.h> 56df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 57df8bae1dSRodney W. Grimes #include <netinet/ip_mroute.h> 58df8bae1dSRodney W. Grimes 59100ba1a6SJordan K. Hubbard #include <netinet/ip_fw.h> 60100ba1a6SJordan K. Hubbard 61f9493383SGarrett Wollman #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 62f9493383SGarrett Wollman #undef COMPAT_IPFW 63f9493383SGarrett Wollman #define COMPAT_IPFW 1 64f9493383SGarrett Wollman #else 65f9493383SGarrett Wollman #undef COMPAT_IPFW 66f9493383SGarrett Wollman #endif 67f9493383SGarrett Wollman 68f6d24a78SPoul-Henning Kamp static struct inpcbhead ripcb; 69f6d24a78SPoul-Henning Kamp static struct inpcbinfo ripcbinfo; 70df8bae1dSRodney W. Grimes 71df8bae1dSRodney W. Grimes /* 72df8bae1dSRodney W. Grimes * Nominal space allocated to a raw ip socket. 73df8bae1dSRodney W. Grimes */ 74df8bae1dSRodney W. Grimes #define RIPSNDQ 8192 75df8bae1dSRodney W. Grimes #define RIPRCVQ 8192 76df8bae1dSRodney W. Grimes 77df8bae1dSRodney W. Grimes /* 78df8bae1dSRodney W. Grimes * Raw interface to IP protocol. 79df8bae1dSRodney W. Grimes */ 80df8bae1dSRodney W. Grimes 81df8bae1dSRodney W. Grimes /* 82df8bae1dSRodney W. Grimes * Initialize raw connection block q. 83df8bae1dSRodney W. Grimes */ 84df8bae1dSRodney W. Grimes void 85df8bae1dSRodney W. Grimes rip_init() 86df8bae1dSRodney W. Grimes { 8715bd2b43SDavid Greenman LIST_INIT(&ripcb); 8815bd2b43SDavid Greenman ripcbinfo.listhead = &ripcb; 8915bd2b43SDavid Greenman /* 9015bd2b43SDavid Greenman * XXX We don't use the hash list for raw IP, but it's easier 9115bd2b43SDavid Greenman * to allocate a one entry hash list than it is to check all 9215bd2b43SDavid Greenman * over the place for hashbase == NULL. 9315bd2b43SDavid Greenman */ 9415bd2b43SDavid Greenman ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize); 95df8bae1dSRodney W. Grimes } 96df8bae1dSRodney W. Grimes 97f6d24a78SPoul-Henning Kamp static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 98df8bae1dSRodney W. Grimes /* 99df8bae1dSRodney W. Grimes * Setup generic address and protocol structures 100df8bae1dSRodney W. Grimes * for raw_input routine, then pass them along with 101df8bae1dSRodney W. Grimes * mbuf chain. 102df8bae1dSRodney W. Grimes */ 103df8bae1dSRodney W. Grimes void 104e62b8c49SBill Fenner rip_input(m, iphlen) 105df8bae1dSRodney W. Grimes struct mbuf *m; 106e62b8c49SBill Fenner int iphlen; 107df8bae1dSRodney W. Grimes { 108df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 109df8bae1dSRodney W. Grimes register struct inpcb *inp; 11082c23ebaSBill Fenner struct inpcb *last = 0; 11182c23ebaSBill Fenner struct mbuf *opts = 0; 112df8bae1dSRodney W. Grimes 113df8bae1dSRodney W. Grimes ripsrc.sin_addr = ip->ip_src; 11415bd2b43SDavid Greenman for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { 115df8bae1dSRodney W. Grimes if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 116df8bae1dSRodney W. Grimes continue; 117df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr && 118d99c7a23SGarrett Wollman inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 119df8bae1dSRodney W. Grimes continue; 120df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr && 121d99c7a23SGarrett Wollman inp->inp_faddr.s_addr != ip->ip_src.s_addr) 122df8bae1dSRodney W. Grimes continue; 123df8bae1dSRodney W. Grimes if (last) { 124623ae52eSPoul-Henning Kamp struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 125623ae52eSPoul-Henning Kamp if (n) { 12682c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS || 12782c23ebaSBill Fenner last->inp_socket->so_options & SO_TIMESTAMP) 12882c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, n); 12982c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 130623ae52eSPoul-Henning Kamp (struct sockaddr *)&ripsrc, n, 13182c23ebaSBill Fenner opts) == 0) { 132df8bae1dSRodney W. Grimes /* should notify about lost packet */ 133df8bae1dSRodney W. Grimes m_freem(n); 13482c23ebaSBill Fenner if (opts) 13582c23ebaSBill Fenner m_freem(opts); 13682c23ebaSBill Fenner } else 13782c23ebaSBill Fenner sorwakeup(last->inp_socket); 13882c23ebaSBill Fenner opts = 0; 139df8bae1dSRodney W. Grimes } 140df8bae1dSRodney W. Grimes } 14182c23ebaSBill Fenner last = inp; 142df8bae1dSRodney W. Grimes } 143df8bae1dSRodney W. Grimes if (last) { 14482c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS || 14582c23ebaSBill Fenner last->inp_socket->so_options & SO_TIMESTAMP) 14682c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, m); 14782c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 14882c23ebaSBill Fenner (struct sockaddr *)&ripsrc, m, opts) == 0) { 149df8bae1dSRodney W. Grimes m_freem(m); 15082c23ebaSBill Fenner if (opts) 15182c23ebaSBill Fenner m_freem(opts); 15282c23ebaSBill Fenner } else 15382c23ebaSBill Fenner sorwakeup(last->inp_socket); 154df8bae1dSRodney W. Grimes } else { 155df8bae1dSRodney W. Grimes m_freem(m); 156df8bae1dSRodney W. Grimes ipstat.ips_noproto++; 157df8bae1dSRodney W. Grimes ipstat.ips_delivered--; 158df8bae1dSRodney W. Grimes } 159df8bae1dSRodney W. Grimes } 160df8bae1dSRodney W. Grimes 161df8bae1dSRodney W. Grimes /* 162df8bae1dSRodney W. Grimes * Generate IP header and pass packet to ip_output. 163df8bae1dSRodney W. Grimes * Tack on options user may have setup with control call. 164df8bae1dSRodney W. Grimes */ 165df8bae1dSRodney W. Grimes int 166df8bae1dSRodney W. Grimes rip_output(m, so, dst) 167df8bae1dSRodney W. Grimes register struct mbuf *m; 168df8bae1dSRodney W. Grimes struct socket *so; 169df8bae1dSRodney W. Grimes u_long dst; 170df8bae1dSRodney W. Grimes { 171df8bae1dSRodney W. Grimes register struct ip *ip; 172df8bae1dSRodney W. Grimes register struct inpcb *inp = sotoinpcb(so); 173df8bae1dSRodney W. Grimes int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 174df8bae1dSRodney W. Grimes 175df8bae1dSRodney W. Grimes /* 176df8bae1dSRodney W. Grimes * If the user handed us a complete IP packet, use it. 177df8bae1dSRodney W. Grimes * Otherwise, allocate an mbuf for a header and fill it in. 178df8bae1dSRodney W. Grimes */ 179df8bae1dSRodney W. Grimes if ((inp->inp_flags & INP_HDRINCL) == 0) { 180430d30d8SBill Fenner if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { 181430d30d8SBill Fenner m_freem(m); 182430d30d8SBill Fenner return(EMSGSIZE); 183430d30d8SBill Fenner } 184df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof(struct ip), M_WAIT); 185df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 186df8bae1dSRodney W. Grimes ip->ip_tos = 0; 187df8bae1dSRodney W. Grimes ip->ip_off = 0; 188df8bae1dSRodney W. Grimes ip->ip_p = inp->inp_ip.ip_p; 189df8bae1dSRodney W. Grimes ip->ip_len = m->m_pkthdr.len; 190df8bae1dSRodney W. Grimes ip->ip_src = inp->inp_laddr; 191df8bae1dSRodney W. Grimes ip->ip_dst.s_addr = dst; 192df8bae1dSRodney W. Grimes ip->ip_ttl = MAXTTL; 193df8bae1dSRodney W. Grimes } else { 194430d30d8SBill Fenner if (m->m_pkthdr.len > IP_MAXPACKET) { 195430d30d8SBill Fenner m_freem(m); 196430d30d8SBill Fenner return(EMSGSIZE); 197430d30d8SBill Fenner } 198df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 199072b9b24SPaul Traina /* don't allow both user specified and setsockopt options, 200072b9b24SPaul Traina and don't allow packet length sizes that will crash */ 2015e2d0696SGarrett Wollman if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) 2025e2d0696SGarrett Wollman && inp->inp_options) 2035e2d0696SGarrett Wollman || (ip->ip_len > m->m_pkthdr.len)) { 204072b9b24SPaul Traina m_freem(m); 205072b9b24SPaul Traina return EINVAL; 206072b9b24SPaul Traina } 207df8bae1dSRodney W. Grimes if (ip->ip_id == 0) 208df8bae1dSRodney W. Grimes ip->ip_id = htons(ip_id++); 209df8bae1dSRodney W. Grimes /* XXX prevent ip_output from overwriting header fields */ 210df8bae1dSRodney W. Grimes flags |= IP_RAWOUTPUT; 211df8bae1dSRodney W. Grimes ipstat.ips_rawout++; 212df8bae1dSRodney W. Grimes } 213072b9b24SPaul Traina return (ip_output(m, inp->inp_options, &inp->inp_route, flags, 214072b9b24SPaul Traina inp->inp_moptions)); 215df8bae1dSRodney W. Grimes } 216df8bae1dSRodney W. Grimes 217df8bae1dSRodney W. Grimes /* 218df8bae1dSRodney W. Grimes * Raw IP socket option processing. 219df8bae1dSRodney W. Grimes */ 220df8bae1dSRodney W. Grimes int 221df8bae1dSRodney W. Grimes rip_ctloutput(op, so, level, optname, m) 222df8bae1dSRodney W. Grimes int op; 223df8bae1dSRodney W. Grimes struct socket *so; 224df8bae1dSRodney W. Grimes int level, optname; 225df8bae1dSRodney W. Grimes struct mbuf **m; 226df8bae1dSRodney W. Grimes { 227df8bae1dSRodney W. Grimes register struct inpcb *inp = sotoinpcb(so); 228df8bae1dSRodney W. Grimes register int error; 229df8bae1dSRodney W. Grimes 230aedcdea1SDavid Greenman if (level != IPPROTO_IP) { 231aedcdea1SDavid Greenman if (op == PRCO_SETOPT && *m) 232aedcdea1SDavid Greenman (void)m_free(*m); 233df8bae1dSRodney W. Grimes return (EINVAL); 234aedcdea1SDavid Greenman } 235df8bae1dSRodney W. Grimes 236df8bae1dSRodney W. Grimes switch (optname) { 237df8bae1dSRodney W. Grimes 238df8bae1dSRodney W. Grimes case IP_HDRINCL: 23925f26ad8SGarrett Wollman error = 0; 240df8bae1dSRodney W. Grimes if (op == PRCO_SETOPT) { 24125f26ad8SGarrett Wollman if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 24225f26ad8SGarrett Wollman error = EINVAL; 24325f26ad8SGarrett Wollman else if (*mtod(*m, int *)) 244df8bae1dSRodney W. Grimes inp->inp_flags |= INP_HDRINCL; 245df8bae1dSRodney W. Grimes else 246df8bae1dSRodney W. Grimes inp->inp_flags &= ~INP_HDRINCL; 24725f26ad8SGarrett Wollman if (*m) 248df8bae1dSRodney W. Grimes (void)m_free(*m); 249df8bae1dSRodney W. Grimes } else { 25025f26ad8SGarrett Wollman *m = m_get(M_WAIT, MT_SOOPTS); 251df8bae1dSRodney W. Grimes (*m)->m_len = sizeof (int); 252df8bae1dSRodney W. Grimes *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 253df8bae1dSRodney W. Grimes } 25425f26ad8SGarrett Wollman return (error); 255df8bae1dSRodney W. Grimes 256f9493383SGarrett Wollman #ifdef COMPAT_IPFW 25709bb5f75SPoul-Henning Kamp case IP_FW_GET: 25809bb5f75SPoul-Henning Kamp if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) { 25909bb5f75SPoul-Henning Kamp if (*m) (void)m_free(*m); 26009bb5f75SPoul-Henning Kamp return(EINVAL); 26109bb5f75SPoul-Henning Kamp } 26209bb5f75SPoul-Henning Kamp return (*ip_fw_ctl_ptr)(optname, m); 263fed1c7e9SSøren Schmidt 2644dd1662bSUgen J.S. Antsilevich case IP_FW_ADD: 2654dd1662bSUgen J.S. Antsilevich case IP_FW_DEL: 266100ba1a6SJordan K. Hubbard case IP_FW_FLUSH: 267e7319babSPoul-Henning Kamp case IP_FW_ZERO: 26809bb5f75SPoul-Henning Kamp if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) { 26909bb5f75SPoul-Henning Kamp if (*m) (void)m_free(*m); 2704dd1662bSUgen J.S. Antsilevich return(EINVAL); 2714dd1662bSUgen J.S. Antsilevich } 27209bb5f75SPoul-Henning Kamp return (*ip_fw_ctl_ptr)(optname, m); 2734dd1662bSUgen J.S. Antsilevich 274fed1c7e9SSøren Schmidt case IP_NAT: 275fed1c7e9SSøren Schmidt if (ip_nat_ctl_ptr == NULL) { 276fed1c7e9SSøren Schmidt if (*m) (void)m_free(*m); 277fed1c7e9SSøren Schmidt return(EINVAL); 278fed1c7e9SSøren Schmidt } 2798f52c187SSøren Schmidt return (*ip_nat_ctl_ptr)(op, m); 280fed1c7e9SSøren Schmidt 28158938916SGarrett Wollman #endif 282f0068c4aSGarrett Wollman case IP_RSVP_ON: 283479bb8daSGarrett Wollman return ip_rsvp_init(so); 284f0068c4aSGarrett Wollman break; 285f0068c4aSGarrett Wollman 286f0068c4aSGarrett Wollman case IP_RSVP_OFF: 287479bb8daSGarrett Wollman return ip_rsvp_done(); 288f0068c4aSGarrett Wollman break; 289f0068c4aSGarrett Wollman 2901c5de19aSGarrett Wollman case IP_RSVP_VIF_ON: 2911c5de19aSGarrett Wollman return ip_rsvp_vif_init(so, *m); 2921c5de19aSGarrett Wollman 2931c5de19aSGarrett Wollman case IP_RSVP_VIF_OFF: 2941c5de19aSGarrett Wollman return ip_rsvp_vif_done(so, *m); 2951c5de19aSGarrett Wollman 2961c5de19aSGarrett Wollman case MRT_INIT: 2971c5de19aSGarrett Wollman case MRT_DONE: 2981c5de19aSGarrett Wollman case MRT_ADD_VIF: 2991c5de19aSGarrett Wollman case MRT_DEL_VIF: 3001c5de19aSGarrett Wollman case MRT_ADD_MFC: 3011c5de19aSGarrett Wollman case MRT_DEL_MFC: 3021c5de19aSGarrett Wollman case MRT_VERSION: 3031c5de19aSGarrett Wollman case MRT_ASSERT: 304df8bae1dSRodney W. Grimes if (op == PRCO_SETOPT) { 3051c5de19aSGarrett Wollman error = ip_mrouter_set(optname, so, *m); 306df8bae1dSRodney W. Grimes if (*m) 307df8bae1dSRodney W. Grimes (void)m_free(*m); 3081c5de19aSGarrett Wollman } else if (op == PRCO_GETOPT) { 3091c5de19aSGarrett Wollman error = ip_mrouter_get(optname, so, m); 310df8bae1dSRodney W. Grimes } else 311df8bae1dSRodney W. Grimes error = EINVAL; 312df8bae1dSRodney W. Grimes return (error); 313df8bae1dSRodney W. Grimes } 314df8bae1dSRodney W. Grimes return (ip_ctloutput(op, so, level, optname, m)); 315df8bae1dSRodney W. Grimes } 316df8bae1dSRodney W. Grimes 31739191c8eSGarrett Wollman /* 31839191c8eSGarrett Wollman * This function exists solely to receive the PRC_IFDOWN messages which 31939191c8eSGarrett Wollman * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa, 32039191c8eSGarrett Wollman * and calls in_ifadown() to remove all routes corresponding to that address. 32139191c8eSGarrett Wollman * It also receives the PRC_IFUP messages from if_up() and reinstalls the 32239191c8eSGarrett Wollman * interface routes. 32339191c8eSGarrett Wollman */ 32439191c8eSGarrett Wollman void 32539191c8eSGarrett Wollman rip_ctlinput(cmd, sa, vip) 32639191c8eSGarrett Wollman int cmd; 32739191c8eSGarrett Wollman struct sockaddr *sa; 32839191c8eSGarrett Wollman void *vip; 32939191c8eSGarrett Wollman { 33039191c8eSGarrett Wollman struct in_ifaddr *ia; 33139191c8eSGarrett Wollman struct ifnet *ifp; 33239191c8eSGarrett Wollman int err; 33339191c8eSGarrett Wollman int flags; 33439191c8eSGarrett Wollman 33539191c8eSGarrett Wollman switch(cmd) { 33639191c8eSGarrett Wollman case PRC_IFDOWN: 33739191c8eSGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 33839191c8eSGarrett Wollman ia = ia->ia_link.tqe_next) { 33939191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa 34039191c8eSGarrett Wollman && (ia->ia_flags & IFA_ROUTE)) { 34139191c8eSGarrett Wollman /* 34239191c8eSGarrett Wollman * in_ifscrub kills the interface route. 34339191c8eSGarrett Wollman */ 34439191c8eSGarrett Wollman in_ifscrub(ia->ia_ifp, ia); 34539191c8eSGarrett Wollman /* 34639191c8eSGarrett Wollman * in_ifadown gets rid of all the rest of 34739191c8eSGarrett Wollman * the routes. This is not quite the right 34839191c8eSGarrett Wollman * thing to do, but at least if we are running 34939191c8eSGarrett Wollman * a routing process they will come back. 35039191c8eSGarrett Wollman */ 35139191c8eSGarrett Wollman in_ifadown(&ia->ia_ifa); 35239191c8eSGarrett Wollman break; 35339191c8eSGarrett Wollman } 35439191c8eSGarrett Wollman } 35539191c8eSGarrett Wollman break; 35639191c8eSGarrett Wollman 35739191c8eSGarrett Wollman case PRC_IFUP: 35839191c8eSGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; 35939191c8eSGarrett Wollman ia = ia->ia_link.tqe_next) { 36039191c8eSGarrett Wollman if (ia->ia_ifa.ifa_addr == sa) 36139191c8eSGarrett Wollman break; 36239191c8eSGarrett Wollman } 36339191c8eSGarrett Wollman if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) 36439191c8eSGarrett Wollman return; 36539191c8eSGarrett Wollman flags = RTF_UP; 36639191c8eSGarrett Wollman ifp = ia->ia_ifa.ifa_ifp; 36739191c8eSGarrett Wollman 36839191c8eSGarrett Wollman if ((ifp->if_flags & IFF_LOOPBACK) 36939191c8eSGarrett Wollman || (ifp->if_flags & IFF_POINTOPOINT)) 37039191c8eSGarrett Wollman flags |= RTF_HOST; 37139191c8eSGarrett Wollman 37239191c8eSGarrett Wollman err = rtinit(&ia->ia_ifa, RTM_ADD, flags); 37339191c8eSGarrett Wollman if (err == 0) 37439191c8eSGarrett Wollman ia->ia_flags |= IFA_ROUTE; 37539191c8eSGarrett Wollman break; 37639191c8eSGarrett Wollman } 37739191c8eSGarrett Wollman } 37839191c8eSGarrett Wollman 3790312fbe9SPoul-Henning Kamp static u_long rip_sendspace = RIPSNDQ; /* XXX sysctl ? */ 3800312fbe9SPoul-Henning Kamp static u_long rip_recvspace = RIPRCVQ; /* XXX sysctl ? */ 381df8bae1dSRodney W. Grimes 382df8bae1dSRodney W. Grimes /*ARGSUSED*/ 383df8bae1dSRodney W. Grimes int 384df8bae1dSRodney W. Grimes rip_usrreq(so, req, m, nam, control) 385df8bae1dSRodney W. Grimes register struct socket *so; 386df8bae1dSRodney W. Grimes int req; 387df8bae1dSRodney W. Grimes struct mbuf *m, *nam, *control; 388df8bae1dSRodney W. Grimes { 389df8bae1dSRodney W. Grimes register int error = 0; 390df8bae1dSRodney W. Grimes register struct inpcb *inp = sotoinpcb(so); 391c1f8a6ceSDavid Greenman 392c1f8a6ceSDavid Greenman if (req == PRU_CONTROL) 393c1f8a6ceSDavid Greenman return (in_control(so, (u_long)m, (caddr_t)nam, 394c1f8a6ceSDavid Greenman (struct ifnet *)control)); 395c1f8a6ceSDavid Greenman 396df8bae1dSRodney W. Grimes switch (req) { 397df8bae1dSRodney W. Grimes 398df8bae1dSRodney W. Grimes case PRU_ATTACH: 399df8bae1dSRodney W. Grimes if (inp) 400df8bae1dSRodney W. Grimes panic("rip_attach"); 401df8bae1dSRodney W. Grimes if ((so->so_state & SS_PRIV) == 0) { 402df8bae1dSRodney W. Grimes error = EACCES; 403df8bae1dSRodney W. Grimes break; 404df8bae1dSRodney W. Grimes } 405df8bae1dSRodney W. Grimes if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 40615bd2b43SDavid Greenman (error = in_pcballoc(so, &ripcbinfo))) 407df8bae1dSRodney W. Grimes break; 408df8bae1dSRodney W. Grimes inp = (struct inpcb *)so->so_pcb; 409df8bae1dSRodney W. Grimes inp->inp_ip.ip_p = (int)nam; 410df8bae1dSRodney W. Grimes break; 411df8bae1dSRodney W. Grimes 412df8bae1dSRodney W. Grimes case PRU_DISCONNECT: 413df8bae1dSRodney W. Grimes if ((so->so_state & SS_ISCONNECTED) == 0) { 414df8bae1dSRodney W. Grimes error = ENOTCONN; 415df8bae1dSRodney W. Grimes break; 416df8bae1dSRodney W. Grimes } 417df8bae1dSRodney W. Grimes /* FALLTHROUGH */ 418df8bae1dSRodney W. Grimes case PRU_ABORT: 419df8bae1dSRodney W. Grimes soisdisconnected(so); 420df8bae1dSRodney W. Grimes /* FALLTHROUGH */ 421df8bae1dSRodney W. Grimes case PRU_DETACH: 422df8bae1dSRodney W. Grimes if (inp == 0) 423df8bae1dSRodney W. Grimes panic("rip_detach"); 424df8bae1dSRodney W. Grimes if (so == ip_mrouter) 425df8bae1dSRodney W. Grimes ip_mrouter_done(); 426b4489dc3SGarrett Wollman ip_rsvp_force_done(so); 427838ecf42SGarrett Wollman if (so == ip_rsvpd) 428838ecf42SGarrett Wollman ip_rsvp_done(); 429df8bae1dSRodney W. Grimes in_pcbdetach(inp); 430df8bae1dSRodney W. Grimes break; 431df8bae1dSRodney W. Grimes 432df8bae1dSRodney W. Grimes case PRU_BIND: 433df8bae1dSRodney W. Grimes { 434df8bae1dSRodney W. Grimes struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 435df8bae1dSRodney W. Grimes 436df8bae1dSRodney W. Grimes if (nam->m_len != sizeof(*addr)) { 437df8bae1dSRodney W. Grimes error = EINVAL; 438df8bae1dSRodney W. Grimes break; 439df8bae1dSRodney W. Grimes } 44029412182SGarrett Wollman if (TAILQ_EMPTY(&ifnet) || 441df8bae1dSRodney W. Grimes ((addr->sin_family != AF_INET) && 442df8bae1dSRodney W. Grimes (addr->sin_family != AF_IMPLINK)) || 443df8bae1dSRodney W. Grimes (addr->sin_addr.s_addr && 444df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 445df8bae1dSRodney W. Grimes error = EADDRNOTAVAIL; 446df8bae1dSRodney W. Grimes break; 447df8bae1dSRodney W. Grimes } 448df8bae1dSRodney W. Grimes inp->inp_laddr = addr->sin_addr; 449df8bae1dSRodney W. Grimes break; 450df8bae1dSRodney W. Grimes } 451df8bae1dSRodney W. Grimes case PRU_CONNECT: 452df8bae1dSRodney W. Grimes { 453df8bae1dSRodney W. Grimes struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 454df8bae1dSRodney W. Grimes 455df8bae1dSRodney W. Grimes if (nam->m_len != sizeof(*addr)) { 456df8bae1dSRodney W. Grimes error = EINVAL; 457df8bae1dSRodney W. Grimes break; 458df8bae1dSRodney W. Grimes } 45929412182SGarrett Wollman if (TAILQ_EMPTY(&ifnet)) { 460df8bae1dSRodney W. Grimes error = EADDRNOTAVAIL; 461df8bae1dSRodney W. Grimes break; 462df8bae1dSRodney W. Grimes } 463df8bae1dSRodney W. Grimes if ((addr->sin_family != AF_INET) && 464df8bae1dSRodney W. Grimes (addr->sin_family != AF_IMPLINK)) { 465df8bae1dSRodney W. Grimes error = EAFNOSUPPORT; 466df8bae1dSRodney W. Grimes break; 467df8bae1dSRodney W. Grimes } 468df8bae1dSRodney W. Grimes inp->inp_faddr = addr->sin_addr; 469df8bae1dSRodney W. Grimes soisconnected(so); 470df8bae1dSRodney W. Grimes break; 471df8bae1dSRodney W. Grimes } 472df8bae1dSRodney W. Grimes 473df8bae1dSRodney W. Grimes case PRU_CONNECT2: 474df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 475df8bae1dSRodney W. Grimes break; 476df8bae1dSRodney W. Grimes 477df8bae1dSRodney W. Grimes /* 478df8bae1dSRodney W. Grimes * Mark the connection as being incapable of further input. 479df8bae1dSRodney W. Grimes */ 480df8bae1dSRodney W. Grimes case PRU_SHUTDOWN: 481df8bae1dSRodney W. Grimes socantsendmore(so); 482df8bae1dSRodney W. Grimes break; 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes /* 485df8bae1dSRodney W. Grimes * Ship a packet out. The appropriate raw output 486df8bae1dSRodney W. Grimes * routine handles any massaging necessary. 487df8bae1dSRodney W. Grimes */ 488df8bae1dSRodney W. Grimes case PRU_SEND: 489df8bae1dSRodney W. Grimes { 490df8bae1dSRodney W. Grimes register u_long dst; 491df8bae1dSRodney W. Grimes 492df8bae1dSRodney W. Grimes if (so->so_state & SS_ISCONNECTED) { 493df8bae1dSRodney W. Grimes if (nam) { 494df8bae1dSRodney W. Grimes error = EISCONN; 495df8bae1dSRodney W. Grimes break; 496df8bae1dSRodney W. Grimes } 497df8bae1dSRodney W. Grimes dst = inp->inp_faddr.s_addr; 498df8bae1dSRodney W. Grimes } else { 499df8bae1dSRodney W. Grimes if (nam == NULL) { 500df8bae1dSRodney W. Grimes error = ENOTCONN; 501df8bae1dSRodney W. Grimes break; 502df8bae1dSRodney W. Grimes } 503df8bae1dSRodney W. Grimes dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 504df8bae1dSRodney W. Grimes } 505df8bae1dSRodney W. Grimes error = rip_output(m, so, dst); 506df8bae1dSRodney W. Grimes m = NULL; 507df8bae1dSRodney W. Grimes break; 508df8bae1dSRodney W. Grimes } 509df8bae1dSRodney W. Grimes 510df8bae1dSRodney W. Grimes case PRU_SENSE: 511df8bae1dSRodney W. Grimes /* 512df8bae1dSRodney W. Grimes * stat: don't bother with a blocksize. 513df8bae1dSRodney W. Grimes */ 514df8bae1dSRodney W. Grimes return (0); 515df8bae1dSRodney W. Grimes 516df8bae1dSRodney W. Grimes /* 517df8bae1dSRodney W. Grimes * Not supported. 518df8bae1dSRodney W. Grimes */ 519df8bae1dSRodney W. Grimes case PRU_RCVOOB: 520df8bae1dSRodney W. Grimes case PRU_RCVD: 521df8bae1dSRodney W. Grimes case PRU_LISTEN: 522df8bae1dSRodney W. Grimes case PRU_ACCEPT: 523df8bae1dSRodney W. Grimes case PRU_SENDOOB: 524df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 525df8bae1dSRodney W. Grimes break; 526df8bae1dSRodney W. Grimes 527df8bae1dSRodney W. Grimes case PRU_SOCKADDR: 528df8bae1dSRodney W. Grimes in_setsockaddr(inp, nam); 529df8bae1dSRodney W. Grimes break; 530df8bae1dSRodney W. Grimes 531df8bae1dSRodney W. Grimes case PRU_PEERADDR: 532df8bae1dSRodney W. Grimes in_setpeeraddr(inp, nam); 533df8bae1dSRodney W. Grimes break; 534df8bae1dSRodney W. Grimes 535df8bae1dSRodney W. Grimes default: 536df8bae1dSRodney W. Grimes panic("rip_usrreq"); 537df8bae1dSRodney W. Grimes } 538df8bae1dSRodney W. Grimes if (m != NULL) 539df8bae1dSRodney W. Grimes m_freem(m); 540df8bae1dSRodney W. Grimes return (error); 541df8bae1dSRodney W. Grimes } 542