ip_divert.c revision 82884
139287Ssos/* 239643Syokota * Copyright (c) 1982, 1986, 1988, 1993 339287Ssos * The Regents of the University of California. All rights reserved. 439287Ssos * 5146736Sdelphij * Redistribution and use in source and binary forms, with or without 6146736Sdelphij * modification, are permitted provided that the following conditions 7146736Sdelphij * are met: 839287Ssos * 1. Redistributions of source code must retain the above copyright 939287Ssos * notice, this list of conditions and the following disclaimer. 1039287Ssos * 2. Redistributions in binary form must reproduce the above copyright 1139287Ssos * notice, this list of conditions and the following disclaimer in the 1239643Syokota * documentation and/or other materials provided with the distribution. 1339643Syokota * 3. All advertising materials mentioning features or use of this software 1439287Ssos * must display the following acknowledgement: 1539287Ssos * This product includes software developed by the University of 1639287Ssos * California, Berkeley and its contributors. 1739287Ssos * 4. Neither the name of the University nor the names of its contributors 1839643Syokota * may be used to endorse or promote products derived from this software 1939643Syokota * without specific prior written permission. 2039643Syokota * 2139643Syokota * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2239643Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2339643Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2439643Syokota * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2539643Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2639643Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2739643Syokota * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2839287Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2939287Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30119420Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31119420Sobrien * SUCH DAMAGE. 32119420Sobrien * 33162711Sru * $FreeBSD: head/sys/netinet/ip_divert.c 82884 2001-09-03 20:03:55Z julian $ 3439287Ssos */ 3539287Ssos 3639287Ssos#include "opt_inet.h" 3739287Ssos#include "opt_ipfw.h" 3851404Syokota#include "opt_ipdivert.h" 3939287Ssos#include "opt_ipsec.h" 4039287Ssos 4139287Ssos#ifndef INET 4266834Sphk#error "IPDIVERT requires INET." 4366834Sphk#endif 4491140Stanimura 4591140Stanimura#include <sys/param.h> 4691140Stanimura#include <sys/kernel.h> 4791140Stanimura#include <sys/malloc.h> 4891140Stanimura#include <sys/mbuf.h> 4939287Ssos#include <sys/socket.h> 5042504Syokota#include <sys/protosw.h> 5142504Syokota#include <sys/socketvar.h> 5239287Ssos#include <sys/sysctl.h> 5378161Speter#include <sys/systm.h> 5478161Speter 5542504Syokota#include <vm/vm_zone.h> 5648104Syokota 5742504Syokota#include <net/if.h> 5842504Syokota#include <net/route.h> 5942504Syokota 6042504Syokota#include <netinet/in.h> 6148104Syokota#include <netinet/in_systm.h> 6242504Syokota#include <netinet/ip.h> 6342504Syokota#include <netinet/in_pcb.h> 6442504Syokota#include <netinet/in_var.h> 6542504Syokota#include <netinet/ip_var.h> 6642504Syokota 6742504Syokota/* 6842504Syokota * Divert sockets 6942504Syokota */ 7048104Syokota 7142504Syokota/* 7242504Syokota * Allocate enough space to hold a full IP packet 7342504Syokota */ 7442504Syokota#define DIVSNDQ (65536 + 100) 7542504Syokota#define DIVRCVQ (65536 + 100) 7642504Syokota 7742504Syokota/* 7842504Syokota * A 16 bit cookie is passed to and from the user process. 7942504Syokota * The user process can send it back to help the caller know 8042504Syokota * something about where the packet originally came from. 8139287Ssos * 8242504Syokota * In the case of ipfw, then the cookie is the rule that sent 8342504Syokota * us here. On reinjection is is the rule after which processing 8448104Syokota * should continue. Leaving it the same will make processing start 8548104Syokota * at the rule number after that which sent it here. Setting it to 8648104Syokota * 0 will restart processing at the beginning. 8748104Syokota * 8848104Syokota * For divert_packet(), ip_divert_cookie is an input value only. 8948104Syokota * For div_output(), ip_divert_cookie is an output value only. 9048104Syokota */ 9148104Syokotau_int16_t ip_divert_cookie; 9248104Syokota 9348104Syokota/* Internal variables */ 9448104Syokotastatic struct inpcbhead divcb; 9548104Syokotastatic struct inpcbinfo divcbinfo; 9648104Syokota 9748104Syokotastatic u_long div_sendspace = DIVSNDQ; /* XXX sysctl ? */ 9848104Syokotastatic u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */ 99132107Sstefanf 10048104Syokota/* Optimization: have this preinitialized */ 10148104Syokotastatic struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET }; 10248104Syokota 10348104Syokota/* Internal functions */ 10448104Syokotastatic int div_output(struct socket *so, 10548104Syokota struct mbuf *m, struct sockaddr *addr, struct mbuf *control); 10639287Ssos 10748104Syokota/* 10848104Syokota * Initialize divert connection block queue. 10948104Syokota */ 11048104Syokotavoid 11148104Syokotadiv_init(void) 11248104Syokota{ 11348104Syokota LIST_INIT(&divcb); 11448104Syokota divcbinfo.listhead = &divcb; 11548104Syokota /* 11648104Syokota * XXX We don't use the hash list for divert IP, but it's easier 11748104Syokota * to allocate a one entry hash list than it is to check all 11848104Syokota * over the place for hashbase == NULL. 11948104Syokota */ 12048104Syokota divcbinfo.hashbase = hashinit(1, M_PCB, &divcbinfo.hashmask); 12148104Syokota divcbinfo.porthashbase = hashinit(1, M_PCB, &divcbinfo.porthashmask); 12248104Syokota divcbinfo.ipi_zone = zinit("divcb", sizeof(struct inpcb), 12348104Syokota maxsockets, ZONE_INTERRUPT, 0); 12448104Syokota} 12548104Syokota 12648104Syokota/* 12748104Syokota * IPPROTO_DIVERT is not a real IP protocol; don't allow any packets 12848104Syokota * with that protocol number to enter the system from the outside. 12948104Syokota */ 13048104Syokotavoid 13148104Syokotadiv_input(struct mbuf *m, int off) 13248104Syokota{ 13348104Syokota ipstat.ips_noproto++; 13448104Syokota m_freem(m); 13539287Ssos} 13639287Ssos 137149640Srodrigc/* 13839287Ssos * Divert a packet by passing it up to the divert socket at port 'port'. 13939287Ssos * 140242529Sed * Setup generic address and protocol structures for div_input routine, 14148104Syokota * then pass them along with mbuf chain. 14248667Syokota */ 14339287Ssosvoid 14439287Ssosdivert_packet(struct mbuf *m, int incoming, int port) 14539287Ssos{ 146174985Swkoszek struct ip *ip; 14739287Ssos struct inpcb *inp; 14848104Syokota struct socket *sa; 14939287Ssos u_int16_t nport; 150149828Srodrigc 151149828Srodrigc /* Sanity check */ 15239287Ssos KASSERT(port != 0, ("%s: port=0", __FUNCTION__)); 15339287Ssos 154216079Sjkim /* Record and reset divert cookie */ 15539287Ssos divsrc.sin_port = ip_divert_cookie; 156216079Sjkim ip_divert_cookie = 0; 15739287Ssos 158216079Sjkim /* Assure header */ 15939287Ssos if (m->m_len < sizeof(struct ip) && 16048104Syokota (m = m_pullup(m, sizeof(struct ip))) == 0) { 161216079Sjkim return; 162216079Sjkim } 163216079Sjkim ip = mtod(m, struct ip *); 164216079Sjkim 165216079Sjkim /* 166216079Sjkim * Record receive interface address, if any. 167216079Sjkim * But only for incoming packets. 168216079Sjkim */ 169216079Sjkim divsrc.sin_addr.s_addr = 0; 17048104Syokota if (incoming) { 171216079Sjkim struct ifaddr *ifa; 172216079Sjkim 173216079Sjkim /* Sanity check */ 174216079Sjkim KASSERT((m->m_flags & M_PKTHDR), ("%s: !PKTHDR", __FUNCTION__)); 175216079Sjkim 176216079Sjkim /* Find IP address for receive interface */ 177216079Sjkim TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 17848104Syokota if (ifa->ifa_addr == NULL) 179216079Sjkim continue; 18048104Syokota if (ifa->ifa_addr->sa_family != AF_INET) 18139287Ssos continue; 18239287Ssos divsrc.sin_addr = 18339287Ssos ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; 18439287Ssos break; 18539287Ssos } 18639287Ssos } 18739287Ssos /* 18839287Ssos * Record the incoming interface name whenever we have one. 18939287Ssos */ 19039287Ssos bzero(&divsrc.sin_zero, sizeof(divsrc.sin_zero)); 19139287Ssos if (m->m_pkthdr.rcvif) { 19239287Ssos /* 19356043Syokota * Hide the actual interface name in there in the 19448104Syokota * sin_zero array. XXX This needs to be moved to a 19548104Syokota * different sockaddr type for divert, e.g. 19648104Syokota * sockaddr_div with multiple fields like 19748104Syokota * sockaddr_dl. Presently we have only 7 bytes 19839287Ssos * but that will do for now as most interfaces 19951394Syokota * are 4 or less + 2 or less bytes for unit. 20051394Syokota * There is probably a faster way of doing this, 20151394Syokota * possibly taking it from the sockaddr_dl on the iface. 20251394Syokota * This solves the problem of a P2P link and a LAN interface 20348667Syokota * having the same address, which can result in the wrong 20439287Ssos * interface being assigned to the packet when fed back 20539287Ssos * into the divert socket. Theoretically if the daemon saves 20639287Ssos * and re-uses the sockaddr_in as suggested in the man pages, 20739287Ssos * this iface name will come along for the ride. 20858872Syokota * (see div_output for the other half of this.) 20958872Syokota */ 21039287Ssos snprintf(divsrc.sin_zero, sizeof(divsrc.sin_zero), 21139287Ssos "%s%d", m->m_pkthdr.rcvif->if_name, 21239287Ssos m->m_pkthdr.rcvif->if_unit); 21342504Syokota } 21442504Syokota 21539287Ssos /* Put packet on socket queue, if any */ 21639287Ssos sa = NULL; 21748104Syokota nport = htons((u_int16_t)port); 21848104Syokota LIST_FOREACH(inp, &divcb, inp_list) { 219149640Srodrigc if (inp->inp_lport == nport) 22039287Ssos sa = inp->inp_socket; 22139287Ssos } 22239287Ssos if (sa) { 22356043Syokota if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc, 22448104Syokota m, (struct mbuf *)0) == 0) 22548104Syokota m_freem(m); 22648104Syokota else 22748104Syokota sorwakeup(sa); 22848667Syokota } else { 22948104Syokota m_freem(m); 23039287Ssos ipstat.ips_noproto++; 23139287Ssos ipstat.ips_delivered--; 23248104Syokota } 23339287Ssos} 23439287Ssos 23539287Ssos/* 23639287Ssos * Deliver packet back into the IP processing machinery. 23739287Ssos * 238242529Sed * If no address specified, or address is 0.0.0.0, send to ip_output(); 239242529Sed * otherwise, send to ip_input() and mark as having been received on 240242529Sed * the interface with that address. 24139287Ssos */ 24239287Ssosstatic int 24339287Ssosdiv_output(so, m, addr, control) 24439287Ssos struct socket *so; 24539287Ssos register struct mbuf *m; 24639287Ssos struct sockaddr *addr; 24748104Syokota struct mbuf *control; 24848104Syokota{ 24948104Syokota register struct inpcb *const inp = sotoinpcb(so); 25039287Ssos register struct ip *const ip = mtod(m, struct ip *); 251242529Sed struct sockaddr_in *sin = (struct sockaddr_in *)addr; 25239287Ssos int error = 0; 25339287Ssos 25439287Ssos if (control) 255174985Swkoszek m_freem(control); /* XXX */ 25639287Ssos 25739287Ssos /* Loopback avoidance and state recovery */ 25839287Ssos if (sin) { 25939287Ssos int len = 0; 26039287Ssos char *c = sin->sin_zero; 26139287Ssos 26239287Ssos ip_divert_cookie = sin->sin_port; 26339287Ssos 26439287Ssos /* 26556043Syokota * Find receive interface with the given name or IP address. 26648104Syokota * The name is user supplied data so don't trust it's size or 26748104Syokota * that it is zero terminated. The name has priority. 26848104Syokota * We are presently assuming that the sockaddr_in 26948104Syokota * has not been replaced by a sockaddr_div, so we limit it 27039287Ssos * to 16 bytes in total. the name is stuffed (if it exists) 27158872Syokota * in the sin_zero[] field. 27258872Syokota */ 27339287Ssos while (*c++ && (len++ < sizeof(sin->sin_zero))); 27450447Syokota if ((len > 0) && (len < sizeof(sin->sin_zero))) 27550447Syokota m->m_pkthdr.rcvif = ifunit(sin->sin_zero); 27650447Syokota } else { 27750447Syokota ip_divert_cookie = 0; 27842504Syokota } 27942504Syokota 28039287Ssos /* Reinject packet into the system as incoming or outgoing */ 28139287Ssos if (!sin || sin->sin_addr.s_addr == 0) { 28248104Syokota /* 28356328Syokota * Don't allow both user specified and setsockopt options, 28448104Syokota * and don't allow packet length sizes that will crash 28539287Ssos */ 28648104Syokota if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) || 28748104Syokota ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { 28856043Syokota error = EINVAL; 28939287Ssos goto cantsend; 29039287Ssos } 29148104Syokota 29239287Ssos /* Convert fields to host order for ip_output() */ 29339287Ssos NTOHS(ip->ip_len); 29439287Ssos NTOHS(ip->ip_off); 29539287Ssos 29639287Ssos /* Send packet to output processing */ 29739287Ssos ipstat.ips_rawout++; /* XXX */ 298242529Sed error = ip_output(m, inp->inp_options, &inp->inp_route, 299242529Sed (so->so_options & SO_DONTROUTE) | 300242529Sed IP_ALLOWBROADCAST | IP_RAWOUTPUT, 30139287Ssos inp->inp_moptions); 30248104Syokota } else { 30339287Ssos struct ifaddr *ifa; 30439287Ssos 30539287Ssos /* If no luck with the name above. check by IP address. */ 30639287Ssos if (m->m_pkthdr.rcvif == NULL) { 307149640Srodrigc /* 30839287Ssos * Make sure there are no distractions 30948104Syokota * for ifa_ifwithaddr. Clear the port and the ifname. 31048104Syokota * Maybe zap all 8 bytes at once using a 64bit write? 31148104Syokota */ 31239287Ssos bzero(sin->sin_zero, sizeof(sin->sin_zero)); 313242529Sed /* *((u_int64_t *)sin->sin_zero) = 0; */ /* XXX ?? */ 31448104Syokota sin->sin_port = 0; 31548667Syokota if (!(ifa = ifa_ifwithaddr((struct sockaddr *) sin))) { 31639287Ssos error = EADDRNOTAVAIL; 31739287Ssos goto cantsend; 31839287Ssos } 319174985Swkoszek m->m_pkthdr.rcvif = ifa->ifa_ifp; 32039287Ssos } 32139287Ssos 32239287Ssos /* Send packet to input processing */ 32356328Syokota ip_input(m); 32439287Ssos } 325216079Sjkim 32639287Ssos /* paranoid: Reset for next time (and other packets) */ 327216079Sjkim /* almost definitly already done in the ipfw filter but.. */ 32839287Ssos ip_divert_cookie = 0; 329216079Sjkim return error; 33039287Ssos 33148104Syokotacantsend: 332216079Sjkim m_freem(m); 333216079Sjkim ip_divert_cookie = 0; 334216079Sjkim return error; 335216079Sjkim} 336216079Sjkim 337216079Sjkimstatic int 338216079Sjkimdiv_attach(struct socket *so, int proto, struct proc *p) 339216079Sjkim{ 340216079Sjkim struct inpcb *inp; 34148104Syokota int error, s; 342216079Sjkim 343216079Sjkim inp = sotoinpcb(so); 344216079Sjkim if (inp) 345216079Sjkim panic("div_attach"); 346216079Sjkim if (p && (error = suser(p)) != 0) 347216079Sjkim return error; 348216079Sjkim 34948104Syokota error = soreserve(so, div_sendspace, div_recvspace); 350216079Sjkim if (error) 35148104Syokota return error; 35239287Ssos s = splnet(); 35339287Ssos error = in_pcballoc(so, &divcbinfo, p); 35439287Ssos splx(s); 35539287Ssos if (error) 35639287Ssos return error; 35739591Syokota inp = (struct inpcb *)so->so_pcb; 35839591Syokota inp->inp_ip_p = proto; 35939591Syokota inp->inp_vflag |= INP_IPV4; 360204281Sjkim inp->inp_flags |= INP_HDRINCL; 36139591Syokota /* The socket is always "connected" because 36239591Syokota we always know "where" to send the packet */ 36339287Ssos so->so_state |= SS_ISCONNECTED; 36439287Ssos return 0; 36539287Ssos} 36639287Ssos 36739287Ssosstatic int 36839287Ssosdiv_detach(struct socket *so) 36939287Ssos{ 37056043Syokota struct inpcb *inp; 37148104Syokota 37248104Syokota inp = sotoinpcb(so); 37348104Syokota if (inp == 0) 37448104Syokota panic("div_detach"); 37556043Syokota in_pcbdetach(inp); 37656043Syokota return 0; 37756043Syokota} 37856043Syokota 37956043Syokotastatic int 38056043Syokotadiv_abort(struct socket *so) 38156043Syokota{ 38239287Ssos soisdisconnected(so); 38351394Syokota return div_detach(so); 38451394Syokota} 38551394Syokota 38651394Syokotastatic int 38748667Syokotadiv_disconnect(struct socket *so) 38858872Syokota{ 38958872Syokota if ((so->so_state & SS_ISCONNECTED) == 0) 39039287Ssos return ENOTCONN; 39139287Ssos return div_abort(so); 39239287Ssos} 39339287Ssos 39448104Syokotastatic int 39548104Syokotadiv_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 396149640Srodrigc{ 39739287Ssos struct inpcb *inp; 39839287Ssos int s; 39939287Ssos int error; 40056043Syokota 40148104Syokota s = splnet(); 40248104Syokota inp = sotoinpcb(so); 40348104Syokota /* in_pcbbind assumes that the socket is a sockaddr_in 40448104Syokota * and in_pcbbind requires a valid address. Since divert 40548667Syokota * sockets don't we need to make sure the address is 40648104Syokota * filled in properly. 40739287Ssos * XXX -- divert should not be abusing in_pcbind 40839287Ssos * and should probably have its own family. 40948104Syokota */ 41056043Syokota if (nam->sa_family != AF_INET) { 41148104Syokota error = EAFNOSUPPORT; 41248104Syokota } else { 41339287Ssos ((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY; 41439287Ssos error = in_pcbbind(inp, nam, p); 41539287Ssos } 41639287Ssos splx(s); 41739287Ssos return error; 418242529Sed} 419242529Sed 420242529Sedstatic int 42139287Ssosdiv_shutdown(struct socket *so) 42248104Syokota{ 42339287Ssos socantsendmore(so); 42439287Ssos return 0; 425204281Sjkim} 426204281Sjkim 427204281Sjkimstatic int 428204281Sjkimdiv_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 429204281Sjkim struct mbuf *control, struct proc *p) 430204281Sjkim{ 431204281Sjkim /* Packet must have a header (but that's about it) */ 432204281Sjkim if (m->m_len < sizeof (struct ip) && 433204281Sjkim (m = m_pullup(m, sizeof (struct ip))) == 0) { 434204281Sjkim ipstat.ips_toosmall++; 435204281Sjkim m_freem(m); 436204281Sjkim return EINVAL; 437204281Sjkim } 438204281Sjkim 439204281Sjkim /* Send packet */ 440204281Sjkim return div_output(so, m, nam, control); 441204281Sjkim} 442204281Sjkim 443204281Sjkimstatic int 444204281Sjkimdiv_pcblist(SYSCTL_HANDLER_ARGS) 445204281Sjkim{ 446204281Sjkim int error, i, n, s; 447204281Sjkim struct inpcb *inp, **inp_list; 448204281Sjkim inp_gen_t gencnt; 449204281Sjkim struct xinpgen xig; 450204281Sjkim 451204281Sjkim /* 452204281Sjkim * The process of preparing the TCB list is too time-consuming and 453204281Sjkim * resource-intensive to repeat twice on every request. 454204281Sjkim */ 455204281Sjkim if (req->oldptr == 0) { 456204281Sjkim n = divcbinfo.ipi_count; 457204281Sjkim req->oldidx = 2 * (sizeof xig) 458204281Sjkim + (n + n/8) * sizeof(struct xinpcb); 459204281Sjkim return 0; 460204281Sjkim } 461204281Sjkim 462204281Sjkim if (req->newptr != 0) 463204281Sjkim return EPERM; 464204281Sjkim 465204281Sjkim /* 466204281Sjkim * OK, now we're committed to doing something. 46748104Syokota */ 46848104Syokota s = splnet(); 469174985Swkoszek gencnt = divcbinfo.ipi_gencnt; 47048104Syokota n = divcbinfo.ipi_count; 47139287Ssos splx(s); 472181905Sed 47339287Ssos xig.xig_len = sizeof xig; 47439287Ssos xig.xig_count = n; 47548104Syokota xig.xig_gen = gencnt; 47648104Syokota xig.xig_sogen = so_gencnt; 47748104Syokota error = SYSCTL_OUT(req, &xig, sizeof xig); 47839287Ssos if (error) 47939287Ssos return error; 480162711Sru 481162711Sru inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); 482162711Sru if (inp_list == 0) 483162711Sru return ENOMEM; 48439287Ssos 485181905Sed s = splnet(); 48648104Syokota for (inp = LIST_FIRST(divcbinfo.listhead), i = 0; inp && i < n; 48748104Syokota inp = LIST_NEXT(inp, inp_list)) { 48848104Syokota if (inp->inp_gencnt <= gencnt && !prison_xinpcb(req->p, inp)) 48948104Syokota inp_list[i++] = inp; 49048104Syokota } 49139287Ssos splx(s); 49239287Ssos n = i; 49339287Ssos 49448104Syokota error = 0; 49548104Syokota for (i = 0; i < n; i++) { 49648104Syokota inp = inp_list[i]; 49748104Syokota if (inp->inp_gencnt <= gencnt) { 49839287Ssos struct xinpcb xi; 49948104Syokota xi.xi_len = sizeof xi; 50048104Syokota /* XXX should avoid extra copy */ 50139287Ssos bcopy(inp, &xi.xi_inp, sizeof *inp); 50248104Syokota if (inp->inp_socket) 50348104Syokota sotoxsocket(inp->inp_socket, &xi.xi_socket); 50448104Syokota error = SYSCTL_OUT(req, &xi, sizeof xi); 50548104Syokota } 50648104Syokota } 50748104Syokota if (!error) { 50848104Syokota /* 50948104Syokota * Give the user an updated idea of our state. 51048104Syokota * If the generation differs from what we told 51148104Syokota * her before, she knows that something happened 51248104Syokota * while we were processing this request, and it 51348104Syokota * might be necessary to retry. 51448104Syokota */ 51548104Syokota s = splnet(); 51648104Syokota xig.xig_gen = divcbinfo.ipi_gencnt; 51748104Syokota xig.xig_sogen = so_gencnt; 51848104Syokota xig.xig_count = divcbinfo.ipi_count; 51942504Syokota splx(s); 52048104Syokota error = SYSCTL_OUT(req, &xig, sizeof xig); 52142504Syokota } 52242504Syokota free(inp_list, M_TEMP); 52348104Syokota return error; 52448104Syokota} 52548104Syokota 52648104SyokotaSYSCTL_DECL(_net_inet_divert); 52748104SyokotaSYSCTL_PROC(_net_inet_divert, OID_AUTO, pcblist, CTLFLAG_RD, 0, 0, 52848104Syokota div_pcblist, "S,xinpcb", "List of active divert sockets"); 52948104Syokota 53048104Syokotastruct pr_usrreqs div_usrreqs = { 53148104Syokota div_abort, pru_accept_notsupp, div_attach, div_bind, 53248104Syokota pru_connect_notsupp, pru_connect2_notsupp, in_control, div_detach, 53348104Syokota div_disconnect, pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, 53448104Syokota pru_rcvoob_notsupp, div_send, pru_sense_null, div_shutdown, 53539287Ssos in_setsockaddr, sosend, soreceive, sopoll 53648104Syokota}; 53748104Syokota