if_pfsync.c revision 138666
133965Sjdp/* $FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 138666 2004-12-10 17:42:47Z mlaier $ */ 2218822Sdim/* $OpenBSD: if_pfsync.c,v 1.26 2004/03/28 18:14:20 mcbride Exp $ */ 3218822Sdim 460484Sobrien/* 533965Sjdp * Copyright (c) 2002 Michael Shalayeff 633965Sjdp * All rights reserved. 733965Sjdp * 833965Sjdp * Redistribution and use in source and binary forms, with or without 933965Sjdp * modification, are permitted provided that the following conditions 1033965Sjdp * are met: 1133965Sjdp * 1. Redistributions of source code must retain the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer. 1333965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1433965Sjdp * notice, this list of conditions and the following disclaimer in the 1533965Sjdp * documentation and/or other materials provided with the distribution. 1633965Sjdp * 1733965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1833965Sjdp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1933965Sjdp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2033965Sjdp * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 21218822Sdim * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22218822Sdim * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2333965Sjdp * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2433965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2560484Sobrien * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2633965Sjdp * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 2733965Sjdp * THE POSSIBILITY OF SUCH DAMAGE. 2860484Sobrien */ 2933965Sjdp 3033965Sjdp#ifdef __FreeBSD__ 3133965Sjdp#include "opt_inet.h" 3233965Sjdp#include "opt_inet6.h" 3333965Sjdp#endif 3489857Sobrien 3533965Sjdp#ifndef __FreeBSD__ 3633965Sjdp#include "bpfilter.h" 3789857Sobrien#include "pfsync.h" 3833965Sjdp#elif __FreeBSD__ >= 5 3933965Sjdp#include "opt_bpf.h" 4033965Sjdp#include "opt_pf.h" 4133965Sjdp#define NBPFILTER DEV_BPF 4233965Sjdp#define NPFSYNC DEV_PFSYNC 4333965Sjdp#endif 4433965Sjdp 4533965Sjdp#include <sys/param.h> 4633965Sjdp#include <sys/proc.h> 4733965Sjdp#include <sys/systm.h> 4833965Sjdp#include <sys/time.h> 4933965Sjdp#include <sys/mbuf.h> 5033965Sjdp#include <sys/socket.h> 5133965Sjdp#ifdef __FreeBSD__ 5233965Sjdp#include <sys/kernel.h> 5333965Sjdp#include <sys/malloc.h> 5433965Sjdp#include <sys/module.h> 5533965Sjdp#include <sys/sockio.h> 5633965Sjdp#include <sys/lock.h> 57218822Sdim#include <sys/mutex.h> 58218822Sdim#else 59218822Sdim#include <sys/ioctl.h> 60218822Sdim#include <sys/timeout.h> 6133965Sjdp#endif 62218822Sdim 63218822Sdim#include <net/if.h> 64218822Sdim#if defined(__FreeBSD__) 65218822Sdim#include <net/if_clone.h> 66218822Sdim#endif 67218822Sdim#include <net/if_types.h> 68218822Sdim#include <net/route.h> 6933965Sjdp#include <net/bpf.h> 70218822Sdim 71218822Sdim#ifdef INET 72218822Sdim#include <netinet/in.h> 73218822Sdim#include <netinet/in_systm.h> 74218822Sdim#include <netinet/in_var.h> 75218822Sdim#include <netinet/ip.h> 76218822Sdim#include <netinet/ip_var.h> 77218822Sdim#endif 7833965Sjdp 79218822Sdim#ifdef INET6 80218822Sdim#ifndef INET 81218822Sdim#include <netinet/in.h> 82218822Sdim#endif 83218822Sdim#include <netinet6/nd6.h> 84218822Sdim#endif /* INET6 */ 85218822Sdim 86218822Sdim#include <net/pfvar.h> 87218822Sdim#include <net/if_pfsync.h> 88218822Sdim 89218822Sdim#ifdef __FreeBSD__ 90218822Sdim#define PFSYNCNAME "pfsync" 91218822Sdim#endif 92218822Sdim 93218822Sdim#define PFSYNC_MINMTU \ 94218822Sdim (sizeof(struct pfsync_header) + sizeof(struct pf_state)) 95218822Sdim 96218822Sdim#ifdef PFSYNCDEBUG 97218822Sdim#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0) 98218822Sdimint pfsyncdebug; 99218822Sdim#else 100218822Sdim#define DPRINTF(x) 101218822Sdim#endif 102218822Sdim 103218822Sdim#ifndef __FreeBSD__ 104218822Sdimstruct pfsync_softc pfsyncif; 105218822Sdim#endif 106218822Sdimint pfsync_sync_ok; 107218822Sdimstruct pfsyncstats pfsyncstats; 108218822Sdim 109218822Sdim#ifdef __FreeBSD__ 110218822Sdim 111218822Sdim/* 112218822Sdim * Locking notes: 113218822Sdim * Whenever we really touch/look at the state table we have to hold the 114218822Sdim * PF_LOCK. Functions that do just the interface handling, grab the per 115218822Sdim * softc lock instead. 116218822Sdim * 117218822Sdim */ 118218822Sdim 119218822Sdimstatic void pfsync_clone_destroy(struct ifnet *); 120218822Sdimstatic int pfsync_clone_create(struct if_clone *, int); 121218822Sdim#else 122218822Sdimvoid pfsyncattach(int); 123218822Sdim#endif 124218822Sdimvoid pfsync_setmtu(struct pfsync_softc *, int); 125218822Sdimint pfsync_insert_net_state(struct pfsync_state *); 126218822Sdimint pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 127218822Sdim struct rtentry *); 128218822Sdimint pfsyncioctl(struct ifnet *, u_long, caddr_t); 129218822Sdimvoid pfsyncstart(struct ifnet *); 130218822Sdim 131218822Sdimstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); 132218822Sdimint pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); 133218822Sdimint pfsync_sendout(struct pfsync_softc *); 134218822Sdimvoid pfsync_timeout(void *); 135218822Sdimvoid pfsync_send_bus(struct pfsync_softc *, u_int8_t); 136218822Sdimvoid pfsync_bulk_update(void *); 137218822Sdimvoid pfsync_bulkfail(void *); 138218822Sdim 139218822Sdim#ifndef __FreeBSD__ 140218822Sdimextern int ifqmaxlen; 141218822Sdimextern struct timeval time; 142218822Sdimextern struct timeval mono_time; 143218822Sdimextern int hz; 144218822Sdim#endif 145218822Sdim 146218822Sdim#ifdef __FreeBSD__ 147218822Sdimstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); 148218822Sdimstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; 149218822SdimIFC_SIMPLE_DECLARE(pfsync, 1); 150218822Sdim 151218822Sdimstatic void 152218822Sdimpfsync_clone_destroy(struct ifnet *ifp) 153218822Sdim{ 154218822Sdim struct pfsync_softc *sc; 155218822Sdim 156218822Sdim sc = ifp->if_softc; 157218822Sdim callout_stop(&sc->sc_tmo); 158218822Sdim callout_stop(&sc->sc_bulk_tmo); 159218822Sdim callout_stop(&sc->sc_bulkfail_tmo); 160218822Sdim 161218822Sdim#if NBPFILTER > 0 162218822Sdim bpfdetach(ifp); 163218822Sdim#endif 164218822Sdim if_detach(ifp); 165218822Sdim LIST_REMOVE(sc, sc_next); 166218822Sdim free(sc, M_PFSYNC); 167218822Sdim} 168218822Sdim 169218822Sdimstatic int 170218822Sdimpfsync_clone_create(struct if_clone *ifc, int unit) 171218822Sdim{ 172218822Sdim struct pfsync_softc *sc; 173218822Sdim struct ifnet *ifp; 174218822Sdim 175218822Sdim MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, 176218822Sdim M_WAITOK|M_ZERO); 177218822Sdim 178218822Sdim pfsync_sync_ok = 1; 179218822Sdim sc->sc_mbuf = NULL; 180218822Sdim sc->sc_mbuf_net = NULL; 181218822Sdim sc->sc_statep.s = NULL; 182218822Sdim sc->sc_statep_net.s = NULL; 183218822Sdim sc->sc_maxupdates = 128; 184218822Sdim sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 185218822Sdim sc->sc_ureq_received = 0; 186218822Sdim sc->sc_ureq_sent = 0; 187218822Sdim 188218822Sdim ifp = &sc->sc_if; 189218822Sdim if_initname(ifp, ifc->ifc_name, unit); 190218822Sdim ifp->if_ioctl = pfsyncioctl; 191218822Sdim ifp->if_output = pfsyncoutput; 192218822Sdim ifp->if_start = pfsyncstart; 193218822Sdim ifp->if_type = IFT_PFSYNC; 194218822Sdim ifp->if_snd.ifq_maxlen = ifqmaxlen; 195218822Sdim ifp->if_hdrlen = PFSYNC_HDRLEN; 19633965Sjdp ifp->if_baudrate = IF_Mbps(100); 197218822Sdim ifp->if_softc = sc; 19833965Sjdp pfsync_setmtu(sc, MCLBYTES); 19933965Sjdp /* 20033965Sjdp * XXX 20133965Sjdp * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE 20233965Sjdp * if Gaint lock is removed from the network stack. 20333965Sjdp */ 20460484Sobrien callout_init(&sc->sc_tmo, 0); 20533965Sjdp callout_init(&sc->sc_bulk_tmo, 0); 206218822Sdim callout_init(&sc->sc_bulkfail_tmo, 0); 20733965Sjdp if_attach(&sc->sc_if); 20833965Sjdp 20933965Sjdp LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); 21033965Sjdp#if NBPFILTER > 0 21133965Sjdp bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN); 21233965Sjdp#endif 21333965Sjdp 214218822Sdim return (0); 21533965Sjdp} 21633965Sjdp#else /* !__FreeBSD__ */ 21733965Sjdpvoid 21833965Sjdppfsyncattach(int npfsync) 21933965Sjdp{ 22033965Sjdp struct ifnet *ifp; 22133965Sjdp 222218822Sdim pfsync_sync_ok = 1; 22333965Sjdp bzero(&pfsyncif, sizeof(pfsyncif)); 22433965Sjdp pfsyncif.sc_mbuf = NULL; 22533965Sjdp pfsyncif.sc_mbuf_net = NULL; 22633965Sjdp pfsyncif.sc_statep.s = NULL; 22733965Sjdp pfsyncif.sc_statep_net.s = NULL; 22833965Sjdp pfsyncif.sc_maxupdates = 128; 22933965Sjdp pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; 230218822Sdim pfsyncif.sc_ureq_received = 0; 23133965Sjdp pfsyncif.sc_ureq_sent = 0; 23233965Sjdp ifp = &pfsyncif.sc_if; 23333965Sjdp strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname); 234218822Sdim ifp->if_softc = &pfsyncif; 23533965Sjdp ifp->if_ioctl = pfsyncioctl; 23633965Sjdp ifp->if_output = pfsyncoutput; 23733965Sjdp ifp->if_start = pfsyncstart; 23833965Sjdp ifp->if_type = IFT_PFSYNC; 239218822Sdim ifp->if_snd.ifq_maxlen = ifqmaxlen; 24033965Sjdp ifp->if_hdrlen = PFSYNC_HDRLEN; 24133965Sjdp pfsync_setmtu(&pfsyncif, MCLBYTES); 24233965Sjdp timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif); 243218822Sdim timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif); 24433965Sjdp timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif); 24533965Sjdp if_attach(ifp); 24633965Sjdp if_alloc_sadl(ifp); 247218822Sdim 24833965Sjdp#if NBPFILTER > 0 24933965Sjdp bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 25033965Sjdp#endif 25133965Sjdp} 252218822Sdim#endif 25333965Sjdp 25433965Sjdp/* 25533965Sjdp * Start output on the pfsync interface. 25633965Sjdp */ 257218822Sdimvoid 25833965Sjdppfsyncstart(struct ifnet *ifp) 25933965Sjdp{ 26033965Sjdp#ifdef __FreeBSD__ 26133965Sjdp IF_LOCK(&ifp->if_snd); 262218822Sdim _IF_DROP(&ifp->if_snd); 26333965Sjdp _IF_DRAIN(&ifp->if_snd); 26433965Sjdp IF_UNLOCK(&ifp->if_snd); 26533965Sjdp#else 26633965Sjdp struct mbuf *m; 267218822Sdim int s; 26833965Sjdp 26933965Sjdp for (;;) { 27033965Sjdp s = splimp(); 27133965Sjdp IF_DROP(&ifp->if_snd); 272218822Sdim IF_DEQUEUE(&ifp->if_snd, m); 27333965Sjdp splx(s); 27433965Sjdp 27533965Sjdp if (m == NULL) 276218822Sdim return; 27733965Sjdp else 27833965Sjdp m_freem(m); 27933965Sjdp } 28033965Sjdp#endif 28133965Sjdp} 28233965Sjdp 28333965Sjdpint 28433965Sjdppfsync_insert_net_state(struct pfsync_state *sp) 285218822Sdim{ 28633965Sjdp struct pf_state *st = NULL; 28733965Sjdp struct pf_rule *r = NULL; 28833965Sjdp struct pfi_kif *kif; 28933965Sjdp 29033965Sjdp#ifdef __FreeBSD__ 291218822Sdim PF_ASSERT(MA_OWNED); 29233965Sjdp#endif 29333965Sjdp if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 29433965Sjdp printf("pfsync_insert_net_state: invalid creator id:" 29533965Sjdp " %08x\n", ntohl(sp->creatorid)); 296218822Sdim return (EINVAL); 29733965Sjdp } 29860484Sobrien 29933965Sjdp kif = pfi_lookup_create(sp->ifname); 30033965Sjdp if (kif == NULL) { 301218822Sdim if (pf_status.debug >= PF_DEBUG_MISC) 30233965Sjdp printf("pfsync_insert_net_state: " 30333965Sjdp "unknown interface: %s\n", sp->ifname); 30433965Sjdp /* skip this state */ 30533965Sjdp return (0); 30633965Sjdp } 30733965Sjdp 30833965Sjdp /* 30933965Sjdp * Just use the default rule until we have infrastructure to find the 310218822Sdim * best matching rule. 31133965Sjdp */ 31233965Sjdp r = &pf_default_rule; 31333965Sjdp 314218822Sdim if (!r->max_states || r->states < r->max_states) 31533965Sjdp st = pool_get(&pf_state_pl, PR_NOWAIT); 31633965Sjdp if (st == NULL) { 31760484Sobrien pfi_maybe_destroy(kif); 31860484Sobrien return (ENOMEM); 319218822Sdim } 32060484Sobrien bzero(st, sizeof(*st)); 32160484Sobrien 32260484Sobrien st->rule.ptr = r; 323218822Sdim /* XXX get pointers to nat_rule and anchor */ 32460484Sobrien 32560484Sobrien /* fill in the rest of the state entry */ 32660484Sobrien pf_state_host_ntoh(&sp->lan, &st->lan); 32760484Sobrien pf_state_host_ntoh(&sp->gwy, &st->gwy); 32833965Sjdp pf_state_host_ntoh(&sp->ext, &st->ext); 32933965Sjdp 33060484Sobrien pf_state_peer_ntoh(&sp->src, &st->src); 33133965Sjdp pf_state_peer_ntoh(&sp->dst, &st->dst); 33233965Sjdp 333218822Sdim bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 33433965Sjdp#ifdef __FreeBSD__ 335218822Sdim st->creation = ntohl(sp->creation) + time_second; 33633965Sjdp st->expire = ntohl(sp->expire) + time_second; 33733965Sjdp#else 33833965Sjdp st->creation = ntohl(sp->creation) + time.tv_sec; 339218822Sdim st->expire = ntohl(sp->expire) + time.tv_sec; 34033965Sjdp#endif 34133965Sjdp 34233965Sjdp st->af = sp->af; 34333965Sjdp st->proto = sp->proto; 344218822Sdim st->direction = sp->direction; 34533965Sjdp st->log = sp->log; 34633965Sjdp st->timeout = sp->timeout; 34733965Sjdp st->allow_opts = sp->allow_opts; 34833965Sjdp 349218822Sdim bcopy(sp->id, &st->id, sizeof(st->id)); 35033965Sjdp st->creatorid = sp->creatorid; 35133965Sjdp st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC; 35233965Sjdp 35333965Sjdp 354218822Sdim if (pf_insert_state(kif, st)) { 35533965Sjdp pfi_maybe_destroy(kif); 35633965Sjdp pool_put(&pf_state_pl, st); 35733965Sjdp return (EINVAL); 35833965Sjdp } 359218822Sdim 36033965Sjdp return (0); 36133965Sjdp} 36233965Sjdp 36333965Sjdpvoid 36433965Sjdp#ifdef __FreeBSD__ 365218822Sdimpfsync_input(struct mbuf *m, __unused int off) 36633965Sjdp#else 36733965Sjdppfsync_input(struct mbuf *m, ...) 36833965Sjdp#endif 36933965Sjdp{ 37033965Sjdp struct ip *ip = mtod(m, struct ip *); 37133965Sjdp struct pfsync_header *ph; 372218822Sdim#ifdef __FreeBSD__ 37333965Sjdp struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); 37433965Sjdp#else 37533965Sjdp struct pfsync_softc *sc = &pfsyncif; 37633965Sjdp#endif 377218822Sdim struct pf_state *st, key; 37833965Sjdp struct pfsync_state *sp; 37933965Sjdp struct pfsync_state_upd *up; 38033965Sjdp struct pfsync_state_del *dp; 38133965Sjdp struct pfsync_state_clr *cp; 382218822Sdim struct pfsync_state_upd_req *rup; 38333965Sjdp struct pfsync_state_bus *bus; 38433965Sjdp struct in_addr src; 38533965Sjdp struct mbuf *mp; 38633965Sjdp int iplen, action, error, i, s, count, offp; 38733965Sjdp 38833965Sjdp pfsyncstats.pfsyncs_ipackets++; 38933965Sjdp 39033965Sjdp /* verify that we have a sync interface configured */ 39160484Sobrien if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */ 39260484Sobrien goto done; 39360484Sobrien 39460484Sobrien /* verify that the packet came in on the right interface */ 39560484Sobrien if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { 39660484Sobrien pfsyncstats.pfsyncs_badif++; 39760484Sobrien goto done; 39860484Sobrien } 39933965Sjdp 40033965Sjdp /* verify that the IP TTL is 255. */ 40133965Sjdp if (ip->ip_ttl != PFSYNC_DFLTTL) { 40233965Sjdp pfsyncstats.pfsyncs_badttl++; 40360484Sobrien goto done; 40433965Sjdp } 40533965Sjdp 40633965Sjdp iplen = ip->ip_hl << 2; 40733965Sjdp 408218822Sdim if (m->m_pkthdr.len < iplen + sizeof(*ph)) { 40933965Sjdp pfsyncstats.pfsyncs_hdrops++; 41033965Sjdp goto done; 41133965Sjdp } 41233965Sjdp 41333965Sjdp if (iplen + sizeof(*ph) > m->m_len) { 41433965Sjdp if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { 41533965Sjdp pfsyncstats.pfsyncs_hdrops++; 41633965Sjdp goto done; 41733965Sjdp } 41833965Sjdp ip = mtod(m, struct ip *); 41933965Sjdp } 42033965Sjdp ph = (struct pfsync_header *)((char *)ip + iplen); 42133965Sjdp 42233965Sjdp /* verify the version */ 42333965Sjdp if (ph->version != PFSYNC_VERSION) { 42460484Sobrien pfsyncstats.pfsyncs_badver++; 42533965Sjdp goto done; 42633965Sjdp } 42733965Sjdp 42833965Sjdp action = ph->action; 42933965Sjdp count = ph->count; 43033965Sjdp 43133965Sjdp /* make sure it's a valid action code */ 43233965Sjdp if (action >= PFSYNC_ACT_MAX) { 43333965Sjdp pfsyncstats.pfsyncs_badact++; 43433965Sjdp goto done; 43533965Sjdp } 43633965Sjdp 43733965Sjdp /* Cheaper to grab this now than having to mess with mbufs later */ 43833965Sjdp src = ip->ip_src; 43933965Sjdp 44033965Sjdp switch (action) { 44133965Sjdp case PFSYNC_ACT_CLR: { 44233965Sjdp struct pfi_kif *kif; 44333965Sjdp u_int32_t creatorid; 44433965Sjdp if ((mp = m_pulldown(m, iplen + sizeof(*ph), 44533965Sjdp sizeof(*cp), &offp)) == NULL) { 44633965Sjdp pfsyncstats.pfsyncs_badlen++; 44733965Sjdp return; 44833965Sjdp } 44933965Sjdp cp = (struct pfsync_state_clr *)(mp->m_data + offp); 45033965Sjdp creatorid = cp->creatorid; 45133965Sjdp 45233965Sjdp s = splsoftnet(); 45333965Sjdp#ifdef __FreeBSD__ 45433965Sjdp PF_LOCK(); 45533965Sjdp#endif 45633965Sjdp if (cp->ifname[0] == '\0') { 45733965Sjdp RB_FOREACH(st, pf_state_tree_id, &tree_id) { 45833965Sjdp if (st->creatorid == creatorid) 45933965Sjdp st->timeout = PFTM_PURGE; 46033965Sjdp } 46133965Sjdp } else { 46233965Sjdp kif = pfi_lookup_if(cp->ifname); 46333965Sjdp if (kif == NULL) { 46433965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 46533965Sjdp printf("pfsync_input: PFSYNC_ACT_CLR " 46633965Sjdp "bad interface: %s\n", cp->ifname); 46733965Sjdp splx(s); 468218822Sdim#ifdef __FreeBSD__ 46933965Sjdp PF_UNLOCK(); 470218822Sdim#endif 471218822Sdim goto done; 47233965Sjdp } 47333965Sjdp RB_FOREACH(st, pf_state_tree_lan_ext, 47433965Sjdp &kif->pfik_lan_ext) { 475130561Sobrien if (st->creatorid == creatorid) 47633965Sjdp st->timeout = PFTM_PURGE; 47733965Sjdp } 47833965Sjdp } 479130561Sobrien pf_purge_expired_states(); 480130561Sobrien#ifdef __FreeBSD__ 481130561Sobrien PF_UNLOCK(); 48233965Sjdp#endif 48333965Sjdp splx(s); 48433965Sjdp 48591041Sobrien break; 48633965Sjdp } 48791041Sobrien case PFSYNC_ACT_INS: 48833965Sjdp if ((mp = m_pulldown(m, iplen + sizeof(*ph), 48933965Sjdp count * sizeof(*sp), &offp)) == NULL) { 49089857Sobrien pfsyncstats.pfsyncs_badlen++; 49189857Sobrien return; 49233965Sjdp } 49333965Sjdp 49433965Sjdp s = splsoftnet(); 49533965Sjdp#ifdef __FreeBSD__ 49633965Sjdp PF_LOCK(); 49733965Sjdp#endif 49833965Sjdp for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 49933965Sjdp i < count; i++, sp++) { 50033965Sjdp /* check for invalid values */ 50133965Sjdp if (sp->timeout >= PFTM_MAX || 50233965Sjdp sp->src.state > PF_TCPS_PROXY_DST || 50333965Sjdp sp->dst.state > PF_TCPS_PROXY_DST || 50433965Sjdp sp->direction > PF_OUT || 50533965Sjdp (sp->af != AF_INET && sp->af != AF_INET6)) { 50633965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 50733965Sjdp printf("pfsync_insert: PFSYNC_ACT_INS: " 50833965Sjdp "invalid value\n"); 50933965Sjdp pfsyncstats.pfsyncs_badstate++; 51033965Sjdp continue; 51133965Sjdp } 51233965Sjdp 51333965Sjdp if ((error = pfsync_insert_net_state(sp))) { 51433965Sjdp if (error == ENOMEM) { 51533965Sjdp splx(s); 51633965Sjdp#ifdef __FreeBSD__ 51733965Sjdp PF_UNLOCK(); 51833965Sjdp#endif 51933965Sjdp goto done; 52033965Sjdp } 52133965Sjdp continue; 52233965Sjdp } 52333965Sjdp } 52433965Sjdp#ifdef __FreeBSD__ 52533965Sjdp PF_UNLOCK(); 52633965Sjdp#endif 52733965Sjdp splx(s); 52833965Sjdp break; 52933965Sjdp case PFSYNC_ACT_UPD: 53033965Sjdp if ((mp = m_pulldown(m, iplen + sizeof(*ph), 53133965Sjdp count * sizeof(*sp), &offp)) == NULL) { 53233965Sjdp pfsyncstats.pfsyncs_badlen++; 53333965Sjdp return; 53433965Sjdp } 53533965Sjdp 53633965Sjdp s = splsoftnet(); 53733965Sjdp#ifdef __FreeBSD__ 53833965Sjdp PF_LOCK(); 53933965Sjdp#endif 54033965Sjdp for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 54133965Sjdp i < count; i++, sp++) { 54233965Sjdp /* check for invalid values */ 54333965Sjdp if (sp->timeout >= PFTM_MAX || 54433965Sjdp sp->src.state > PF_TCPS_PROXY_DST || 54533965Sjdp sp->dst.state > PF_TCPS_PROXY_DST) { 54633965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 54733965Sjdp printf("pfsync_insert: PFSYNC_ACT_UPD: " 54833965Sjdp "invalid value\n"); 54933965Sjdp pfsyncstats.pfsyncs_badstate++; 55033965Sjdp continue; 55133965Sjdp } 55233965Sjdp 55333965Sjdp bcopy(sp->id, &key.id, sizeof(key.id)); 55433965Sjdp key.creatorid = sp->creatorid; 55560484Sobrien 55633965Sjdp st = pf_find_state_byid(&key); 55733965Sjdp if (st == NULL) { 55833965Sjdp /* insert the update */ 55933965Sjdp if (pfsync_insert_net_state(sp)) 56033965Sjdp pfsyncstats.pfsyncs_badstate++; 56133965Sjdp continue; 56233965Sjdp } 56333965Sjdp pf_state_peer_ntoh(&sp->src, &st->src); 56433965Sjdp pf_state_peer_ntoh(&sp->dst, &st->dst); 56533965Sjdp#ifdef __FreeBSD__ 56633965Sjdp st->expire = ntohl(sp->expire) + time_second; 56733965Sjdp#else 56860484Sobrien st->expire = ntohl(sp->expire) + time.tv_sec; 56933965Sjdp#endif 57033965Sjdp st->timeout = sp->timeout; 57133965Sjdp 57233965Sjdp } 57333965Sjdp#ifdef __FreeBSD__ 57433965Sjdp PF_UNLOCK(); 57533965Sjdp#endif 57633965Sjdp splx(s); 57733965Sjdp break; 57833965Sjdp /* 57933965Sjdp * It's not strictly necessary for us to support the "uncompressed" 58033965Sjdp * delete action, but it's relatively simple and maintains consistency. 58133965Sjdp */ 58233965Sjdp case PFSYNC_ACT_DEL: 58333965Sjdp if ((mp = m_pulldown(m, iplen + sizeof(*ph), 58433965Sjdp count * sizeof(*sp), &offp)) == NULL) { 58533965Sjdp pfsyncstats.pfsyncs_badlen++; 58633965Sjdp return; 58733965Sjdp } 58833965Sjdp 58933965Sjdp s = splsoftnet(); 59033965Sjdp#ifdef __FreeBSD__ 59133965Sjdp PF_LOCK(); 59233965Sjdp#endif 59333965Sjdp for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 59433965Sjdp i < count; i++, sp++) { 59533965Sjdp bcopy(sp->id, &key.id, sizeof(key.id)); 59633965Sjdp key.creatorid = sp->creatorid; 59733965Sjdp 59833965Sjdp st = pf_find_state_byid(&key); 59933965Sjdp if (st == NULL) { 60033965Sjdp pfsyncstats.pfsyncs_badstate++; 60133965Sjdp continue; 60233965Sjdp } 60333965Sjdp /* 60433965Sjdp * XXX 60533965Sjdp * pf_purge_expired_states() is expensive, 60633965Sjdp * we really want to purge the state directly. 60733965Sjdp */ 60833965Sjdp st->timeout = PFTM_PURGE; 60933965Sjdp st->sync_flags |= PFSTATE_FROMSYNC; 61033965Sjdp } 61133965Sjdp pf_purge_expired_states(); 61233965Sjdp#ifdef __FreeBSD__ 61333965Sjdp PF_UNLOCK(); 61433965Sjdp#endif 61533965Sjdp splx(s); 61633965Sjdp break; 61733965Sjdp case PFSYNC_ACT_UPD_C: { 61833965Sjdp int update_requested = 0; 61933965Sjdp 62033965Sjdp if ((mp = m_pulldown(m, iplen + sizeof(*ph), 62133965Sjdp count * sizeof(*up), &offp)) == NULL) { 62233965Sjdp pfsyncstats.pfsyncs_badlen++; 62333965Sjdp return; 62433965Sjdp } 62533965Sjdp 62633965Sjdp s = splsoftnet(); 62733965Sjdp#ifdef __FreeBSD__ 62833965Sjdp PF_LOCK(); 62933965Sjdp#endif 63033965Sjdp for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); 63133965Sjdp i < count; i++, up++) { 63233965Sjdp /* check for invalid values */ 63333965Sjdp if (up->timeout >= PFTM_MAX || 63433965Sjdp up->src.state > PF_TCPS_PROXY_DST || 63533965Sjdp up->dst.state > PF_TCPS_PROXY_DST) { 63633965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 63733965Sjdp printf("pfsync_insert: " 63833965Sjdp "PFSYNC_ACT_UPD_C: " 63933965Sjdp "invalid value\n"); 64033965Sjdp pfsyncstats.pfsyncs_badstate++; 64133965Sjdp continue; 64233965Sjdp } 64333965Sjdp 64433965Sjdp bcopy(up->id, &key.id, sizeof(key.id)); 64533965Sjdp key.creatorid = up->creatorid; 64633965Sjdp 64733965Sjdp st = pf_find_state_byid(&key); 64833965Sjdp if (st == NULL) { 64933965Sjdp /* We don't have this state. Ask for it. */ 65033965Sjdp pfsync_request_update(up, &src); 65133965Sjdp update_requested = 1; 65233965Sjdp pfsyncstats.pfsyncs_badstate++; 65333965Sjdp continue; 65433965Sjdp } 65533965Sjdp pf_state_peer_ntoh(&up->src, &st->src); 65633965Sjdp pf_state_peer_ntoh(&up->dst, &st->dst); 65733965Sjdp#ifdef __FreeBSD__ 65833965Sjdp st->expire = ntohl(up->expire) + time_second; 65933965Sjdp#else 66033965Sjdp st->expire = ntohl(up->expire) + time.tv_sec; 66133965Sjdp#endif 66233965Sjdp st->timeout = up->timeout; 66333965Sjdp } 66460484Sobrien if (update_requested) 66560484Sobrien pfsync_sendout(sc); 66633965Sjdp#ifdef __FreeBSD__ 66733965Sjdp PF_UNLOCK(); 66860484Sobrien#endif 66960484Sobrien splx(s); 67060484Sobrien break; 67160484Sobrien } 67233965Sjdp case PFSYNC_ACT_DEL_C: 67360484Sobrien if ((mp = m_pulldown(m, iplen + sizeof(*ph), 67433965Sjdp count * sizeof(*dp), &offp)) == NULL) { 67533965Sjdp pfsyncstats.pfsyncs_badlen++; 67660484Sobrien return; 67760484Sobrien } 67860484Sobrien 67960484Sobrien s = splsoftnet(); 68060484Sobrien#ifdef __FreeBSD__ 68160484Sobrien PF_LOCK(); 68260484Sobrien#endif 68360484Sobrien for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); 68460484Sobrien i < count; i++, dp++) { 68560484Sobrien bcopy(dp->id, &key.id, sizeof(key.id)); 68660484Sobrien key.creatorid = dp->creatorid; 68760484Sobrien 68860484Sobrien st = pf_find_state_byid(&key); 68960484Sobrien if (st == NULL) { 69060484Sobrien pfsyncstats.pfsyncs_badstate++; 69160484Sobrien continue; 69260484Sobrien } 69360484Sobrien /* 69460484Sobrien * XXX 69560484Sobrien * pf_purge_expired_states() is expensive, 69660484Sobrien * we really want to purge the state directly. 69760484Sobrien */ 69860484Sobrien st->timeout = PFTM_PURGE; 69960484Sobrien st->sync_flags |= PFSTATE_FROMSYNC; 70060484Sobrien } 70160484Sobrien pf_purge_expired_states(); 70260484Sobrien#ifdef __FreeBSD__ 70360484Sobrien PF_UNLOCK(); 70460484Sobrien#endif 70560484Sobrien splx(s); 70660484Sobrien break; 70760484Sobrien case PFSYNC_ACT_INS_F: 70860484Sobrien case PFSYNC_ACT_DEL_F: 70960484Sobrien /* not implemented */ 71060484Sobrien break; 71160484Sobrien case PFSYNC_ACT_UREQ: 71260484Sobrien if ((mp = m_pulldown(m, iplen + sizeof(*ph), 71360484Sobrien count * sizeof(*rup), &offp)) == NULL) { 71433965Sjdp pfsyncstats.pfsyncs_badlen++; 71533965Sjdp return; 71633965Sjdp } 71733965Sjdp 71833965Sjdp s = splsoftnet(); 71933965Sjdp /* XXX send existing. pfsync_pack_state should handle this. */ 72033965Sjdp#ifdef __FreeBSD__ 72133965Sjdp PF_LOCK(); 72233965Sjdp#endif 72333965Sjdp if (sc->sc_mbuf != NULL) 72433965Sjdp pfsync_sendout(sc); 72533965Sjdp for (i = 0, 72633965Sjdp rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); 72733965Sjdp i < count; i++, rup++) { 72833965Sjdp bcopy(rup->id, &key.id, sizeof(key.id)); 72933965Sjdp key.creatorid = rup->creatorid; 73033965Sjdp 73133965Sjdp if (key.id == 0 && key.creatorid == 0) { 73233965Sjdp#ifdef __FreeBSD__ 73333965Sjdp sc->sc_ureq_received = time_uptime; 73433965Sjdp#else 73533965Sjdp sc->sc_ureq_received = mono_time.tv_sec; 73633965Sjdp#endif 73733965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 73833965Sjdp printf("pfsync: received " 73933965Sjdp "bulk update request\n"); 74033965Sjdp pfsync_send_bus(sc, PFSYNC_BUS_START); 74133965Sjdp#ifdef __FreeBSD__ 74233965Sjdp callout_reset(&sc->sc_bulk_tmo, 1 * hz, 74333965Sjdp pfsync_bulk_update, 74433965Sjdp LIST_FIRST(&pfsync_list)); 74533965Sjdp#else 74633965Sjdp timeout_add(&sc->sc_bulk_tmo, 1 * hz); 74733965Sjdp#endif 74833965Sjdp } else { 74933965Sjdp st = pf_find_state_byid(&key); 75033965Sjdp if (st == NULL) { 75133965Sjdp pfsyncstats.pfsyncs_badstate++; 75233965Sjdp continue; 75333965Sjdp } 75433965Sjdp pfsync_pack_state(PFSYNC_ACT_UPD, st, 0); 75533965Sjdp } 75633965Sjdp } 75733965Sjdp if (sc->sc_mbuf != NULL) 75833965Sjdp pfsync_sendout(sc); 75933965Sjdp#ifdef __FreeBSD__ 76033965Sjdp PF_UNLOCK(); 76133965Sjdp#endif 76233965Sjdp splx(s); 76333965Sjdp break; 76433965Sjdp case PFSYNC_ACT_BUS: 76533965Sjdp /* If we're not waiting for a bulk update, who cares. */ 76633965Sjdp if (sc->sc_ureq_sent == 0) 76733965Sjdp break; 76833965Sjdp 76933965Sjdp if ((mp = m_pulldown(m, iplen + sizeof(*ph), 77033965Sjdp sizeof(*bus), &offp)) == NULL) { 77133965Sjdp pfsyncstats.pfsyncs_badlen++; 77233965Sjdp return; 77333965Sjdp } 77433965Sjdp bus = (struct pfsync_state_bus *)(mp->m_data + offp); 77533965Sjdp switch (bus->status) { 77633965Sjdp case PFSYNC_BUS_START: 77733965Sjdp#ifdef __FreeBSD__ 77833965Sjdp callout_reset(&sc->sc_bulkfail_tmo, 77933965Sjdp pf_pool_limits[PF_LIMIT_STATES].limit / 78033965Sjdp (PFSYNC_BULKPACKETS * sc->sc_maxcount), 78133965Sjdp pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 78233965Sjdp#else 78333965Sjdp timeout_add(&sc->sc_bulkfail_tmo, 78433965Sjdp pf_pool_limits[PF_LIMIT_STATES].limit / 78533965Sjdp (PFSYNC_BULKPACKETS * sc->sc_maxcount)); 78633965Sjdp#endif 78733965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 78833965Sjdp printf("pfsync: received bulk " 78933965Sjdp "update start\n"); 79033965Sjdp break; 79133965Sjdp case PFSYNC_BUS_END: 79233965Sjdp#ifdef __FreeBSD__ 79333965Sjdp if (time_uptime - ntohl(bus->endtime) >= 79433965Sjdp#else 79533965Sjdp if (mono_time.tv_sec - ntohl(bus->endtime) >= 79633965Sjdp#endif 79733965Sjdp sc->sc_ureq_sent) { 79833965Sjdp /* that's it, we're happy */ 79933965Sjdp sc->sc_ureq_sent = 0; 80033965Sjdp sc->sc_bulk_tries = 0; 80133965Sjdp#ifdef __FreeBSD__ 80233965Sjdp callout_stop(&sc->sc_bulkfail_tmo); 80333965Sjdp#else 80433965Sjdp timeout_del(&sc->sc_bulkfail_tmo); 80533965Sjdp#endif 80633965Sjdp pfsync_sync_ok = 1; 80733965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 80833965Sjdp printf("pfsync: received valid " 80933965Sjdp "bulk update end\n"); 81033965Sjdp } else { 81133965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 81233965Sjdp printf("pfsync: received invalid " 81333965Sjdp "bulk update end: bad timestamp\n"); 81433965Sjdp } 81533965Sjdp break; 81633965Sjdp } 81733965Sjdp break; 81833965Sjdp } 81933965Sjdp 82033965Sjdpdone: 82133965Sjdp if (m) 82233965Sjdp m_freem(m); 82333965Sjdp} 82433965Sjdp 82533965Sjdpint 82633965Sjdppfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 82733965Sjdp struct rtentry *rt) 82833965Sjdp{ 82933965Sjdp m_freem(m); 83033965Sjdp return (0); 83133965Sjdp} 83233965Sjdp 83333965Sjdp/* ARGSUSED */ 83433965Sjdpint 83533965Sjdppfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 83633965Sjdp{ 83733965Sjdp#ifndef __FreeBSD__ 83833965Sjdp struct proc *p = curproc; 83933965Sjdp#endif 84033965Sjdp struct pfsync_softc *sc = ifp->if_softc; 84133965Sjdp struct ifreq *ifr = (struct ifreq *)data; 84233965Sjdp struct ip_moptions *imo = &sc->sc_imo; 84333965Sjdp struct pfsyncreq pfsyncr; 84433965Sjdp struct ifnet *sifp; 84533965Sjdp int s, error; 84633965Sjdp 84733965Sjdp switch (cmd) { 84833965Sjdp case SIOCSIFADDR: 84933965Sjdp case SIOCAIFADDR: 85033965Sjdp case SIOCSIFDSTADDR: 85133965Sjdp case SIOCSIFFLAGS: 85233965Sjdp if (ifp->if_flags & IFF_UP) 85333965Sjdp ifp->if_flags |= IFF_RUNNING; 85433965Sjdp else 85533965Sjdp ifp->if_flags &= ~IFF_RUNNING; 85633965Sjdp break; 85733965Sjdp case SIOCSIFMTU: 85833965Sjdp if (ifr->ifr_mtu < PFSYNC_MINMTU) 85933965Sjdp return (EINVAL); 86033965Sjdp if (ifr->ifr_mtu > MCLBYTES) 86133965Sjdp ifr->ifr_mtu = MCLBYTES; 86233965Sjdp s = splnet(); 86333965Sjdp#ifdef __FreeBSD__ 86433965Sjdp PF_LOCK(); 86533965Sjdp#endif 86633965Sjdp if (ifr->ifr_mtu < ifp->if_mtu) { 86733965Sjdp pfsync_sendout(sc); 86833965Sjdp } 86933965Sjdp pfsync_setmtu(sc, ifr->ifr_mtu); 87033965Sjdp#ifdef __FreeBSD__ 87133965Sjdp PF_UNLOCK(); 87233965Sjdp#endif 87333965Sjdp splx(s); 87433965Sjdp break; 87533965Sjdp case SIOCGETPFSYNC: 87633965Sjdp#ifdef __FreeBSD__ 87733965Sjdp /* XXX: read unlocked */ 87833965Sjdp#endif 87933965Sjdp bzero(&pfsyncr, sizeof(pfsyncr)); 88033965Sjdp if (sc->sc_sync_ifp) 88133965Sjdp strlcpy(pfsyncr.pfsyncr_syncif, 88233965Sjdp sc->sc_sync_ifp->if_xname, IFNAMSIZ); 88333965Sjdp pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 88433965Sjdp if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) 88533965Sjdp return (error); 88633965Sjdp break; 88733965Sjdp case SIOCSETPFSYNC: 88833965Sjdp#ifdef __FreeBSD__ 88933965Sjdp if ((error = suser(curthread)) != 0) 89033965Sjdp#else 89133965Sjdp if ((error = suser(p, p->p_acflag)) != 0) 89233965Sjdp#endif 89333965Sjdp return (error); 89433965Sjdp if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 89533965Sjdp return (error); 89633965Sjdp 89733965Sjdp if (pfsyncr.pfsyncr_maxupdates > 255) 89833965Sjdp return (EINVAL); 89938889Sjdp#ifdef __FreeBSD__ 90033965Sjdp PF_LOCK(); 90133965Sjdp#endif 90233965Sjdp sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 90333965Sjdp 90433965Sjdp if (pfsyncr.pfsyncr_syncif[0] == 0) { 90533965Sjdp sc->sc_sync_ifp = NULL; 90633965Sjdp if (sc->sc_mbuf_net != NULL) { 90733965Sjdp /* Don't keep stale pfsync packets around. */ 90833965Sjdp s = splnet(); 90933965Sjdp m_freem(sc->sc_mbuf_net); 91033965Sjdp sc->sc_mbuf_net = NULL; 91133965Sjdp sc->sc_statep_net.s = NULL; 91233965Sjdp splx(s); 91333965Sjdp } 91433965Sjdp#ifdef __FreeBSD__ 91533965Sjdp PF_UNLOCK(); 91633965Sjdp#endif 91733965Sjdp break; 91833965Sjdp } 91938889Sjdp if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL) { 92033965Sjdp#ifdef __FreeBSD__ 92133965Sjdp PF_UNLOCK(); 92233965Sjdp#endif 92333965Sjdp return (EINVAL); 92433965Sjdp } 92533965Sjdp else if (sifp == sc->sc_sync_ifp) { 92633965Sjdp#ifdef __FreeBSD__ 92733965Sjdp PF_UNLOCK(); 92833965Sjdp#endif 92933965Sjdp break; 93033965Sjdp } 93133965Sjdp 93233965Sjdp s = splnet(); 93333965Sjdp if (sifp->if_mtu < sc->sc_if.if_mtu || 93433965Sjdp (sc->sc_sync_ifp != NULL && 93533965Sjdp sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || 93633965Sjdp sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 93733965Sjdp pfsync_sendout(sc); 93833965Sjdp sc->sc_sync_ifp = sifp; 93933965Sjdp 94038889Sjdp pfsync_setmtu(sc, sc->sc_if.if_mtu); 94133965Sjdp 94233965Sjdp if (imo->imo_num_memberships > 0) { 94333965Sjdp in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 94433965Sjdp imo->imo_multicast_ifp = NULL; 94533965Sjdp } 94633965Sjdp 94733965Sjdp if (sc->sc_sync_ifp) { 94833965Sjdp struct in_addr addr; 94933965Sjdp 95033965Sjdp#ifdef __FreeBSD__ 95133965Sjdp PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */ 95233965Sjdp addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 95333965Sjdp#else 95433965Sjdp addr.s_addr = INADDR_PFSYNC_GROUP; 95533965Sjdp#endif 95633965Sjdp if ((imo->imo_membership[0] = 95733965Sjdp in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { 95833965Sjdp splx(s); 95933965Sjdp return (ENOBUFS); 96033965Sjdp } 96133965Sjdp imo->imo_num_memberships++; 96233965Sjdp imo->imo_multicast_ifp = sc->sc_sync_ifp; 96333965Sjdp imo->imo_multicast_ttl = PFSYNC_DFLTTL; 96433965Sjdp imo->imo_multicast_loop = 0; 96533965Sjdp 96638889Sjdp /* Request a full state table update. */ 96733965Sjdp#ifdef __FreeBSD__ 96833965Sjdp PF_LOCK(); 96933965Sjdp sc->sc_ureq_sent = time_uptime; 97033965Sjdp#else 97133965Sjdp sc->sc_ureq_sent = mono_time.tv_sec; 97233965Sjdp#endif 97333965Sjdp pfsync_sync_ok = 0; 97433965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 97533965Sjdp printf("pfsync: requesting bulk update\n"); 97633965Sjdp#ifdef __FreeBSD__ 97733965Sjdp callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 97833965Sjdp pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 97933965Sjdp#else 98033965Sjdp timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 98133965Sjdp#endif 98233965Sjdp pfsync_request_update(NULL, NULL); 98333965Sjdp pfsync_sendout(sc); 98433965Sjdp } 98533965Sjdp#ifdef __FreeBSD__ 98633965Sjdp PF_UNLOCK(); 98733965Sjdp#endif 98833965Sjdp splx(s); 98938889Sjdp 99033965Sjdp break; 99133965Sjdp 99233965Sjdp default: 99333965Sjdp return (ENOTTY); 99433965Sjdp } 99533965Sjdp 99633965Sjdp return (0); 99733965Sjdp} 99833965Sjdp 99933965Sjdpvoid 100033965Sjdppfsync_setmtu(struct pfsync_softc *sc, int mtu_req) 100133965Sjdp{ 100233965Sjdp int mtu; 100333965Sjdp 100433965Sjdp if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) 100533965Sjdp mtu = sc->sc_sync_ifp->if_mtu; 100633965Sjdp else 100733965Sjdp mtu = mtu_req; 100833965Sjdp 100933965Sjdp sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / 101033965Sjdp sizeof(struct pfsync_state); 101133965Sjdp if (sc->sc_maxcount > 254) 101233965Sjdp sc->sc_maxcount = 254; 101333965Sjdp sc->sc_if.if_mtu = sizeof(struct pfsync_header) + 101433965Sjdp sc->sc_maxcount * sizeof(struct pfsync_state); 101538889Sjdp} 101633965Sjdp 101733965Sjdpstruct mbuf * 101833965Sjdppfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) 101933965Sjdp{ 102033965Sjdp struct pfsync_header *h; 102133965Sjdp struct mbuf *m; 102233965Sjdp int len; 102333965Sjdp 102433965Sjdp#ifdef __FreeBSD__ 102533965Sjdp PF_ASSERT(MA_OWNED); 102633965Sjdp#endif 102733965Sjdp MGETHDR(m, M_DONTWAIT, MT_DATA); 102833965Sjdp if (m == NULL) { 102933965Sjdp sc->sc_if.if_oerrors++; 103033965Sjdp return (NULL); 103133965Sjdp } 103233965Sjdp 103333965Sjdp switch (action) { 103433965Sjdp case PFSYNC_ACT_CLR: 103533965Sjdp len = sizeof(struct pfsync_header) + 103633965Sjdp sizeof(struct pfsync_state_clr); 103733965Sjdp break; 103833965Sjdp case PFSYNC_ACT_UPD_C: 103933965Sjdp len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + 104033965Sjdp sizeof(struct pfsync_header); 104133965Sjdp break; 104233965Sjdp case PFSYNC_ACT_DEL_C: 104333965Sjdp len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + 104433965Sjdp sizeof(struct pfsync_header); 104560484Sobrien break; 104660484Sobrien case PFSYNC_ACT_UREQ: 1047130561Sobrien len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + 1048130561Sobrien sizeof(struct pfsync_header); 104933965Sjdp break; 105060484Sobrien case PFSYNC_ACT_BUS: 105133965Sjdp len = sizeof(struct pfsync_header) + 105260484Sobrien sizeof(struct pfsync_state_bus); 105389857Sobrien break; 105433965Sjdp default: 105533965Sjdp len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + 105633965Sjdp sizeof(struct pfsync_header); 105760484Sobrien break; 105833965Sjdp } 105933965Sjdp 106033965Sjdp if (len > MHLEN) { 106133965Sjdp MCLGET(m, M_DONTWAIT); 106233965Sjdp if ((m->m_flags & M_EXT) == 0) { 106333965Sjdp m_free(m); 106433965Sjdp sc->sc_if.if_oerrors++; 106533965Sjdp return (NULL); 106633965Sjdp } 106791041Sobrien m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); 106891041Sobrien } else 106933965Sjdp MH_ALIGN(m, len); 107033965Sjdp 107191041Sobrien m->m_pkthdr.rcvif = NULL; 107291041Sobrien m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); 107333965Sjdp h = mtod(m, struct pfsync_header *); 107433965Sjdp h->version = PFSYNC_VERSION; 107533965Sjdp h->af = 0; 107633965Sjdp h->count = 0; 107733965Sjdp h->action = action; 107833965Sjdp 107960484Sobrien *sp = (void *)((char *)h + PFSYNC_HDRLEN); 108033965Sjdp#ifdef __FreeBSD__ 108133965Sjdp callout_reset(&sc->sc_tmo, hz, pfsync_timeout, 108260484Sobrien LIST_FIRST(&pfsync_list)); 108333965Sjdp#else 108433965Sjdp timeout_add(&sc->sc_tmo, hz); 108533965Sjdp#endif 108633965Sjdp return (m); 108733965Sjdp} 108833965Sjdp 108933965Sjdpint 109033965Sjdppfsync_pack_state(u_int8_t action, struct pf_state *st, int compress) 109133965Sjdp{ 109233965Sjdp#ifdef __FreeBSD__ 109333965Sjdp struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 109460484Sobrien#else 109533965Sjdp struct ifnet *ifp = &pfsyncif.sc_if; 109633965Sjdp#endif 109733965Sjdp struct pfsync_softc *sc = ifp->if_softc; 109833965Sjdp struct pfsync_header *h, *h_net; 109933965Sjdp struct pfsync_state *sp = NULL; 110033965Sjdp struct pfsync_state_upd *up = NULL; 110133965Sjdp struct pfsync_state_del *dp = NULL; 110233965Sjdp struct pf_rule *r; 110333965Sjdp u_long secs; 110433965Sjdp int s, ret = 0; 110533965Sjdp u_int8_t i = 255, newaction = 0; 110633965Sjdp 110733965Sjdp#ifdef __FreeBSD__ 110833965Sjdp PF_ASSERT(MA_OWNED); 110933965Sjdp#endif 111033965Sjdp /* 111133965Sjdp * If a packet falls in the forest and there's nobody around to 111233965Sjdp * hear, does it make a sound? 111333965Sjdp */ 111433965Sjdp if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL) { 111560484Sobrien /* Don't leave any stale pfsync packets hanging around. */ 111633965Sjdp if (sc->sc_mbuf != NULL) { 111733965Sjdp m_freem(sc->sc_mbuf); 111860484Sobrien sc->sc_mbuf = NULL; 111960484Sobrien sc->sc_statep.s = NULL; 112033965Sjdp } 112133965Sjdp return (0); 112233965Sjdp } 112333965Sjdp 112433965Sjdp if (action >= PFSYNC_ACT_MAX) 112533965Sjdp return (EINVAL); 112633965Sjdp 112733965Sjdp s = splnet(); 112833965Sjdp if (sc->sc_mbuf == NULL) { 112960484Sobrien if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 113033965Sjdp (void *)&sc->sc_statep.s)) == NULL) { 113133965Sjdp splx(s); 113233965Sjdp return (ENOMEM); 113333965Sjdp } 113433965Sjdp h = mtod(sc->sc_mbuf, struct pfsync_header *); 113533965Sjdp } else { 113633965Sjdp h = mtod(sc->sc_mbuf, struct pfsync_header *); 113733965Sjdp if (h->action != action) { 113833965Sjdp pfsync_sendout(sc); 113933965Sjdp if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 114033965Sjdp (void *)&sc->sc_statep.s)) == NULL) { 114133965Sjdp splx(s); 114260484Sobrien return (ENOMEM); 114333965Sjdp } 114433965Sjdp h = mtod(sc->sc_mbuf, struct pfsync_header *); 114560484Sobrien } else { 114633965Sjdp /* 114733965Sjdp * If it's an update, look in the packet to see if 114833965Sjdp * we already have an update for the state. 114933965Sjdp */ 115033965Sjdp if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { 115133965Sjdp struct pfsync_state *usp = 115233965Sjdp (void *)((char *)h + PFSYNC_HDRLEN); 115333965Sjdp 115433965Sjdp for (i = 0; i < h->count; i++) { 115533965Sjdp if (!memcmp(usp->id, &st->id, 115633965Sjdp PFSYNC_ID_LEN) && 115760484Sobrien usp->creatorid == st->creatorid) { 115833965Sjdp sp = usp; 115933965Sjdp sp->updates++; 116033965Sjdp break; 116133965Sjdp } 116233965Sjdp usp++; 116333965Sjdp } 116433965Sjdp } 116533965Sjdp } 116633965Sjdp } 116733965Sjdp 116833965Sjdp#ifdef __FreeBSD__ 116933965Sjdp secs = time_second; 117033965Sjdp 117133965Sjdp st->pfsync_time = time_uptime; 117233965Sjdp#else 117333965Sjdp secs = time.tv_sec; 117433965Sjdp 117533965Sjdp st->pfsync_time = mono_time.tv_sec; 117633965Sjdp#endif 117733965Sjdp TAILQ_REMOVE(&state_updates, st, u.s.entry_updates); 117860484Sobrien TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates); 117933965Sjdp 118033965Sjdp if (sp == NULL) { 118160484Sobrien /* not a "duplicate" update */ 118260484Sobrien i = 255; 118333965Sjdp sp = sc->sc_statep.s++; 118433965Sjdp sc->sc_mbuf->m_pkthdr.len = 118533965Sjdp sc->sc_mbuf->m_len += sizeof(struct pfsync_state); 118633965Sjdp h->count++; 118733965Sjdp bzero(sp, sizeof(*sp)); 118833965Sjdp 118933965Sjdp bcopy(&st->id, sp->id, sizeof(sp->id)); 119033965Sjdp sp->creatorid = st->creatorid; 119133965Sjdp 119260484Sobrien strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); 119333965Sjdp pf_state_host_hton(&st->lan, &sp->lan); 119433965Sjdp pf_state_host_hton(&st->gwy, &sp->gwy); 119533965Sjdp pf_state_host_hton(&st->ext, &sp->ext); 119633965Sjdp 119733965Sjdp bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 119833965Sjdp 119933965Sjdp sp->creation = htonl(secs - st->creation); 120033965Sjdp sp->packets[0] = htonl(st->packets[0]); 120133965Sjdp sp->packets[1] = htonl(st->packets[1]); 120233965Sjdp sp->bytes[0] = htonl(st->bytes[0]); 120333965Sjdp sp->bytes[1] = htonl(st->bytes[1]); 120433965Sjdp if ((r = st->rule.ptr) == NULL) 120533965Sjdp sp->rule = htonl(-1); 120633965Sjdp else 120733965Sjdp sp->rule = htonl(r->nr); 120833965Sjdp if ((r = st->anchor.ptr) == NULL) 120933965Sjdp sp->anchor = htonl(-1); 121033965Sjdp else 121133965Sjdp sp->anchor = htonl(r->nr); 121233965Sjdp sp->af = st->af; 121333965Sjdp sp->proto = st->proto; 121433965Sjdp sp->direction = st->direction; 121533965Sjdp sp->log = st->log; 121633965Sjdp sp->allow_opts = st->allow_opts; 121733965Sjdp sp->timeout = st->timeout; 121833965Sjdp 121933965Sjdp sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC; 122033965Sjdp } 122133965Sjdp 122233965Sjdp pf_state_peer_hton(&st->src, &sp->src); 122333965Sjdp pf_state_peer_hton(&st->dst, &sp->dst); 122433965Sjdp 122533965Sjdp if (st->expire <= secs) 122633965Sjdp sp->expire = htonl(0); 122733965Sjdp else 122833965Sjdp sp->expire = htonl(st->expire - secs); 122933965Sjdp 123033965Sjdp /* do we need to build "compressed" actions for network transfer? */ 123133965Sjdp if (sc->sc_sync_ifp && compress) { 123233965Sjdp switch (action) { 123333965Sjdp case PFSYNC_ACT_UPD: 123433965Sjdp newaction = PFSYNC_ACT_UPD_C; 123533965Sjdp break; 123633965Sjdp case PFSYNC_ACT_DEL: 123733965Sjdp newaction = PFSYNC_ACT_DEL_C; 123833965Sjdp break; 123933965Sjdp default: 124033965Sjdp /* by default we just send the uncompressed states */ 124133965Sjdp break; 124233965Sjdp } 124333965Sjdp } 124433965Sjdp 124533965Sjdp if (newaction) { 124633965Sjdp if (sc->sc_mbuf_net == NULL) { 124733965Sjdp if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, 124833965Sjdp (void *)&sc->sc_statep_net.s)) == NULL) { 124933965Sjdp splx(s); 125033965Sjdp return (ENOMEM); 125133965Sjdp } 125233965Sjdp } 125333965Sjdp h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); 125433965Sjdp 125533965Sjdp switch (newaction) { 125633965Sjdp case PFSYNC_ACT_UPD_C: 125733965Sjdp if (i != 255) { 125833965Sjdp up = (void *)((char *)h_net + 125933965Sjdp PFSYNC_HDRLEN + (i * sizeof(*up))); 126033965Sjdp up->updates++; 126133965Sjdp } else { 126233965Sjdp h_net->count++; 126333965Sjdp sc->sc_mbuf_net->m_pkthdr.len = 126433965Sjdp sc->sc_mbuf_net->m_len += sizeof(*up); 126533965Sjdp up = sc->sc_statep_net.u++; 126633965Sjdp 126733965Sjdp bzero(up, sizeof(*up)); 126833965Sjdp bcopy(&st->id, up->id, sizeof(up->id)); 126933965Sjdp up->creatorid = st->creatorid; 127033965Sjdp } 127133965Sjdp up->timeout = st->timeout; 127233965Sjdp up->expire = sp->expire; 127333965Sjdp up->src = sp->src; 127433965Sjdp up->dst = sp->dst; 127533965Sjdp break; 127633965Sjdp case PFSYNC_ACT_DEL_C: 127733965Sjdp sc->sc_mbuf_net->m_pkthdr.len = 127833965Sjdp sc->sc_mbuf_net->m_len += sizeof(*dp); 127933965Sjdp dp = sc->sc_statep_net.d++; 128033965Sjdp h_net->count++; 128133965Sjdp 128233965Sjdp bzero(dp, sizeof(*dp)); 128333965Sjdp bcopy(&st->id, dp->id, sizeof(dp->id)); 128433965Sjdp dp->creatorid = st->creatorid; 128533965Sjdp break; 128633965Sjdp } 128733965Sjdp } 128833965Sjdp 128933965Sjdp if (h->count == sc->sc_maxcount || 129033965Sjdp (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) 129133965Sjdp ret = pfsync_sendout(sc); 129233965Sjdp 129333965Sjdp splx(s); 129433965Sjdp return (ret); 129533965Sjdp} 129633965Sjdp 129733965Sjdp/* This must be called in splnet() */ 129833965Sjdpint 129933965Sjdppfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) 130033965Sjdp{ 130133965Sjdp#ifdef __FreeBSD__ 130233965Sjdp struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 130333965Sjdp#else 130433965Sjdp struct ifnet *ifp = &pfsyncif.sc_if; 130533965Sjdp#endif 130633965Sjdp struct pfsync_header *h; 130733965Sjdp struct pfsync_softc *sc = ifp->if_softc; 130833965Sjdp struct pfsync_state_upd_req *rup; 130933965Sjdp int s = 0, ret = 0; /* make the compiler happy */ 131033965Sjdp 131133965Sjdp#ifdef __FreeBSD__ 131233965Sjdp PF_ASSERT(MA_OWNED); 131333965Sjdp#endif 131433965Sjdp if (sc->sc_mbuf == NULL) { 131533965Sjdp if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 131660484Sobrien (void *)&sc->sc_statep.s)) == NULL) { 131733965Sjdp splx(s); 131833965Sjdp return (ENOMEM); 131933965Sjdp } 132033965Sjdp h = mtod(sc->sc_mbuf, struct pfsync_header *); 132133965Sjdp } else { 132233965Sjdp h = mtod(sc->sc_mbuf, struct pfsync_header *); 132333965Sjdp if (h->action != PFSYNC_ACT_UREQ) { 132433965Sjdp pfsync_sendout(sc); 132533965Sjdp if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 132633965Sjdp (void *)&sc->sc_statep.s)) == NULL) { 132738889Sjdp splx(s); 132860484Sobrien return (ENOMEM); 132960484Sobrien } 133060484Sobrien h = mtod(sc->sc_mbuf, struct pfsync_header *); 133160484Sobrien } 133260484Sobrien } 133360484Sobrien 133460484Sobrien if (src != NULL) 133560484Sobrien sc->sc_sendaddr = *src; 133660484Sobrien sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); 133760484Sobrien h->count++; 133833965Sjdp rup = sc->sc_statep.r++; 133933965Sjdp bzero(rup, sizeof(*rup)); 134033965Sjdp if (up != NULL) { 134133965Sjdp bcopy(up->id, rup->id, sizeof(rup->id)); 134260484Sobrien rup->creatorid = up->creatorid; 134333965Sjdp } 134433965Sjdp 134560484Sobrien if (h->count == sc->sc_maxcount) 134633965Sjdp ret = pfsync_sendout(sc); 134733965Sjdp 134833965Sjdp return (ret); 134933965Sjdp} 135033965Sjdp 135133965Sjdpint 135233965Sjdppfsync_clear_states(u_int32_t creatorid, char *ifname) 135360484Sobrien{ 135433965Sjdp#ifdef __FreeBSD__ 135533965Sjdp struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 135633965Sjdp#else 135733965Sjdp struct ifnet *ifp = &pfsyncif.sc_if; 135833965Sjdp#endif 135933965Sjdp struct pfsync_softc *sc = ifp->if_softc; 136033965Sjdp struct pfsync_state_clr *cp; 136133965Sjdp int s, ret; 136233965Sjdp 136333965Sjdp s = splnet(); 136433965Sjdp#ifdef __FreeBSD__ 136533965Sjdp PF_ASSERT(MA_OWNED); 136633965Sjdp#endif 136733965Sjdp if (sc->sc_mbuf != NULL) 136833965Sjdp pfsync_sendout(sc); 136933965Sjdp if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, 137060484Sobrien (void *)&sc->sc_statep.c)) == NULL) { 137133965Sjdp splx(s); 137233965Sjdp return (ENOMEM); 137333965Sjdp } 137433965Sjdp sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); 137533965Sjdp cp = sc->sc_statep.c; 137633965Sjdp cp->creatorid = creatorid; 137760484Sobrien if (ifname != NULL) 137833965Sjdp strlcpy(cp->ifname, ifname, IFNAMSIZ); 137933965Sjdp 138060484Sobrien ret = (pfsync_sendout(sc)); 138133965Sjdp splx(s); 138233965Sjdp return (ret); 138333965Sjdp} 138433965Sjdp 138533965Sjdpvoid 138633965Sjdppfsync_timeout(void *v) 138733965Sjdp{ 138860484Sobrien struct pfsync_softc *sc = v; 138933965Sjdp int s; 139033965Sjdp 139133965Sjdp s = splnet(); 139233965Sjdp#ifdef __FreeBSD__ 139333965Sjdp PF_LOCK(); 139433965Sjdp#endif 139533965Sjdp pfsync_sendout(sc); 139633965Sjdp#ifdef __FreeBSD__ 139733965Sjdp PF_UNLOCK(); 139833965Sjdp#endif 139933965Sjdp splx(s); 140033965Sjdp} 140133965Sjdp 140233965Sjdpvoid 140333965Sjdppfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) 140433965Sjdp{ 140533965Sjdp struct pfsync_state_bus *bus; 140633965Sjdp 140760484Sobrien#ifdef __FreeBSD__ 140833965Sjdp PF_ASSERT(MA_OWNED); 140933965Sjdp#endif 141033965Sjdp if (sc->sc_mbuf != NULL) 141133965Sjdp pfsync_sendout(sc); 141233965Sjdp 141333965Sjdp if (pfsync_sync_ok && 141433965Sjdp (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, 141533965Sjdp (void *)&sc->sc_statep.b)) != NULL) { 141633965Sjdp sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); 141733965Sjdp bus = sc->sc_statep.b; 141833965Sjdp bus->creatorid = pf_status.hostid; 141933965Sjdp bus->status = status; 142033965Sjdp#ifdef __FreeBSD__ 142133965Sjdp bus->endtime = htonl(time_uptime - sc->sc_ureq_received); 142233965Sjdp#else 142333965Sjdp bus->endtime = htonl(mono_time.tv_sec - sc->sc_ureq_received); 142433965Sjdp#endif 142533965Sjdp pfsync_sendout(sc); 142633965Sjdp } 142733965Sjdp} 142833965Sjdp 142933965Sjdpvoid 143033965Sjdppfsync_bulk_update(void *v) 143133965Sjdp{ 143233965Sjdp struct pfsync_softc *sc = v; 143333965Sjdp int s, i = 0; 143433965Sjdp struct pf_state *state; 143533965Sjdp 143633965Sjdp#ifdef __FreeBSD__ 143733965Sjdp PF_LOCK(); 143833965Sjdp#endif 143933965Sjdp s = splnet(); 144033965Sjdp if (sc->sc_mbuf != NULL) 144133965Sjdp pfsync_sendout(sc); 144233965Sjdp 144333965Sjdp /* 144433965Sjdp * Grab at most PFSYNC_BULKPACKETS worth of states which have not 144533965Sjdp * been sent since the latest request was made. 144633965Sjdp */ 144733965Sjdp while ((state = TAILQ_FIRST(&state_updates)) != NULL && 144833965Sjdp ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) { 144933965Sjdp if (state->pfsync_time > sc->sc_ureq_received) { 145033965Sjdp /* we're done */ 145133965Sjdp pfsync_send_bus(sc, PFSYNC_BUS_END); 145233965Sjdp sc->sc_ureq_received = 0; 145333965Sjdp#ifdef __FreeBSD__ 145433965Sjdp callout_stop(&sc->sc_bulk_tmo); 145533965Sjdp#else 145633965Sjdp timeout_del(&sc->sc_bulk_tmo); 145733965Sjdp#endif 145833965Sjdp if (pf_status.debug >= PF_DEBUG_MISC) 145933965Sjdp printf("pfsync: bulk update complete\n"); 146033965Sjdp break; 146133965Sjdp } else { 146233965Sjdp /* send an update and move to end of list */ 146333965Sjdp if (!state->sync_flags) 146433965Sjdp pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); 146533965Sjdp#ifdef __FreeBSD__ 146633965Sjdp state->pfsync_time = time_uptime; 146733965Sjdp#else 146833965Sjdp state->pfsync_time = mono_time.tv_sec; 146933965Sjdp#endif 147033965Sjdp TAILQ_REMOVE(&state_updates, state, u.s.entry_updates); 147133965Sjdp TAILQ_INSERT_TAIL(&state_updates, state, 147233965Sjdp u.s.entry_updates); 147333965Sjdp 147433965Sjdp /* look again for more in a bit */ 147533965Sjdp#ifdef __FreeBSD__ 147633965Sjdp callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout, 147733965Sjdp LIST_FIRST(&pfsync_list)); 147833965Sjdp#else 147933965Sjdp timeout_add(&sc->sc_bulk_tmo, 1); 148033965Sjdp#endif 148133965Sjdp } 148233965Sjdp } 148333965Sjdp if (sc->sc_mbuf != NULL) 148433965Sjdp pfsync_sendout(sc); 148533965Sjdp splx(s); 148633965Sjdp#ifdef __FreeBSD__ 148733965Sjdp PF_UNLOCK(); 148833965Sjdp#endif 148933965Sjdp} 149033965Sjdp 149133965Sjdpvoid 149233965Sjdppfsync_bulkfail(void *v) 149333965Sjdp{ 149433965Sjdp struct pfsync_softc *sc = v; 149533965Sjdp 149633965Sjdp#ifdef __FreeBSD__ 149733965Sjdp PF_LOCK(); 149860484Sobrien#endif 1499 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 1500 /* Try again in a bit */ 1501#ifdef __FreeBSD__ 1502 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, 1503 LIST_FIRST(&pfsync_list)); 1504#else 1505 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1506#endif 1507 pfsync_request_update(NULL, NULL); 1508 pfsync_sendout(sc); 1509 } else { 1510 /* Pretend like the transfer was ok */ 1511 sc->sc_ureq_sent = 0; 1512 sc->sc_bulk_tries = 0; 1513 pfsync_sync_ok = 1; 1514 if (pf_status.debug >= PF_DEBUG_MISC) 1515 printf("pfsync: failed to receive " 1516 "bulk update status\n"); 1517#ifdef __FreeBSD__ 1518 callout_stop(&sc->sc_bulkfail_tmo); 1519#else 1520 timeout_del(&sc->sc_bulkfail_tmo); 1521#endif 1522 } 1523#ifdef __FreeBSD__ 1524 PF_UNLOCK(); 1525#endif 1526} 1527 1528int 1529pfsync_sendout(sc) 1530 struct pfsync_softc *sc; 1531{ 1532#if NBPFILTER > 0 1533 struct ifnet *ifp = &sc->sc_if; 1534#endif 1535 struct mbuf *m; 1536 1537#ifdef __FreeBSD__ 1538 PF_ASSERT(MA_OWNED); 1539 callout_stop(&sc->sc_tmo); 1540#else 1541 timeout_del(&sc->sc_tmo); 1542#endif 1543 1544 if (sc->sc_mbuf == NULL) 1545 return (0); 1546 m = sc->sc_mbuf; 1547 sc->sc_mbuf = NULL; 1548 sc->sc_statep.s = NULL; 1549 1550#ifdef __FreeBSD__ 1551 KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); 1552#endif 1553#if NBPFILTER > 0 1554 if (ifp->if_bpf) 1555 bpf_mtap(ifp->if_bpf, m); 1556#endif 1557 1558 if (sc->sc_mbuf_net) { 1559 m_freem(m); 1560 m = sc->sc_mbuf_net; 1561 sc->sc_mbuf_net = NULL; 1562 sc->sc_statep_net.s = NULL; 1563 } 1564 1565 if (sc->sc_sync_ifp) { 1566 struct ip *ip; 1567 struct ifaddr *ifa; 1568 struct sockaddr sa; 1569 1570 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 1571 if (m == NULL) { 1572 pfsyncstats.pfsyncs_onomem++; 1573 return (0); 1574 } 1575 ip = mtod(m, struct ip *); 1576 ip->ip_v = IPVERSION; 1577 ip->ip_hl = sizeof(*ip) >> 2; 1578 ip->ip_tos = IPTOS_LOWDELAY; 1579#ifdef __FreeBSD__ 1580 ip->ip_len = m->m_pkthdr.len; 1581#else 1582 ip->ip_len = htons(m->m_pkthdr.len); 1583#endif 1584 ip->ip_id = htons(ip_randomid()); 1585#ifdef __FreeBSD__ 1586 ip->ip_off = IP_DF; 1587#else 1588 ip->ip_off = htons(IP_DF); 1589#endif 1590 ip->ip_ttl = PFSYNC_DFLTTL; 1591 ip->ip_p = IPPROTO_PFSYNC; 1592 ip->ip_sum = 0; 1593 1594 bzero(&sa, sizeof(sa)); 1595 sa.sa_family = AF_INET; 1596 ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp); 1597 if (ifa == NULL) 1598 return (0); 1599 ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; 1600 1601#ifdef __FreeBSD__ 1602 if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) 1603#else 1604 if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) 1605#endif 1606 m->m_flags |= M_MCAST; 1607 ip->ip_dst = sc->sc_sendaddr; 1608#ifdef __FreeBSD__ 1609 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1610#else 1611 sc->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; 1612#endif 1613 1614 pfsyncstats.pfsyncs_opackets++; 1615 1616#ifdef __FreeBSD__ 1617 PF_UNLOCK(); 1618#endif 1619 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1620 pfsyncstats.pfsyncs_oerrors++; 1621 1622#ifdef __FreeBSD__ 1623 PF_LOCK(); 1624#endif 1625 } else 1626 m_freem(m); 1627 1628 return (0); 1629} 1630 1631 1632#ifdef __FreeBSD__ 1633static int 1634pfsync_modevent(module_t mod, int type, void *data) 1635{ 1636 int error = 0; 1637 1638 switch (type) { 1639 case MOD_LOAD: 1640 LIST_INIT(&pfsync_list); 1641 if_clone_attach(&pfsync_cloner); 1642 break; 1643 1644 case MOD_UNLOAD: 1645 if_clone_detach(&pfsync_cloner); 1646 while (!LIST_EMPTY(&pfsync_list)) 1647 pfsync_clone_destroy( 1648 &LIST_FIRST(&pfsync_list)->sc_if); 1649 break; 1650 1651 default: 1652 error = EINVAL; 1653 break; 1654 } 1655 1656 return error; 1657} 1658 1659static moduledata_t pfsync_mod = { 1660 "pfsync", 1661 pfsync_modevent, 1662 0 1663}; 1664 1665#define PFSYNC_MODVER 1 1666 1667DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 1668MODULE_VERSION(pfsync, PFSYNC_MODVER); 1669#endif /* __FreeBSD__ */ 1670