raw_ip.c revision 117737
1139804Simp/* 299026Sjulian * Copyright (c) 1982, 1986, 1988, 1993 399026Sjulian * The Regents of the University of California. All rights reserved. 499026Sjulian * 599026Sjulian * Redistribution and use in source and binary forms, with or without 699026Sjulian * modification, are permitted provided that the following conditions 799026Sjulian * are met: 899026Sjulian * 1. Redistributions of source code must retain the above copyright 999026Sjulian * notice, this list of conditions and the following disclaimer. 10124350Sschweikh * 2. Redistributions in binary form must reproduce the above copyright 1199026Sjulian * notice, this list of conditions and the following disclaimer in the 1299026Sjulian * documentation and/or other materials provided with the distribution. 1399026Sjulian * 3. All advertising materials mentioning features or use of this software 1499026Sjulian * must display the following acknowledgement: 1599026Sjulian * This product includes software developed by the University of 1699026Sjulian * California, Berkeley and its contributors. 1799026Sjulian * 4. Neither the name of the University nor the names of its contributors 1899026Sjulian * may be used to endorse or promote products derived from this software 1999026Sjulian * without specific prior written permission. 2099026Sjulian * 2199026Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2299026Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2399026Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2499026Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2599026Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2699026Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2799026Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2899026Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29181695Sattilio * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30235459Srstone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31198464Sjkoshy * SUCH DAMAGE. 32181695Sattilio * 33116182Sobrien * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 34116182Sobrien * $FreeBSD: head/sys/netinet/raw_ip.c 117737 2003-07-18 16:10:36Z rwatson $ 35116182Sobrien */ 3699026Sjulian 3799026Sjulian#include "opt_inet6.h" 3899026Sjulian#include "opt_ipsec.h" 3999026Sjulian#include "opt_mac.h" 4099026Sjulian#include "opt_random_ip_id.h" 4199026Sjulian 42236317Skib#include <sys/param.h> 43156705Sdavidxu#include <sys/kernel.h> 44235459Srstone#include <sys/lock.h> 45130355Sjulian#include <sys/mac.h> 46107126Sjeff#include <sys/malloc.h> 47126326Sjhb#include <sys/mbuf.h> 48174647Sjeff#include <sys/proc.h> 49294614Sjhb#include <sys/protosw.h> 50293490Sdchagin#include <sys/signalvar.h> 51122514Sjhb#include <sys/socket.h> 5299026Sjulian#include <sys/socketvar.h> 53213642Sdavidxu#include <sys/sx.h> 54143149Sdavidxu#include <sys/sysctl.h> 55176730Sjeff#include <sys/systm.h> 56198464Sjkoshy 57198464Sjkoshy#include <vm/uma.h> 58198464Sjkoshy 5999026Sjulian#include <net/if.h> 60155195Srwatson#include <net/route.h> 61155195Srwatson 6299026Sjulian#include <netinet/in.h> 63116355Salc#include <netinet/in_systm.h> 6499026Sjulian#include <netinet/in_pcb.h> 65173631Srrs#include <netinet/in_var.h> 6699026Sjulian#include <netinet/ip.h> 67235459Srstone#include <netinet/ip_var.h> 68260817Savg#include <netinet/ip_mroute.h> 69235459Srstone 7099026Sjulian#include <netinet/ip_fw.h> 71163709Sjb#include <netinet/ip_dummynet.h> 72163709Sjb 7399026Sjulian#ifdef FAST_IPSEC 7499026Sjulian#include <netipsec/ipsec.h> 75111028Sjeff#endif /*FAST_IPSEC*/ 76172256Sattilio 77170296Sjeff#ifdef IPSEC 7899026Sjulian#include <netinet6/ipsec.h> 79170598Sjeff#endif /*IPSEC*/ 80283279Skib 81283279Skibstruct inpcbhead ripcb; 82170598Sjeffstruct inpcbinfo ripcbinfo; 83216314Sdavidxu 84216314Sdavidxu/* control hooks for ipfw and dummynet */ 85127794Smarcelip_fw_ctl_t *ip_fw_ctl_ptr; 86143802Sphkip_dn_ctl_t *ip_dn_ctl_ptr; 87216314Sdavidxu 88216314Sdavidxu/* 89213642Sdavidxu * hooks for multicast routing. They all default to NULL, 90213642Sdavidxu * so leave them not initialized and rely on BSS being set to 0. 91213642Sdavidxu */ 92213642Sdavidxu 93213642Sdavidxu/* The socket used to communicate with the multicast routing daemon. */ 94213642Sdavidxustruct socket *ip_mrouter; 95216314Sdavidxu 96216314Sdavidxu/* The various mrouter and rsvp functions */ 97216314Sdavidxuint (*ip_mrouter_set)(struct socket *, struct sockopt *); 98216314Sdavidxuint (*ip_mrouter_get)(struct socket *, struct sockopt *); 99216314Sdavidxuint (*ip_mrouter_done)(void); 100216314Sdavidxuint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 101216314Sdavidxu struct ip_moptions *); 102216314Sdavidxuint (*mrt_ioctl)(int, caddr_t); 103216314Sdavidxuint (*legal_vif_num)(int); 104216314Sdavidxuu_long (*ip_mcast_src)(int); 105216314Sdavidxu 106216314Sdavidxuvoid (*rsvp_input_p)(struct mbuf *m, int off); 107216314Sdavidxuint (*ip_rsvp_vif)(struct socket *, struct sockopt *); 108240951Skibvoid (*ip_rsvp_force_done)(struct socket *); 109240951Skib 110216314Sdavidxu/* 111216314Sdavidxu * Nominal space allocated to a raw ip socket. 112216314Sdavidxu */ 113216314Sdavidxu#define RIPSNDQ 8192 114216314Sdavidxu#define RIPRCVQ 8192 115216314Sdavidxu 116216314Sdavidxu/* 117216314Sdavidxu * Raw interface to IP protocol. 118216314Sdavidxu */ 119216314Sdavidxu 120216314Sdavidxu/* 121240951Skib * Initialize raw connection block q. 122240951Skib */ 123216314Sdavidxuvoid 124240951Skibrip_init() 125240951Skib{ 126216314Sdavidxu INP_INFO_LOCK_INIT(&ripcbinfo, "rip"); 127216314Sdavidxu LIST_INIT(&ripcb); 128216314Sdavidxu ripcbinfo.listhead = &ripcb; 129216314Sdavidxu /* 130216314Sdavidxu * XXX We don't use the hash list for raw IP, but it's easier 131127794Smarcel * to allocate a one entry hash list than it is to check all 132107719Sjulian * over the place for hashbase == NULL. 13399026Sjulian */ 134132987Sgreen ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask); 135132987Sgreen ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask); 13699026Sjulian ripcbinfo.ipi_zone = uma_zcreate("ripcb", sizeof(struct inpcb), 13799026Sjulian NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); 13899026Sjulian uma_zone_set_max(ripcbinfo.ipi_zone, maxsockets); 13999026Sjulian} 140103216Sjulian 141135573Sjhbstatic struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 142130269Sjmallett/* 143216314Sdavidxu * Setup generic address and protocol structures 144143840Sphk * for raw_input routine, then pass them along with 145130269Sjmallett * mbuf chain. 146130269Sjmallett */ 147130269Sjmallettvoid 148170296Sjeffrip_input(m, off) 149130269Sjmallett struct mbuf *m; 150118442Sjhb int off; 151216313Sdavidxu{ 152173631Srrs register struct ip *ip = mtod(m, struct ip *); 153155195Srwatson register struct inpcb *inp; 154155195Srwatson struct inpcb *last = 0; 155155195Srwatson struct mbuf *opts = 0; 156161678Sdavidxu int proto = ip->ip_p; 157132987Sgreen 15899026Sjulian ripsrc.sin_addr = ip->ip_src; 15999026Sjulian LIST_FOREACH(inp, &ripcb, inp_list) { 16099026Sjulian#ifdef INET6 16199026Sjulian if ((inp->inp_vflag & INP_IPV4) == 0) 16299026Sjulian continue; 16399026Sjulian#endif 16499026Sjulian if (inp->inp_ip_p && inp->inp_ip_p != proto) 16599026Sjulian continue; 166127794Smarcel if (inp->inp_laddr.s_addr && 16799026Sjulian inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 16899026Sjulian continue; 16999026Sjulian if (inp->inp_faddr.s_addr && 17099026Sjulian inp->inp_faddr.s_addr != ip->ip_src.s_addr) 17199026Sjulian continue; 17299026Sjulian if (last) { 173103216Sjulian struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 174103216Sjulian int policyfail = 0; 175103216Sjulian 17699026Sjulian if (n != NULL) { 17799026Sjulian#ifdef IPSEC 17899026Sjulian /* check AH/ESP integrity. */ 17999026Sjulian if (ipsec4_in_reject_so(n, last->inp_socket)) { 18099026Sjulian policyfail = 1; 18199026Sjulian ipsecstat.in_polvio++; 18299026Sjulian /* do not inject data to pcb */ 183103216Sjulian } 18499026Sjulian#endif /*IPSEC*/ 18599026Sjulian#ifdef FAST_IPSEC 18699026Sjulian /* check AH/ESP integrity. */ 18799026Sjulian if (ipsec4_in_reject(n, last)) { 18899026Sjulian policyfail = 1; 18999026Sjulian /* do not inject data to pcb */ 190155353Srwatson } 191155353Srwatson#endif /*FAST_IPSEC*/ 192155353Srwatson#ifdef MAC 193185029Spjd if (policyfail == 0 && 194185029Spjd mac_check_socket_deliver(last->inp_socket, 195185029Spjd n) != 0) 196173631Srrs policyfail = 1; 197216314Sdavidxu#endif 19899026Sjulian } 19999026Sjulian if (policyfail) 20099026Sjulian m_freem(n); 20199026Sjulian else if (n) { 20299026Sjulian if (last->inp_flags & INP_CONTROLOPTS || 203132987Sgreen last->inp_socket->so_options & SO_TIMESTAMP) 204132987Sgreen ip_savecontrol(last, &opts, ip, n); 20599026Sjulian if (sbappendaddr(&last->inp_socket->so_rcv, 206131149Smarcel (struct sockaddr *)&ripsrc, n, 20799026Sjulian opts) == 0) { 20899026Sjulian /* should notify about lost packet */ 209131149Smarcel m_freem(n); 210126326Sjhb if (opts) 211122514Sjhb m_freem(opts); 212236317Skib } else 213173631Srrs sorwakeup(last->inp_socket); 214107126Sjeff opts = 0; 215161678Sdavidxu } 216173361Skib } 217281979Skib last = inp; 218132987Sgreen } 21999026Sjulian if (last) { 22099026Sjulian#ifdef IPSEC 22199026Sjulian /* check AH/ESP integrity. */ 22299026Sjulian if (ipsec4_in_reject_so(m, last->inp_socket)) { 22399026Sjulian m_freem(m); 22499026Sjulian ipsecstat.in_polvio++; 22599026Sjulian ipstat.ips_delivered--; 22699026Sjulian /* do not inject data to pcb */ 227131149Smarcel return; 22899026Sjulian } 22999026Sjulian#endif /*IPSEC*/ 230173631Srrs#ifdef FAST_IPSEC 231236317Skib /* check AH/ESP integrity. */ 232122514Sjhb if (ipsec4_in_reject(m, last)) { 233126326Sjhb m_freem(m); 234161678Sdavidxu ipstat.ips_delivered--; 235174647Sjeff /* do not inject data to pcb */ 23699026Sjulian return; 237111028Sjeff } 238107126Sjeff#endif /*FAST_IPSEC*/ 239111028Sjeff#ifdef MAC 240111028Sjeff if (mac_check_socket_deliver(last->inp_socket, m) != 0) { 241134791Sjulian m_freem(m); 242134791Sjulian ipstat.ips_delivered--; 243134791Sjulian return; 244134791Sjulian } 245105854Sjulian#endif 246105854Sjulian if (last->inp_flags & INP_CONTROLOPTS || 247173361Skib last->inp_socket->so_options & SO_TIMESTAMP) 248173361Skib ip_savecontrol(last, &opts, ip, m); 249173361Skib if (sbappendaddr(&last->inp_socket->so_rcv, 250173361Skib (struct sockaddr *)&ripsrc, m, opts) == 0) { 251173361Skib m_freem(m); 252173361Skib if (opts) 253173361Skib m_freem(opts); 254163709Sjb } else 255105854Sjulian sorwakeup(last->inp_socket); 256170296Sjeff } else { 257151316Sdavidxu m_freem(m); 258153253Sdavidxu ipstat.ips_noproto++; 259153253Sdavidxu ipstat.ips_delivered--; 260153253Sdavidxu } 261153253Sdavidxu} 262152185Sdavidxu 263152948Sdavidxu/* 264105854Sjulian * Generate IP header and pass packet to ip_output. 265163709Sjb * Tack on options user may have setup with control call. 266105854Sjulian */ 267105854Sjulianint 268111028Sjeffrip_output(m, so, dst) 26999026Sjulian struct mbuf *m; 27099026Sjulian struct socket *so; 27199026Sjulian u_long dst; 27299026Sjulian{ 27399026Sjulian register struct ip *ip; 27499026Sjulian register struct inpcb *inp = sotoinpcb(so); 275143802Sphk int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 276239301Skib 277239301Skib#ifdef MAC 278239328Skib mac_create_mbuf_from_socket(so, m); 279239301Skib#endif 280239301Skib 281174848Sjulian /* 282143802Sphk * If the user handed us a complete IP packet, use it. 283107126Sjeff * Otherwise, allocate an mbuf for a header and fill it in. 28499026Sjulian */ 285290325Skib if ((inp->inp_flags & INP_HDRINCL) == 0) { 286213642Sdavidxu if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { 287213642Sdavidxu m_freem(m); 28899026Sjulian return(EMSGSIZE); 28999026Sjulian } 29099026Sjulian M_PREPEND(m, sizeof(struct ip), M_TRYWAIT); 291170598Sjeff ip = mtod(m, struct ip *); 292164936Sjulian ip->ip_tos = inp->inp_ip_tos; 29399026Sjulian ip->ip_off = 0; 29499026Sjulian ip->ip_p = inp->inp_ip_p; 295170598Sjeff ip->ip_len = m->m_pkthdr.len; 29699026Sjulian ip->ip_src = inp->inp_laddr; 297170296Sjeff ip->ip_dst.s_addr = dst; 298164936Sjulian ip->ip_ttl = inp->inp_ip_ttl; 299170296Sjeff } else { 30099026Sjulian if (m->m_pkthdr.len > IP_MAXPACKET) { 30199026Sjulian m_freem(m); 302103410Smini return(EMSGSIZE); 303170598Sjeff } 304170598Sjeff ip = mtod(m, struct ip *); 305170598Sjeff /* don't allow both user specified and setsockopt options, 306170598Sjeff and don't allow packet length sizes that will crash */ 307170598Sjeff if (((ip->ip_hl != (sizeof (*ip) >> 2)) 308170598Sjeff && inp->inp_options) 309170598Sjeff || (ip->ip_len > m->m_pkthdr.len) 310170598Sjeff || (ip->ip_len < (ip->ip_hl << 2))) { 311170598Sjeff m_freem(m); 312170598Sjeff return EINVAL; 313177091Sjeff } 31499026Sjulian if (ip->ip_id == 0) 31599026Sjulian#ifdef RANDOM_IP_ID 31699026Sjulian ip->ip_id = ip_randomid(); 31799026Sjulian#else 318105854Sjulian ip->ip_id = htons(ip_id++); 31999026Sjulian#endif 32099026Sjulian /* XXX prevent ip_output from overwriting header fields */ 321111028Sjeff flags |= IP_RAWOUTPUT; 322111028Sjeff ipstat.ips_rawout++; 32399026Sjulian } 324163709Sjb 325170296Sjeff return (ip_output(m, inp->inp_options, &inp->inp_route, flags, 326105854Sjulian inp->inp_moptions, inp)); 327105854Sjulian} 328105854Sjulian 329170296Sjeff/* 330105854Sjulian * Raw IP socket option processing. 331164936Sjulian * 332111028Sjeff * Note that access to all of the IP administrative functions here is 333111028Sjeff * implicitly protected by suser() as gaining access to a raw socket 334105854Sjulian * requires either that the thread pass a suser() check, or that it be 335105854Sjulian * passed a raw socket by another thread that has passed a suser() check. 33699026Sjulian * If FreeBSD moves to a more fine-grained access control mechanism, 33799026Sjulian * additional checks will need to be placed here if the raw IP attachment 33899026Sjulian * check is not equivilent the the check required for these 33999026Sjulian * administrative operations; in some cases, these checks are already 34099026Sjulian * present. 34199026Sjulian */ 34299026Sjulianint 34399026Sjulianrip_ctloutput(so, sopt) 344196730Skib struct socket *so; 34599026Sjulian struct sockopt *sopt; 346173361Skib{ 347163709Sjb struct inpcb *inp = sotoinpcb(so); 34899026Sjulian int error, optval; 349173361Skib 350173361Skib if (sopt->sopt_level != IPPROTO_IP) 351173361Skib return (EINVAL); 352196730Skib 353173361Skib error = 0; 354173361Skib 355173361Skib switch (sopt->sopt_dir) { 356173615Smarcel case SOPT_GET: 357173361Skib switch (sopt->sopt_name) { 35899026Sjulian case IP_HDRINCL: 35999026Sjulian optval = inp->inp_flags & INP_HDRINCL; 360196730Skib error = sooptcopyout(sopt, &optval, sizeof optval); 361196730Skib break; 362196730Skib 363103367Sjulian case IP_FW_ADD: /* ADD actually returns the body... */ 364196730Skib case IP_FW_GET: 365196730Skib if (IPFW_LOADED) 366196730Skib error = ip_fw_ctl_ptr(sopt); 367196730Skib else 368196730Skib error = ENOPROTOOPT; 369196730Skib break; 370196730Skib 371196730Skib case IP_DUMMYNET_GET: 372103367Sjulian if (DUMMYNET_LOADED) 37399026Sjulian error = ip_dn_ctl_ptr(sopt); 37499026Sjulian else 37599026Sjulian error = ENOPROTOOPT; 37699026Sjulian break ; 37799026Sjulian 378189845Sjeff case MRT_INIT: 379189845Sjeff case MRT_DONE: 380177369Sjeff case MRT_ADD_VIF: 381177369Sjeff case MRT_DEL_VIF: 382176730Sjeff case MRT_ADD_MFC: 383173615Smarcel case MRT_DEL_MFC: 384173361Skib case MRT_VERSION: 385173361Skib case MRT_ASSERT: 38699026Sjulian error = ip_mrouter_get ? ip_mrouter_get(so, sopt) : 38799026Sjulian EOPNOTSUPP; 38899026Sjulian break; 38999026Sjulian 39099026Sjulian default: 391130355Sjulian error = ip_ctloutput(so, sopt); 39299026Sjulian break; 39399026Sjulian } 394107719Sjulian break; 395107719Sjulian 396177091Sjeff case SOPT_SET: 39799026Sjulian switch (sopt->sopt_name) { 39899026Sjulian case IP_HDRINCL: 39999026Sjulian error = sooptcopyin(sopt, &optval, sizeof optval, 40099026Sjulian sizeof optval); 401229429Sjhb if (error) 40299026Sjulian break; 403170174Sjeff if (optval) 40499026Sjulian inp->inp_flags |= INP_HDRINCL; 405182011Sjhb else 40699026Sjulian inp->inp_flags &= ~INP_HDRINCL; 40799026Sjulian break; 40899026Sjulian 40999026Sjulian case IP_FW_ADD: 410170296Sjeff case IP_FW_DEL: 411134791Sjulian case IP_FW_FLUSH: 412170296Sjeff case IP_FW_ZERO: 413134791Sjulian case IP_FW_RESETLOG: 414102581Sjulian if (IPFW_LOADED) 415133234Srwatson error = ip_fw_ctl_ptr(sopt); 416173601Sjulian else 417151316Sdavidxu error = ENOPROTOOPT; 41899026Sjulian break; 419155376Srwatson 420155376Srwatson case IP_DUMMYNET_CONFIGURE: 421155376Srwatson case IP_DUMMYNET_DEL: 422134791Sjulian case IP_DUMMYNET_FLUSH: 423134791Sjulian if (DUMMYNET_LOADED) 424134791Sjulian error = ip_dn_ctl_ptr(sopt); 425134791Sjulian else 426134791Sjulian error = ENOPROTOOPT ; 42799026Sjulian break ; 42899026Sjulian 429134791Sjulian case IP_RSVP_ON: 430103002Sjulian error = ip_rsvp_init(so); 431103002Sjulian break; 432134791Sjulian 433134791Sjulian case IP_RSVP_OFF: 434134791Sjulian error = ip_rsvp_done(); 435134791Sjulian break; 436102581Sjulian 437134791Sjulian case IP_RSVP_VIF_ON: 438134791Sjulian case IP_RSVP_VIF_OFF: 439271372Skib error = ip_rsvp_vif ? 440134791Sjulian ip_rsvp_vif(so, sopt) : EINVAL; 441170174Sjeff break; 442170174Sjeff 443134791Sjulian case MRT_INIT: 444134791Sjulian case MRT_DONE: 445134791Sjulian case MRT_ADD_VIF: 446207606Skib case MRT_DEL_VIF: 447134791Sjulian case MRT_ADD_MFC: 448134791Sjulian case MRT_DEL_MFC: 449134791Sjulian case MRT_VERSION: 450134791Sjulian case MRT_ASSERT: 451170296Sjeff error = ip_mrouter_set ? ip_mrouter_set(so, sopt) : 452182011Sjhb EOPNOTSUPP; 453283279Skib break; 454170296Sjeff 455182011Sjhb default: 456182011Sjhb error = ip_ctloutput(so, sopt); 457134791Sjulian break; 458103002Sjulian } 459104695Sjulian break; 460134791Sjulian } 461134791Sjulian 462134791Sjulian return (error); 463134791Sjulian} 464134791Sjulian 465134791Sjulian/* 466119488Sdavidxu * This function exists solely to receive the PRC_IFDOWN messages which 467170296Sjeff * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa, 468198464Sjkoshy * and calls in_ifadown() to remove all routes corresponding to that address. 469198464Sjkoshy * It also receives the PRC_IFUP messages from if_up() and reinstalls the 470198464Sjkoshy * interface routes. 471198464Sjkoshy */ 472198464Sjkoshyvoid 473198464Sjkoshyrip_ctlinput(cmd, sa, vip) 474198464Sjkoshy int cmd; 475198464Sjkoshy struct sockaddr *sa; 476170296Sjeff void *vip; 477293473Sdchagin{ 478293473Sdchagin struct in_ifaddr *ia; 479293473Sdchagin struct ifnet *ifp; 480229429Sjhb int err; 481229429Sjhb int flags; 482229429Sjhb 483229429Sjhb switch (cmd) { 484229429Sjhb case PRC_IFDOWN: 485229429Sjhb TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 486229429Sjhb if (ia->ia_ifa.ifa_addr == sa 487229429Sjhb && (ia->ia_flags & IFA_ROUTE)) { 488229429Sjhb /* 489229429Sjhb * in_ifscrub kills the interface route. 490229429Sjhb */ 491229429Sjhb in_ifscrub(ia->ia_ifp, ia); 492208488Skib /* 493229429Sjhb * in_ifadown gets rid of all the rest of 494293473Sdchagin * the routes. This is not quite the right 495229429Sjhb * thing to do, but at least if we are running 496133396Sjulian * a routing process they will come back. 497181695Sattilio */ 498181695Sattilio in_ifadown(&ia->ia_ifa, 0); 499181695Sattilio break; 500133396Sjulian } 501170296Sjeff } 502112993Speter break; 50399026Sjulian 50499026Sjulian case PRC_IFUP: 50599026Sjulian TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 506124350Sschweikh if (ia->ia_ifa.ifa_addr == sa) 507107719Sjulian break; 508126932Speter } 509107719Sjulian if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) 510107719Sjulian return; 511107719Sjulian flags = RTF_UP; 512107719Sjulian ifp = ia->ia_ifa.ifa_ifp; 513107719Sjulian 514107719Sjulian if ((ifp->if_flags & IFF_LOOPBACK) 515126932Speter || (ifp->if_flags & IFF_POINTOPOINT)) 516271372Skib flags |= RTF_HOST; 517271372Skib 518170598Sjeff err = rtinit(&ia->ia_ifa, RTM_ADD, flags); 519170598Sjeff if (err == 0) 520170598Sjeff ia->ia_flags |= IFA_ROUTE; 521170598Sjeff break; 522189845Sjeff } 523176730Sjeff} 524176730Sjeff 525170598Sjeffu_long rip_sendspace = RIPSNDQ; 526170598Sjeffu_long rip_recvspace = RIPRCVQ; 527107719Sjulianint rip_olddiverterror = 1; 528107719Sjulian 529107719SjulianSYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, 53099026Sjulian &rip_sendspace, 0, "Maximum outgoing raw IP datagram size"); 53199026SjulianSYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, 532103002Sjulian &rip_recvspace, 0, "Maximum incoming raw IP datagram size"); 533103002SjulianSYSCTL_INT(_net_inet_raw, OID_AUTO, olddiverterror, CTLFLAG_RW, 53499026Sjulian &rip_olddiverterror, 0, "Return an error when creating an 'old' DIVERT socket"); 53599026Sjulian 536163709Sjbstatic int 53799026Sjulianrip_attach(struct socket *so, int proto, struct thread *td) 53899026Sjulian{ 539170296Sjeff struct inpcb *inp; 540170296Sjeff int error, s; 541177368Sjeff 542177368Sjeff inp = sotoinpcb(so); 543170296Sjeff if (inp) 544111028Sjeff panic("rip_attach"); 545111028Sjeff if (td && (error = suser(td)) != 0) 546172207Sjeff return error; 54799026Sjulian 548103002Sjulian if (proto >= IPPROTO_MAX || proto < 0) 549174629Sjeff return EPROTONOSUPPORT; 550174629Sjeff 551151316Sdavidxu /* To be removed before 5.2 */ 552119137Ssam if (rip_olddiverterror && proto == IPPROTO_OLD_DIVERT) { 55399026Sjulian printf("Old IPDIVERT program needs to be recompiled, or new IP proto 254 user needs sysctl net.inet.raw.olddiverterror=0\n"); 55499026Sjulian return EPROTONOSUPPORT; 55599026Sjulian } 55699026Sjulian 557134791Sjulian error = soreserve(so, rip_sendspace, rip_recvspace); 558136160Sjulian if (error) 559134791Sjulian return error; 560134791Sjulian s = splnet(); 561113641Sjulian error = in_pcballoc(so, &ripcbinfo, td); 562113641Sjulian splx(s); 563124350Sschweikh if (error) 564113641Sjulian return error; 565113920Sjhb inp = (struct inpcb *)so->so_pcb; 566177368Sjeff inp->inp_vflag |= INP_IPV4; 567113641Sjulian inp->inp_ip_p = proto; 568113641Sjulian inp->inp_ip_ttl = ip_defttl; 569113641Sjulian return 0; 570163709Sjb} 571124350Sschweikh 572113641Sjulianstatic int 573195701Skibrip_detach(struct socket *so) 574195701Skib{ 575195701Skib struct inpcb *inp; 576195701Skib 577195701Skib inp = sotoinpcb(so); 578227657Skib if (inp == 0) 579227657Skib panic("rip_detach"); 580195701Skib if (so == ip_mrouter && ip_mrouter_done) 581195701Skib ip_mrouter_done(); 582195701Skib if (ip_rsvp_force_done) 583195701Skib ip_rsvp_force_done(so); 584276272Skib if (so == ip_rsvpd) 585195701Skib ip_rsvp_done(); 586195701Skib in_pcbdetach(inp); 587195701Skib return 0; 588195701Skib} 589195701Skib 590195701Skibstatic int 591275795Skibrip_abort(struct socket *so) 592275795Skib{ 593275795Skib soisdisconnected(so); 594275795Skib if (so->so_state & SS_NOFDREF) 595276272Skib return rip_detach(so); 596275795Skib return 0; 597275795Skib} 598275795Skib 599275795Skibstatic int 600275795Skibrip_disconnect(struct socket *so) 601275795Skib{ 602275795Skib if ((so->so_state & SS_ISCONNECTED) == 0) 603275795Skib return ENOTCONN; 604275795Skib return rip_abort(so); 605275795Skib} 606275795Skib 607275795Skibstatic int 608275795Skibrip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 609275795Skib{ 610275795Skib struct inpcb *inp = sotoinpcb(so); 611283279Skib struct sockaddr_in *addr = (struct sockaddr_in *)nam; 612275795Skib 613275795Skib if (nam->sa_len != sizeof(*addr)) 614275795Skib return EINVAL; 615275795Skib 616275795Skib if (TAILQ_EMPTY(&ifnet) || ((addr->sin_family != AF_INET) && 617283279Skib (addr->sin_family != AF_IMPLINK)) || 618275795Skib (addr->sin_addr.s_addr && 619275795Skib ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 620275795Skib return EADDRNOTAVAIL; 621275795Skib inp->inp_laddr = addr->sin_addr; 622275795Skib return 0; 623283279Skib} 624275795Skib 625275795Skibstatic int 626275795Skibrip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 627276272Skib{ 628276272Skib struct inpcb *inp = sotoinpcb(so); 629276272Skib struct sockaddr_in *addr = (struct sockaddr_in *)nam; 630276272Skib 631276272Skib if (nam->sa_len != sizeof(*addr)) 632276272Skib return EINVAL; 633276272Skib if (TAILQ_EMPTY(&ifnet)) 634276272Skib return EADDRNOTAVAIL; 635276272Skib if ((addr->sin_family != AF_INET) && 636276272Skib (addr->sin_family != AF_IMPLINK)) 637276272Skib return EAFNOSUPPORT; 638283279Skib inp->inp_faddr = addr->sin_addr; 639276272Skib soisconnected(so); 640276272Skib return 0; 641276272Skib} 642276272Skib 643276272Skibstatic int 644276272Skibrip_shutdown(struct socket *so) 645276272Skib{ 646276272Skib socantsendmore(so); 647276272Skib return 0; 648275795Skib} 649275795Skib 650275795Skibstatic int 651275795Skibrip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 652111028Sjeff struct mbuf *control, struct thread *td) 65399026Sjulian{ 65499026Sjulian struct inpcb *inp = sotoinpcb(so); 65599026Sjulian register u_long dst; 65699026Sjulian 65799026Sjulian if (so->so_state & SS_ISCONNECTED) { 65899026Sjulian if (nam) { 65999026Sjulian m_freem(m); 66099026Sjulian return EISCONN; 66199026Sjulian } 662160048Smaxim dst = inp->inp_faddr.s_addr; 66399026Sjulian } else { 66499026Sjulian if (nam == NULL) { 66599026Sjulian m_freem(m); 666276272Skib return ENOTCONN; 66799026Sjulian } 66899026Sjulian dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr; 66999026Sjulian } 670181334Sjhb return rip_output(m, so, dst); 67199026Sjulian} 67299026Sjulian 673276272Skibstatic int 674276272Skibrip_pcblist(SYSCTL_HANDLER_ARGS) 675276272Skib{ 676276272Skib int error, i, n, s; 677276272Skib struct inpcb *inp, **inp_list; 678276272Skib inp_gen_t gencnt; 679276272Skib struct xinpgen xig; 680276272Skib 681276272Skib /* 682276272Skib * The process of preparing the TCB list is too time-consuming and 683276272Skib * resource-intensive to repeat twice on every request. 684276272Skib */ 685126932Speter if (req->oldptr == 0) { 68699026Sjulian n = ripcbinfo.ipi_count; 68799026Sjulian req->oldidx = 2 * (sizeof xig) 688276272Skib + (n + n/8) * sizeof(struct xinpcb); 68999026Sjulian return 0; 69099026Sjulian } 691100648Sjulian 692136177Sdavidxu if (req->newptr != 0) 69399026Sjulian return EPERM; 69499026Sjulian 695136177Sdavidxu /* 696136177Sdavidxu * OK, now we're committed to doing something. 697136177Sdavidxu */ 698136177Sdavidxu s = splnet(); 699136177Sdavidxu gencnt = ripcbinfo.ipi_gencnt; 700136177Sdavidxu n = ripcbinfo.ipi_count; 701136177Sdavidxu splx(s); 702136177Sdavidxu 703136177Sdavidxu xig.xig_len = sizeof xig; 704136177Sdavidxu xig.xig_count = n; 705276272Skib xig.xig_gen = gencnt; 706276272Skib xig.xig_sogen = so_gencnt; 707102950Sdavidxu error = SYSCTL_OUT(req, &xig, sizeof xig); 708184667Sdavidxu if (error) 70999026Sjulian return error; 710195701Skib 711275795Skib inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); 712156942Sdavidxu if (inp_list == 0) 713156942Sdavidxu return ENOMEM; 714181334Sjhb 71599026Sjulian s = splnet(); 71699026Sjulian for (inp = LIST_FIRST(ripcbinfo.listhead), i = 0; inp && i < n; 71799026Sjulian inp = LIST_NEXT(inp, inp_list)) { 718170296Sjeff if (inp->inp_gencnt <= gencnt) { 719177471Sjeff if (cr_canseesocket(req->td->td_ucred, 720276272Skib inp->inp_socket)) 721275795Skib continue; 722155594Sdavidxu inp_list[i++] = inp; 723276272Skib } 724155594Sdavidxu } 725276272Skib splx(s); 726155594Sdavidxu n = i; 727170296Sjeff 72899026Sjulian error = 0; 729181334Sjhb for (i = 0; i < n; i++) { 730181334Sjhb inp = inp_list[i]; 731195701Skib if (inp->inp_gencnt <= gencnt) { 732130674Sdavidxu struct xinpcb xi; 733124350Sschweikh xi.xi_len = sizeof xi; 734124350Sschweikh /* XXX should avoid extra copy */ 735105911Sjulian bcopy(inp, &xi.xi_inp, sizeof *inp); 736275795Skib if (inp->inp_socket) 737105911Sjulian sotoxsocket(inp->inp_socket, &xi.xi_socket); 738105911Sjulian error = SYSCTL_OUT(req, &xi, sizeof xi); 739156942Sdavidxu } 74099026Sjulian } 74199026Sjulian if (!error) { 742100648Sjulian /* 74399026Sjulian * Give the user an updated idea of our state. 744276272Skib * If the generation differs from what we told 745195701Skib * her before, she knows that something happened 74699026Sjulian * while we were processing this request, and it 747136177Sdavidxu * might be necessary to retry. 748135269Sjulian */ 749271372Skib s = splnet(); 750271372Skib xig.xig_gen = ripcbinfo.ipi_gencnt; 751271372Skib xig.xig_sogen = so_gencnt; 752135269Sjulian xig.xig_count = ripcbinfo.ipi_count; 753271372Skib splx(s); 754136160Sjulian error = SYSCTL_OUT(req, &xig, sizeof xig); 755271372Skib } 756271372Skib free(inp_list, M_TEMP); 757271372Skib return error; 758271372Skib} 759271372Skib 760271372Skib/* 761271372Skib * This is the wrapper function for in_setsockaddr. We just pass down 762271372Skib * the pcbinfo for in_setpeeraddr to lock. 763271372Skib */ 764271372Skibstatic int 765271372Skibrip_sockaddr(struct socket *so, struct sockaddr **nam) 766271372Skib{ 767283004Skib return (in_setsockaddr(so, nam, &ripcbinfo)); 768283004Skib} 769283004Skib 770283004Skib/* 771283004Skib * This is the wrapper function for in_setpeeraddr. We just pass down 772283004Skib * the pcbinfo for in_setpeeraddr to lock. 773283004Skib */ 774283004Skibstatic int 775283004Skibrip_peeraddr(struct socket *so, struct sockaddr **nam) 776283004Skib{ 777283004Skib return (in_setpeeraddr(so, nam, &ripcbinfo)); 778283004Skib} 779283004Skib 780283004Skib 781283004SkibSYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0, 782283004Skib rip_pcblist, "S,xinpcb", "List of active raw IP sockets"); 783283004Skib 784283004Skibstruct pr_usrreqs rip_usrreqs = { 785283004Skib rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect, 786283004Skib pru_connect2_notsupp, in_control, rip_detach, rip_disconnect, 787283004Skib pru_listen_notsupp, rip_peeraddr, pru_rcvd_notsupp, 788283004Skib pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown, 789283004Skib rip_sockaddr, sosend, soreceive, sopoll 790111028Sjeff}; 791184667Sdavidxu