if_pfsync.c revision 246822
1244769Sglebius/*- 2126258Smlaier * Copyright (c) 2002 Michael Shalayeff 3244769Sglebius * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 4126258Smlaier * All rights reserved. 5126258Smlaier * 6126258Smlaier * Redistribution and use in source and binary forms, with or without 7126258Smlaier * modification, are permitted provided that the following conditions 8126258Smlaier * are met: 9126258Smlaier * 1. Redistributions of source code must retain the above copyright 10126258Smlaier * notice, this list of conditions and the following disclaimer. 11126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright 12126258Smlaier * notice, this list of conditions and the following disclaimer in the 13126258Smlaier * documentation and/or other materials provided with the distribution. 14126258Smlaier * 15126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 19126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 25126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE. 26126258Smlaier */ 27126258Smlaier 28244769Sglebius/*- 29223637Sbz * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> 30223637Sbz * 31223637Sbz * Permission to use, copy, modify, and distribute this software for any 32223637Sbz * purpose with or without fee is hereby granted, provided that the above 33223637Sbz * copyright notice and this permission notice appear in all copies. 34223637Sbz * 35223637Sbz * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 36223637Sbz * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 37223637Sbz * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 38223637Sbz * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 39223637Sbz * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 40223637Sbz * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 41223637Sbz * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 42223637Sbz */ 43223637Sbz 44228814Sglebius/* 45244769Sglebius * $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ 46244769Sglebius * 47228814Sglebius * Revisions picked from OpenBSD after revision 1.110 import: 48244185Sglebius * 1.119 - don't m_copydata() beyond the len of mbuf in pfsync_input() 49228814Sglebius * 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates 50228815Sglebius * 1.120, 1.175 - use monotonic time_uptime 51228816Sglebius * 1.122 - reduce number of updates for non-TCP sessions 52244113Sglebius * 1.125, 1.127 - rewrite merge or stale processing 53229961Sglebius * 1.128 - cleanups 54232685Sglebius * 1.146 - bzero() mbuf before sparsely filling it with data 55229777Sglebius * 1.170 - SIOCSIFMTU checks 56233846Sglebius * 1.126, 1.142 - deferred packets processing 57233874Sglebius * 1.173 - correct expire time processing 58228814Sglebius */ 59228814Sglebius 60240233Sglebius#include <sys/cdefs.h> 61240233Sglebius__FBSDID("$FreeBSD: head/sys/netpfil/pf/if_pfsync.c 246822 2013-02-15 09:03:56Z glebius $"); 62240233Sglebius 63126261Smlaier#include "opt_inet.h" 64126261Smlaier#include "opt_inet6.h" 65126261Smlaier#include "opt_pf.h" 66153110Sru 67126258Smlaier#include <sys/param.h> 68223637Sbz#include <sys/bus.h> 69240233Sglebius#include <sys/endian.h> 70223637Sbz#include <sys/interrupt.h> 71240233Sglebius#include <sys/kernel.h> 72240233Sglebius#include <sys/lock.h> 73126258Smlaier#include <sys/mbuf.h> 74129907Smlaier#include <sys/module.h> 75130613Smlaier#include <sys/mutex.h> 76240233Sglebius#include <sys/priv.h> 77229850Sglebius#include <sys/protosw.h> 78240233Sglebius#include <sys/socket.h> 79240233Sglebius#include <sys/sockio.h> 80223637Sbz#include <sys/sysctl.h> 81126258Smlaier 82240233Sglebius#include <net/bpf.h> 83126258Smlaier#include <net/if.h> 84130933Sbrooks#include <net/if_clone.h> 85126258Smlaier#include <net/if_types.h> 86240233Sglebius#include <net/pfvar.h> 87240233Sglebius#include <net/if_pfsync.h> 88223637Sbz 89240233Sglebius#include <netinet/if_ether.h> 90171168Smlaier#include <netinet/in.h> 91126258Smlaier#include <netinet/in_var.h> 92130613Smlaier#include <netinet/ip.h> 93240233Sglebius#include <netinet/ip_carp.h> 94130613Smlaier#include <netinet/ip_var.h> 95240233Sglebius#include <netinet/tcp.h> 96240233Sglebius#include <netinet/tcp_fsm.h> 97240233Sglebius#include <netinet/tcp_seq.h> 98126258Smlaier 99223637Sbz#define PFSYNC_MINPKT ( \ 100223637Sbz sizeof(struct ip) + \ 101223637Sbz sizeof(struct pfsync_header) + \ 102246822Sglebius sizeof(struct pfsync_subheader) ) 103126258Smlaier 104223637Sbzstruct pfsync_pkt { 105223637Sbz struct ip *ip; 106223637Sbz struct in_addr src; 107223637Sbz u_int8_t flags; 108223637Sbz}; 109223637Sbz 110240233Sglebiusstatic int pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *, 111240233Sglebius struct pfsync_state_peer *); 112240233Sglebiusstatic int pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int); 113240233Sglebiusstatic int pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int); 114240233Sglebiusstatic int pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int); 115240233Sglebiusstatic int pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int); 116240233Sglebiusstatic int pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int); 117240233Sglebiusstatic int pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int); 118240233Sglebiusstatic int pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int); 119240233Sglebiusstatic int pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int); 120240233Sglebiusstatic int pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int); 121240233Sglebiusstatic int pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int); 122240233Sglebiusstatic int pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int); 123240233Sglebiusstatic int pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int); 124223637Sbz 125240233Sglebiusstatic int (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = { 126223637Sbz pfsync_in_clr, /* PFSYNC_ACT_CLR */ 127223637Sbz pfsync_in_ins, /* PFSYNC_ACT_INS */ 128223637Sbz pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ 129223637Sbz pfsync_in_upd, /* PFSYNC_ACT_UPD */ 130223637Sbz pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ 131223637Sbz pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ 132223637Sbz pfsync_in_del, /* PFSYNC_ACT_DEL */ 133223637Sbz pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ 134223637Sbz pfsync_in_error, /* PFSYNC_ACT_INS_F */ 135223637Sbz pfsync_in_error, /* PFSYNC_ACT_DEL_F */ 136223637Sbz pfsync_in_bus, /* PFSYNC_ACT_BUS */ 137223637Sbz pfsync_in_tdb, /* PFSYNC_ACT_TDB */ 138223637Sbz pfsync_in_eof /* PFSYNC_ACT_EOF */ 139223637Sbz}; 140223637Sbz 141223637Sbzstruct pfsync_q { 142241056Sglebius void (*write)(struct pf_state *, void *); 143223637Sbz size_t len; 144223637Sbz u_int8_t action; 145223637Sbz}; 146223637Sbz 147223637Sbz/* we have one of these for every PFSYNC_S_ */ 148241056Sglebiusstatic void pfsync_out_state(struct pf_state *, void *); 149241056Sglebiusstatic void pfsync_out_iack(struct pf_state *, void *); 150241056Sglebiusstatic void pfsync_out_upd_c(struct pf_state *, void *); 151241056Sglebiusstatic void pfsync_out_del(struct pf_state *, void *); 152223637Sbz 153240233Sglebiusstatic struct pfsync_q pfsync_qs[] = { 154223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS }, 155223637Sbz { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, 156223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD }, 157223637Sbz { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, 158223637Sbz { pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } 159223637Sbz}; 160223637Sbz 161240233Sglebiusstatic void pfsync_q_ins(struct pf_state *, int); 162240233Sglebiusstatic void pfsync_q_del(struct pf_state *); 163223637Sbz 164240233Sglebiusstatic void pfsync_update_state(struct pf_state *); 165240233Sglebius 166223637Sbzstruct pfsync_upd_req_item { 167223637Sbz TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; 168223637Sbz struct pfsync_upd_req ur_msg; 169223637Sbz}; 170223637Sbz 171223637Sbzstruct pfsync_deferral { 172240233Sglebius struct pfsync_softc *pd_sc; 173240233Sglebius TAILQ_ENTRY(pfsync_deferral) pd_entry; 174240233Sglebius u_int pd_refs; 175240233Sglebius struct callout pd_tmo; 176240233Sglebius 177240233Sglebius struct pf_state *pd_st; 178240233Sglebius struct mbuf *pd_m; 179223637Sbz}; 180126258Smlaier 181223637Sbzstruct pfsync_softc { 182240233Sglebius /* Configuration */ 183223637Sbz struct ifnet *sc_ifp; 184223637Sbz struct ifnet *sc_sync_if; 185240233Sglebius struct ip_moptions sc_imo; 186240233Sglebius struct in_addr sc_sync_peer; 187240233Sglebius uint32_t sc_flags; 188240233Sglebius#define PFSYNCF_OK 0x00000001 189240233Sglebius#define PFSYNCF_DEFER 0x00000002 190240233Sglebius#define PFSYNCF_PUSH 0x00000004 191240233Sglebius uint8_t sc_maxupdates; 192240233Sglebius struct ip sc_template; 193240233Sglebius struct callout sc_tmo; 194240233Sglebius struct mtx sc_mtx; 195223637Sbz 196240233Sglebius /* Queued data */ 197240233Sglebius size_t sc_len; 198240233Sglebius TAILQ_HEAD(, pf_state) sc_qs[PFSYNC_S_COUNT]; 199240233Sglebius TAILQ_HEAD(, pfsync_upd_req_item) sc_upd_req_list; 200240233Sglebius TAILQ_HEAD(, pfsync_deferral) sc_deferrals; 201240233Sglebius u_int sc_deferred; 202223637Sbz void *sc_plus; 203240233Sglebius size_t sc_pluslen; 204223637Sbz 205240233Sglebius /* Bulk update info */ 206240233Sglebius struct mtx sc_bulk_mtx; 207240233Sglebius uint32_t sc_ureq_sent; 208240233Sglebius int sc_bulk_tries; 209240233Sglebius uint32_t sc_ureq_received; 210240233Sglebius int sc_bulk_hashid; 211240233Sglebius uint64_t sc_bulk_stateid; 212240233Sglebius uint32_t sc_bulk_creatorid; 213240233Sglebius struct callout sc_bulk_tmo; 214240233Sglebius struct callout sc_bulkfail_tmo; 215240233Sglebius}; 216223637Sbz 217240233Sglebius#define PFSYNC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 218240233Sglebius#define PFSYNC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 219240233Sglebius#define PFSYNC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) 220223637Sbz 221240233Sglebius#define PFSYNC_BLOCK(sc) mtx_lock(&(sc)->sc_bulk_mtx) 222240233Sglebius#define PFSYNC_BUNLOCK(sc) mtx_unlock(&(sc)->sc_bulk_mtx) 223240233Sglebius#define PFSYNC_BLOCK_ASSERT(sc) mtx_assert(&(sc)->sc_bulk_mtx, MA_OWNED) 224223637Sbz 225241610Sglebiusstatic const char pfsyncname[] = "pfsync"; 226241610Sglebiusstatic MALLOC_DEFINE(M_PFSYNC, pfsyncname, "pfsync(4) data"); 227223637Sbzstatic VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 228223637Sbz#define V_pfsyncif VNET(pfsyncif) 229229850Sglebiusstatic VNET_DEFINE(void *, pfsync_swi_cookie) = NULL; 230229850Sglebius#define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) 231223637Sbzstatic VNET_DEFINE(struct pfsyncstats, pfsyncstats); 232223637Sbz#define V_pfsyncstats VNET(pfsyncstats) 233228736Sglebiusstatic VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW; 234228736Sglebius#define V_pfsync_carp_adj VNET(pfsync_carp_adj) 235223637Sbz 236240233Sglebiusstatic void pfsync_timeout(void *); 237240233Sglebiusstatic void pfsync_push(struct pfsync_softc *); 238229850Sglebiusstatic void pfsyncintr(void *); 239240233Sglebiusstatic int pfsync_multicast_setup(struct pfsync_softc *, struct ifnet *, 240240233Sglebius void *); 241229850Sglebiusstatic void pfsync_multicast_cleanup(struct pfsync_softc *); 242241057Sglebiusstatic void pfsync_pointers_init(void); 243241057Sglebiusstatic void pfsync_pointers_uninit(void); 244229850Sglebiusstatic int pfsync_init(void); 245229850Sglebiusstatic void pfsync_uninit(void); 246229850Sglebius 247223637SbzSYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 248223637SbzSYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 249223637Sbz &VNET_NAME(pfsyncstats), pfsyncstats, 250223637Sbz "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 251228736SglebiusSYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_RW, 252228736Sglebius &VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment"); 253223637Sbz 254240233Sglebiusstatic int pfsync_clone_create(struct if_clone *, int, caddr_t); 255240233Sglebiusstatic void pfsync_clone_destroy(struct ifnet *); 256240233Sglebiusstatic int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 257240233Sglebius struct pf_state_peer *); 258240233Sglebiusstatic int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 259240233Sglebius struct route *); 260240233Sglebiusstatic int pfsyncioctl(struct ifnet *, u_long, caddr_t); 261126258Smlaier 262240233Sglebiusstatic int pfsync_defer(struct pf_state *, struct mbuf *); 263240233Sglebiusstatic void pfsync_undefer(struct pfsync_deferral *, int); 264240233Sglebiusstatic void pfsync_undefer_state(struct pf_state *, int); 265240233Sglebiusstatic void pfsync_defer_tmo(void *); 266223637Sbz 267240233Sglebiusstatic void pfsync_request_update(u_int32_t, u_int64_t); 268240233Sglebiusstatic void pfsync_update_state_req(struct pf_state *); 269223637Sbz 270240233Sglebiusstatic void pfsync_drop(struct pfsync_softc *); 271240233Sglebiusstatic void pfsync_sendout(int); 272240233Sglebiusstatic void pfsync_send_plus(void *, size_t); 273223637Sbz 274240233Sglebiusstatic void pfsync_bulk_start(void); 275240233Sglebiusstatic void pfsync_bulk_status(u_int8_t); 276240233Sglebiusstatic void pfsync_bulk_update(void *); 277240233Sglebiusstatic void pfsync_bulk_fail(void *); 278223637Sbz 279240233Sglebius#ifdef IPSEC 280240233Sglebiusstatic void pfsync_update_net_tdb(struct pfsync_tdb *); 281167710Sbms#endif 282126258Smlaier 283223637Sbz#define PFSYNC_MAX_BULKTRIES 12 284126258Smlaier 285241610SglebiusVNET_DEFINE(struct if_clone *, pfsync_cloner); 286241610Sglebius#define V_pfsync_cloner VNET(pfsync_cloner) 287126261Smlaier 288240233Sglebiusstatic int 289171168Smlaierpfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 290126261Smlaier{ 291223637Sbz struct pfsync_softc *sc; 292130613Smlaier struct ifnet *ifp; 293223637Sbz int q; 294126261Smlaier 295171168Smlaier if (unit != 0) 296171168Smlaier return (EINVAL); 297171168Smlaier 298229850Sglebius sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); 299240233Sglebius sc->sc_flags |= PFSYNCF_OK; 300223637Sbz 301223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) 302223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 303223637Sbz 304223637Sbz TAILQ_INIT(&sc->sc_upd_req_list); 305223637Sbz TAILQ_INIT(&sc->sc_deferrals); 306171168Smlaier 307223637Sbz sc->sc_len = PFSYNC_MINPKT; 308223637Sbz sc->sc_maxupdates = 128; 309223637Sbz 310223637Sbz ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 311147256Sbrooks if (ifp == NULL) { 312229850Sglebius free(sc, M_PFSYNC); 313147256Sbrooks return (ENOSPC); 314147256Sbrooks } 315241610Sglebius if_initname(ifp, pfsyncname, unit); 316223637Sbz ifp->if_softc = sc; 317130613Smlaier ifp->if_ioctl = pfsyncioctl; 318130613Smlaier ifp->if_output = pfsyncoutput; 319171168Smlaier ifp->if_type = IFT_PFSYNC; 320130613Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 321223637Sbz ifp->if_hdrlen = sizeof(struct pfsync_header); 322229777Sglebius ifp->if_mtu = ETHERMTU; 323241610Sglebius mtx_init(&sc->sc_mtx, pfsyncname, NULL, MTX_DEF); 324240233Sglebius mtx_init(&sc->sc_bulk_mtx, "pfsync bulk", NULL, MTX_DEF); 325223637Sbz callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); 326240233Sglebius callout_init_mtx(&sc->sc_bulk_tmo, &sc->sc_bulk_mtx, 0); 327240233Sglebius callout_init_mtx(&sc->sc_bulkfail_tmo, &sc->sc_bulk_mtx, 0); 328223637Sbz 329141584Smlaier if_attach(ifp); 330126261Smlaier 331141584Smlaier bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 332126261Smlaier 333223637Sbz V_pfsyncif = sc; 334223637Sbz 335126261Smlaier return (0); 336126261Smlaier} 337171168Smlaier 338240233Sglebiusstatic void 339171168Smlaierpfsync_clone_destroy(struct ifnet *ifp) 340126258Smlaier{ 341223637Sbz struct pfsync_softc *sc = ifp->if_softc; 342223637Sbz 343240233Sglebius /* 344240233Sglebius * At this stage, everything should have already been 345240233Sglebius * cleared by pfsync_uninit(), and we have only to 346240233Sglebius * drain callouts. 347240233Sglebius */ 348240233Sglebius while (sc->sc_deferred > 0) { 349240233Sglebius struct pfsync_deferral *pd = TAILQ_FIRST(&sc->sc_deferrals); 350240233Sglebius 351240233Sglebius TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 352240233Sglebius sc->sc_deferred--; 353240233Sglebius if (callout_stop(&pd->pd_tmo)) { 354240233Sglebius pf_release_state(pd->pd_st); 355240233Sglebius m_freem(pd->pd_m); 356240233Sglebius free(pd, M_PFSYNC); 357240233Sglebius } else { 358240233Sglebius pd->pd_refs++; 359240233Sglebius callout_drain(&pd->pd_tmo); 360240233Sglebius free(pd, M_PFSYNC); 361240233Sglebius } 362240233Sglebius } 363240233Sglebius 364240233Sglebius callout_drain(&sc->sc_tmo); 365240233Sglebius callout_drain(&sc->sc_bulkfail_tmo); 366240233Sglebius callout_drain(&sc->sc_bulk_tmo); 367240233Sglebius 368240233Sglebius if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 369228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy"); 370171168Smlaier bpfdetach(ifp); 371171168Smlaier if_detach(ifp); 372223637Sbz 373223637Sbz pfsync_drop(sc); 374223637Sbz 375171168Smlaier if_free(ifp); 376229850Sglebius if (sc->sc_imo.imo_membership) 377229850Sglebius pfsync_multicast_cleanup(sc); 378240233Sglebius mtx_destroy(&sc->sc_mtx); 379240233Sglebius mtx_destroy(&sc->sc_bulk_mtx); 380229850Sglebius free(sc, M_PFSYNC); 381223637Sbz 382223637Sbz V_pfsyncif = NULL; 383126258Smlaier} 384126258Smlaier 385240233Sglebiusstatic int 386171168Smlaierpfsync_alloc_scrub_memory(struct pfsync_state_peer *s, 387171168Smlaier struct pf_state_peer *d) 388130613Smlaier{ 389171168Smlaier if (s->scrub.scrub_flag && d->scrub == NULL) { 390240233Sglebius d->scrub = uma_zalloc(V_pf_state_scrub_z, M_NOWAIT | M_ZERO); 391171168Smlaier if (d->scrub == NULL) 392171168Smlaier return (ENOMEM); 393171168Smlaier } 394171168Smlaier 395171168Smlaier return (0); 396171168Smlaier} 397171168Smlaier 398223637Sbz 399240233Sglebiusstatic int 400223637Sbzpfsync_state_import(struct pfsync_state *sp, u_int8_t flags) 401171168Smlaier{ 402240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 403130613Smlaier struct pf_state *st = NULL; 404223637Sbz struct pf_state_key *skw = NULL, *sks = NULL; 405130613Smlaier struct pf_rule *r = NULL; 406130613Smlaier struct pfi_kif *kif; 407223637Sbz int error; 408130613Smlaier 409240233Sglebius PF_RULES_RASSERT(); 410226544Sbz 411223637Sbz if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) { 412240233Sglebius printf("%s: invalid creator id: %08x\n", __func__, 413240233Sglebius ntohl(sp->creatorid)); 414130613Smlaier return (EINVAL); 415130613Smlaier } 416130613Smlaier 417240233Sglebius if ((kif = pfi_kif_find(sp->ifname)) == NULL) { 418223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 419240233Sglebius printf("%s: unknown interface: %s\n", __func__, 420240233Sglebius sp->ifname); 421223637Sbz if (flags & PFSYNC_SI_IOCTL) 422223637Sbz return (EINVAL); 423223637Sbz return (0); /* skip this state */ 424130613Smlaier } 425130613Smlaier 426130613Smlaier /* 427223637Sbz * If the ruleset checksums match or the state is coming from the ioctl, 428223637Sbz * it's safe to associate the state with the rule of that number. 429130613Smlaier */ 430223637Sbz if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && 431223637Sbz (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < 432223637Sbz pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 433171168Smlaier r = pf_main_ruleset.rules[ 434171168Smlaier PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; 435171168Smlaier else 436223637Sbz r = &V_pf_default_rule; 437130613Smlaier 438223637Sbz if ((r->max_states && r->states_cur >= r->max_states)) 439223637Sbz goto cleanup; 440130613Smlaier 441240233Sglebius /* 442240233Sglebius * XXXGL: consider M_WAITOK in ioctl path after. 443240233Sglebius */ 444240233Sglebius if ((st = uma_zalloc(V_pf_state_z, M_NOWAIT | M_ZERO)) == NULL) 445223637Sbz goto cleanup; 446130613Smlaier 447240233Sglebius if ((skw = uma_zalloc(V_pf_state_key_z, M_NOWAIT)) == NULL) 448223637Sbz goto cleanup; 449145836Smlaier 450223637Sbz if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], 451223637Sbz &sp->key[PF_SK_STACK].addr[0], sp->af) || 452223637Sbz PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], 453223637Sbz &sp->key[PF_SK_STACK].addr[1], sp->af) || 454223637Sbz sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || 455223637Sbz sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { 456240233Sglebius sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT); 457240233Sglebius if (sks == NULL) 458223637Sbz goto cleanup; 459223637Sbz } else 460223637Sbz sks = skw; 461130613Smlaier 462223637Sbz /* allocate memory for scrub info */ 463223637Sbz if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || 464223637Sbz pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) 465223637Sbz goto cleanup; 466223637Sbz 467223637Sbz /* copy to state key(s) */ 468223637Sbz skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; 469223637Sbz skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; 470223637Sbz skw->port[0] = sp->key[PF_SK_WIRE].port[0]; 471223637Sbz skw->port[1] = sp->key[PF_SK_WIRE].port[1]; 472223637Sbz skw->proto = sp->proto; 473223637Sbz skw->af = sp->af; 474223637Sbz if (sks != skw) { 475223637Sbz sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; 476223637Sbz sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; 477223637Sbz sks->port[0] = sp->key[PF_SK_STACK].port[0]; 478223637Sbz sks->port[1] = sp->key[PF_SK_STACK].port[1]; 479223637Sbz sks->proto = sp->proto; 480223637Sbz sks->af = sp->af; 481223637Sbz } 482223637Sbz 483223637Sbz /* copy to state */ 484130613Smlaier bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 485228815Sglebius st->creation = time_uptime - ntohl(sp->creation); 486240233Sglebius st->expire = time_uptime; 487223637Sbz if (sp->expire) { 488233874Sglebius uint32_t timeout; 489233874Sglebius 490233874Sglebius timeout = r->timeout[sp->timeout]; 491233874Sglebius if (!timeout) 492233917Sae timeout = V_pf_default_rule.timeout[sp->timeout]; 493233874Sglebius 494233874Sglebius /* sp->expire may have been adaptively scaled by export. */ 495233874Sglebius st->expire -= timeout - ntohl(sp->expire); 496223637Sbz } 497223637Sbz 498130613Smlaier st->direction = sp->direction; 499130613Smlaier st->log = sp->log; 500130613Smlaier st->timeout = sp->timeout; 501200930Sdelphij st->state_flags = sp->state_flags; 502130613Smlaier 503240233Sglebius st->id = sp->id; 504130613Smlaier st->creatorid = sp->creatorid; 505223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 506223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 507130613Smlaier 508223637Sbz st->rule.ptr = r; 509223637Sbz st->nat_rule.ptr = NULL; 510223637Sbz st->anchor.ptr = NULL; 511223637Sbz st->rt_kif = NULL; 512223637Sbz 513228815Sglebius st->pfsync_time = time_uptime; 514223637Sbz st->sync_state = PFSYNC_S_NONE; 515223637Sbz 516223637Sbz /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 517223637Sbz r->states_cur++; 518223637Sbz r->states_tot++; 519223637Sbz 520240233Sglebius if (!(flags & PFSYNC_SI_IOCTL)) 521240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 522223637Sbz 523223637Sbz if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { 524145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 525223637Sbz r->states_cur--; 526223637Sbz goto cleanup_state; 527223637Sbz } 528223637Sbz 529240233Sglebius if (!(flags & PFSYNC_SI_IOCTL)) { 530240233Sglebius st->state_flags &= ~PFSTATE_NOSYNC; 531240233Sglebius if (st->state_flags & PFSTATE_ACK) { 532223637Sbz pfsync_q_ins(st, PFSYNC_S_IACK); 533240233Sglebius pfsync_push(sc); 534223637Sbz } 535223637Sbz } 536240233Sglebius st->state_flags &= ~PFSTATE_ACK; 537240233Sglebius PF_STATE_UNLOCK(st); 538223637Sbz 539223637Sbz return (0); 540223637Sbz 541223637Sbzcleanup: 542223637Sbz error = ENOMEM; 543223637Sbz if (skw == sks) 544223637Sbz sks = NULL; 545223637Sbz if (skw != NULL) 546240233Sglebius uma_zfree(V_pf_state_key_z, skw); 547223637Sbz if (sks != NULL) 548240233Sglebius uma_zfree(V_pf_state_key_z, sks); 549223637Sbz 550240233Sglebiuscleanup_state: /* pf_state_insert() frees the state keys. */ 551223637Sbz if (st) { 552171168Smlaier if (st->dst.scrub) 553240233Sglebius uma_zfree(V_pf_state_scrub_z, st->dst.scrub); 554223637Sbz if (st->src.scrub) 555240233Sglebius uma_zfree(V_pf_state_scrub_z, st->src.scrub); 556240233Sglebius uma_zfree(V_pf_state_z, st); 557130613Smlaier } 558223637Sbz return (error); 559130613Smlaier} 560130613Smlaier 561240233Sglebiusstatic void 562130613Smlaierpfsync_input(struct mbuf *m, __unused int off) 563130613Smlaier{ 564223637Sbz struct pfsync_softc *sc = V_pfsyncif; 565223637Sbz struct pfsync_pkt pkt; 566130613Smlaier struct ip *ip = mtod(m, struct ip *); 567130613Smlaier struct pfsync_header *ph; 568223637Sbz struct pfsync_subheader subh; 569130613Smlaier 570244185Sglebius int offset, len; 571223637Sbz int rv; 572240233Sglebius uint16_t count; 573130613Smlaier 574223637Sbz V_pfsyncstats.pfsyncs_ipackets++; 575223637Sbz 576240233Sglebius /* Verify that we have a sync interface configured. */ 577240233Sglebius if (!sc || !sc->sc_sync_if || !V_pf_status.running || 578240233Sglebius (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 579130613Smlaier goto done; 580130613Smlaier 581130613Smlaier /* verify that the packet came in on the right interface */ 582223637Sbz if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 583223637Sbz V_pfsyncstats.pfsyncs_badif++; 584130613Smlaier goto done; 585130613Smlaier } 586130613Smlaier 587223637Sbz sc->sc_ifp->if_ipackets++; 588223637Sbz sc->sc_ifp->if_ibytes += m->m_pkthdr.len; 589223637Sbz /* verify that the IP TTL is 255. */ 590130613Smlaier if (ip->ip_ttl != PFSYNC_DFLTTL) { 591223637Sbz V_pfsyncstats.pfsyncs_badttl++; 592130613Smlaier goto done; 593130613Smlaier } 594130613Smlaier 595223637Sbz offset = ip->ip_hl << 2; 596223637Sbz if (m->m_pkthdr.len < offset + sizeof(*ph)) { 597223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 598130613Smlaier goto done; 599130613Smlaier } 600130613Smlaier 601223637Sbz if (offset + sizeof(*ph) > m->m_len) { 602223637Sbz if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 603223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 604223637Sbz return; 605130613Smlaier } 606130613Smlaier ip = mtod(m, struct ip *); 607130613Smlaier } 608223637Sbz ph = (struct pfsync_header *)((char *)ip + offset); 609130613Smlaier 610130613Smlaier /* verify the version */ 611130613Smlaier if (ph->version != PFSYNC_VERSION) { 612223637Sbz V_pfsyncstats.pfsyncs_badver++; 613130613Smlaier goto done; 614130613Smlaier } 615130613Smlaier 616244185Sglebius len = ntohs(ph->len) + offset; 617244185Sglebius if (m->m_pkthdr.len < len) { 618244202Sglebius V_pfsyncstats.pfsyncs_badlen++; 619244185Sglebius goto done; 620244185Sglebius } 621244185Sglebius 622130613Smlaier /* Cheaper to grab this now than having to mess with mbufs later */ 623223637Sbz pkt.ip = ip; 624223637Sbz pkt.src = ip->ip_src; 625223637Sbz pkt.flags = 0; 626130613Smlaier 627240233Sglebius /* 628240233Sglebius * Trusting pf_chksum during packet processing, as well as seeking 629240233Sglebius * in interface name tree, require holding PF_RULES_RLOCK(). 630240233Sglebius */ 631240233Sglebius PF_RULES_RLOCK(); 632223637Sbz if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 633223637Sbz pkt.flags |= PFSYNC_SI_CKSUM; 634171168Smlaier 635223637Sbz offset += sizeof(*ph); 636244185Sglebius while (offset <= len - sizeof(subh)) { 637223637Sbz m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 638223637Sbz offset += sizeof(subh); 639223637Sbz 640223637Sbz if (subh.action >= PFSYNC_ACT_MAX) { 641223637Sbz V_pfsyncstats.pfsyncs_badact++; 642240233Sglebius PF_RULES_RUNLOCK(); 643223637Sbz goto done; 644130613Smlaier } 645130613Smlaier 646240233Sglebius count = ntohs(subh.count); 647240233Sglebius V_pfsyncstats.pfsyncs_iacts[subh.action] += count; 648240233Sglebius rv = (*pfsync_acts[subh.action])(&pkt, m, offset, count); 649240233Sglebius if (rv == -1) { 650240233Sglebius PF_RULES_RUNLOCK(); 651223637Sbz return; 652240233Sglebius } 653223637Sbz 654223637Sbz offset += rv; 655223637Sbz } 656240233Sglebius PF_RULES_RUNLOCK(); 657223637Sbz 658223637Sbzdone: 659223637Sbz m_freem(m); 660223637Sbz} 661223637Sbz 662240233Sglebiusstatic int 663223637Sbzpfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 664223637Sbz{ 665223637Sbz struct pfsync_clr *clr; 666223637Sbz struct mbuf *mp; 667223637Sbz int len = sizeof(*clr) * count; 668223637Sbz int i, offp; 669223637Sbz u_int32_t creatorid; 670223637Sbz 671223637Sbz mp = m_pulldown(m, offset, len, &offp); 672223637Sbz if (mp == NULL) { 673223637Sbz V_pfsyncstats.pfsyncs_badlen++; 674223637Sbz return (-1); 675223637Sbz } 676223637Sbz clr = (struct pfsync_clr *)(mp->m_data + offp); 677223637Sbz 678223637Sbz for (i = 0; i < count; i++) { 679223637Sbz creatorid = clr[i].creatorid; 680223637Sbz 681240233Sglebius if (clr[i].ifname[0] != '\0' && 682240233Sglebius pfi_kif_find(clr[i].ifname) == NULL) 683240233Sglebius continue; 684223637Sbz 685240233Sglebius for (int i = 0; i <= V_pf_hashmask; i++) { 686240233Sglebius struct pf_idhash *ih = &V_pf_idhash[i]; 687240233Sglebius struct pf_state *s; 688240233Sglebiusrelock: 689240233Sglebius PF_HASHROW_LOCK(ih); 690240233Sglebius LIST_FOREACH(s, &ih->states, entry) { 691240233Sglebius if (s->creatorid == creatorid) { 692240233Sglebius s->state_flags |= PFSTATE_NOSYNC; 693240233Sglebius pf_unlink_state(s, PF_ENTER_LOCKED); 694240233Sglebius goto relock; 695145836Smlaier } 696130613Smlaier } 697240233Sglebius PF_HASHROW_UNLOCK(ih); 698130613Smlaier } 699223637Sbz } 700130613Smlaier 701223637Sbz return (len); 702223637Sbz} 703223637Sbz 704240233Sglebiusstatic int 705223637Sbzpfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 706223637Sbz{ 707223637Sbz struct mbuf *mp; 708223637Sbz struct pfsync_state *sa, *sp; 709223637Sbz int len = sizeof(*sp) * count; 710223637Sbz int i, offp; 711223637Sbz 712223637Sbz mp = m_pulldown(m, offset, len, &offp); 713223637Sbz if (mp == NULL) { 714223637Sbz V_pfsyncstats.pfsyncs_badlen++; 715223637Sbz return (-1); 716130613Smlaier } 717223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 718130613Smlaier 719223637Sbz for (i = 0; i < count; i++) { 720223637Sbz sp = &sa[i]; 721130613Smlaier 722240233Sglebius /* Check for invalid values. */ 723223637Sbz if (sp->timeout >= PFTM_MAX || 724223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 725223637Sbz sp->dst.state > PF_TCPS_PROXY_DST || 726223637Sbz sp->direction > PF_OUT || 727223637Sbz (sp->af != AF_INET && sp->af != AF_INET6)) { 728240233Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 729240233Sglebius printf("%s: invalid value\n", __func__); 730223637Sbz V_pfsyncstats.pfsyncs_badval++; 731223637Sbz continue; 732130613Smlaier } 733223637Sbz 734240233Sglebius if (pfsync_state_import(sp, pkt->flags) == ENOMEM) 735240233Sglebius /* Drop out, but process the rest of the actions. */ 736223637Sbz break; 737223637Sbz } 738130613Smlaier 739223637Sbz return (len); 740223637Sbz} 741223637Sbz 742240233Sglebiusstatic int 743223637Sbzpfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 744223637Sbz{ 745223637Sbz struct pfsync_ins_ack *ia, *iaa; 746223637Sbz struct pf_state *st; 747223637Sbz 748223637Sbz struct mbuf *mp; 749223637Sbz int len = count * sizeof(*ia); 750223637Sbz int offp, i; 751223637Sbz 752223637Sbz mp = m_pulldown(m, offset, len, &offp); 753223637Sbz if (mp == NULL) { 754223637Sbz V_pfsyncstats.pfsyncs_badlen++; 755223637Sbz return (-1); 756223637Sbz } 757223637Sbz iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 758223637Sbz 759223637Sbz for (i = 0; i < count; i++) { 760223637Sbz ia = &iaa[i]; 761145836Smlaier 762240233Sglebius st = pf_find_state_byid(ia->id, ia->creatorid); 763223637Sbz if (st == NULL) 764223637Sbz continue; 765130613Smlaier 766240233Sglebius if (st->state_flags & PFSTATE_ACK) { 767240233Sglebius PFSYNC_LOCK(V_pfsyncif); 768240233Sglebius pfsync_undefer_state(st, 0); 769240233Sglebius PFSYNC_UNLOCK(V_pfsyncif); 770240233Sglebius } 771240233Sglebius PF_STATE_UNLOCK(st); 772223637Sbz } 773130613Smlaier /* 774223637Sbz * XXX this is not yet implemented, but we know the size of the 775223637Sbz * message so we can skip it. 776130613Smlaier */ 777130613Smlaier 778223637Sbz return (count * sizeof(struct pfsync_ins_ack)); 779223637Sbz} 780223637Sbz 781240233Sglebiusstatic int 782223637Sbzpfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, 783223637Sbz struct pfsync_state_peer *dst) 784223637Sbz{ 785242694Sglebius int sync = 0; 786223637Sbz 787240233Sglebius PF_STATE_LOCK_ASSERT(st); 788240233Sglebius 789223637Sbz /* 790223637Sbz * The state should never go backwards except 791223637Sbz * for syn-proxy states. Neither should the 792223637Sbz * sequence window slide backwards. 793223637Sbz */ 794242694Sglebius if ((st->src.state > src->state && 795223637Sbz (st->src.state < PF_TCPS_PROXY_SRC || 796242694Sglebius src->state >= PF_TCPS_PROXY_SRC)) || 797244113Sglebius 798244113Sglebius (st->src.state == src->state && 799244113Sglebius SEQ_GT(st->src.seqlo, ntohl(src->seqlo)))) 800242694Sglebius sync++; 801242694Sglebius else 802223637Sbz pf_state_peer_ntoh(src, &st->src); 803223637Sbz 804244113Sglebius if ((st->dst.state > dst->state) || 805244113Sglebius 806242694Sglebius (st->dst.state >= TCPS_SYN_SENT && 807242694Sglebius SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo)))) 808242694Sglebius sync++; 809242694Sglebius else 810242694Sglebius pf_state_peer_ntoh(dst, &st->dst); 811242694Sglebius 812242694Sglebius return (sync); 813223637Sbz} 814223637Sbz 815240233Sglebiusstatic int 816223637Sbzpfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 817223637Sbz{ 818240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 819223637Sbz struct pfsync_state *sa, *sp; 820223637Sbz struct pf_state *st; 821242694Sglebius int sync; 822223637Sbz 823223637Sbz struct mbuf *mp; 824223637Sbz int len = count * sizeof(*sp); 825223637Sbz int offp, i; 826223637Sbz 827223637Sbz mp = m_pulldown(m, offset, len, &offp); 828223637Sbz if (mp == NULL) { 829223637Sbz V_pfsyncstats.pfsyncs_badlen++; 830223637Sbz return (-1); 831223637Sbz } 832223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 833223637Sbz 834223637Sbz for (i = 0; i < count; i++) { 835223637Sbz sp = &sa[i]; 836130613Smlaier 837223637Sbz /* check for invalid values */ 838223637Sbz if (sp->timeout >= PFTM_MAX || 839223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 840223637Sbz sp->dst.state > PF_TCPS_PROXY_DST) { 841223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 842223637Sbz printf("pfsync_input: PFSYNC_ACT_UPD: " 843223637Sbz "invalid value\n"); 844130613Smlaier } 845223637Sbz V_pfsyncstats.pfsyncs_badval++; 846223637Sbz continue; 847130613Smlaier } 848223637Sbz 849240233Sglebius st = pf_find_state_byid(sp->id, sp->creatorid); 850223637Sbz if (st == NULL) { 851223637Sbz /* insert the update */ 852223637Sbz if (pfsync_state_import(sp, 0)) 853223637Sbz V_pfsyncstats.pfsyncs_badstate++; 854223637Sbz continue; 855223637Sbz } 856223637Sbz 857240233Sglebius if (st->state_flags & PFSTATE_ACK) { 858240233Sglebius PFSYNC_LOCK(sc); 859240233Sglebius pfsync_undefer_state(st, 1); 860240233Sglebius PFSYNC_UNLOCK(sc); 861240233Sglebius } 862223637Sbz 863242694Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) 864242694Sglebius sync = pfsync_upd_tcp(st, &sp->src, &sp->dst); 865223637Sbz else { 866242694Sglebius sync = 0; 867242694Sglebius 868223637Sbz /* 869223637Sbz * Non-TCP protocol state machine always go 870223637Sbz * forwards 871223637Sbz */ 872223637Sbz if (st->src.state > sp->src.state) 873242694Sglebius sync++; 874242694Sglebius else 875242694Sglebius pf_state_peer_ntoh(&sp->src, &st->src); 876242694Sglebius if (st->dst.state > sp->dst.state) 877242694Sglebius sync++; 878242694Sglebius else 879242694Sglebius pf_state_peer_ntoh(&sp->dst, &st->dst); 880223637Sbz } 881242694Sglebius if (sync < 2) { 882242694Sglebius pfsync_alloc_scrub_memory(&sp->dst, &st->dst); 883242694Sglebius pf_state_peer_ntoh(&sp->dst, &st->dst); 884242694Sglebius st->expire = time_uptime; 885242694Sglebius st->timeout = sp->timeout; 886242694Sglebius } 887242694Sglebius st->pfsync_time = time_uptime; 888223637Sbz 889242694Sglebius if (sync) { 890223637Sbz V_pfsyncstats.pfsyncs_stale++; 891130613Smlaier 892223637Sbz pfsync_update_state(st); 893240233Sglebius PF_STATE_UNLOCK(st); 894240233Sglebius PFSYNC_LOCK(sc); 895240233Sglebius pfsync_push(sc); 896240233Sglebius PFSYNC_UNLOCK(sc); 897223637Sbz continue; 898130613Smlaier } 899240233Sglebius PF_STATE_UNLOCK(st); 900223637Sbz } 901130613Smlaier 902223637Sbz return (len); 903223637Sbz} 904223637Sbz 905240233Sglebiusstatic int 906223637Sbzpfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 907223637Sbz{ 908240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 909223637Sbz struct pfsync_upd_c *ua, *up; 910223637Sbz struct pf_state *st; 911223637Sbz int len = count * sizeof(*up); 912242694Sglebius int sync; 913223637Sbz struct mbuf *mp; 914223637Sbz int offp, i; 915223637Sbz 916223637Sbz mp = m_pulldown(m, offset, len, &offp); 917223637Sbz if (mp == NULL) { 918223637Sbz V_pfsyncstats.pfsyncs_badlen++; 919223637Sbz return (-1); 920223637Sbz } 921223637Sbz ua = (struct pfsync_upd_c *)(mp->m_data + offp); 922223637Sbz 923223637Sbz for (i = 0; i < count; i++) { 924223637Sbz up = &ua[i]; 925223637Sbz 926223637Sbz /* check for invalid values */ 927223637Sbz if (up->timeout >= PFTM_MAX || 928223637Sbz up->src.state > PF_TCPS_PROXY_DST || 929223637Sbz up->dst.state > PF_TCPS_PROXY_DST) { 930223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 931223637Sbz printf("pfsync_input: " 932223637Sbz "PFSYNC_ACT_UPD_C: " 933223637Sbz "invalid value\n"); 934130613Smlaier } 935223637Sbz V_pfsyncstats.pfsyncs_badval++; 936223637Sbz continue; 937223637Sbz } 938130613Smlaier 939240233Sglebius st = pf_find_state_byid(up->id, up->creatorid); 940223637Sbz if (st == NULL) { 941223637Sbz /* We don't have this state. Ask for it. */ 942240233Sglebius PFSYNC_LOCK(sc); 943240233Sglebius pfsync_request_update(up->creatorid, up->id); 944240233Sglebius PFSYNC_UNLOCK(sc); 945223637Sbz continue; 946223637Sbz } 947223637Sbz 948240233Sglebius if (st->state_flags & PFSTATE_ACK) { 949240233Sglebius PFSYNC_LOCK(sc); 950240233Sglebius pfsync_undefer_state(st, 1); 951240233Sglebius PFSYNC_UNLOCK(sc); 952240233Sglebius } 953223637Sbz 954242694Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) 955242694Sglebius sync = pfsync_upd_tcp(st, &up->src, &up->dst); 956223637Sbz else { 957242694Sglebius sync = 0; 958242694Sglebius 959223637Sbz /* 960242694Sglebius * Non-TCP protocol state machine always go 961242694Sglebius * forwards 962223637Sbz */ 963223637Sbz if (st->src.state > up->src.state) 964242694Sglebius sync++; 965242694Sglebius else 966242694Sglebius pf_state_peer_ntoh(&up->src, &st->src); 967242694Sglebius if (st->dst.state > up->dst.state) 968242694Sglebius sync++; 969242694Sglebius else 970242694Sglebius pf_state_peer_ntoh(&up->dst, &st->dst); 971223637Sbz } 972242694Sglebius if (sync < 2) { 973242694Sglebius pfsync_alloc_scrub_memory(&up->dst, &st->dst); 974242694Sglebius pf_state_peer_ntoh(&up->dst, &st->dst); 975242694Sglebius st->expire = time_uptime; 976242694Sglebius st->timeout = up->timeout; 977242694Sglebius } 978242694Sglebius st->pfsync_time = time_uptime; 979223637Sbz 980242694Sglebius if (sync) { 981223637Sbz V_pfsyncstats.pfsyncs_stale++; 982145836Smlaier 983223637Sbz pfsync_update_state(st); 984240233Sglebius PF_STATE_UNLOCK(st); 985240233Sglebius PFSYNC_LOCK(sc); 986240233Sglebius pfsync_push(sc); 987240233Sglebius PFSYNC_UNLOCK(sc); 988223637Sbz continue; 989130613Smlaier } 990240233Sglebius PF_STATE_UNLOCK(st); 991223637Sbz } 992223637Sbz 993223637Sbz return (len); 994223637Sbz} 995223637Sbz 996240233Sglebiusstatic int 997223637Sbzpfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 998223637Sbz{ 999223637Sbz struct pfsync_upd_req *ur, *ura; 1000223637Sbz struct mbuf *mp; 1001223637Sbz int len = count * sizeof(*ur); 1002223637Sbz int i, offp; 1003223637Sbz 1004223637Sbz struct pf_state *st; 1005223637Sbz 1006223637Sbz mp = m_pulldown(m, offset, len, &offp); 1007223637Sbz if (mp == NULL) { 1008223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1009223637Sbz return (-1); 1010130613Smlaier } 1011223637Sbz ura = (struct pfsync_upd_req *)(mp->m_data + offp); 1012130613Smlaier 1013223637Sbz for (i = 0; i < count; i++) { 1014223637Sbz ur = &ura[i]; 1015130613Smlaier 1016240233Sglebius if (ur->id == 0 && ur->creatorid == 0) 1017223637Sbz pfsync_bulk_start(); 1018223637Sbz else { 1019240233Sglebius st = pf_find_state_byid(ur->id, ur->creatorid); 1020130613Smlaier if (st == NULL) { 1021223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1022130613Smlaier continue; 1023130613Smlaier } 1024240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1025240233Sglebius PF_STATE_UNLOCK(st); 1026223637Sbz continue; 1027240233Sglebius } 1028223637Sbz 1029223637Sbz pfsync_update_state_req(st); 1030240233Sglebius PF_STATE_UNLOCK(st); 1031130613Smlaier } 1032223637Sbz } 1033223637Sbz 1034223637Sbz return (len); 1035223637Sbz} 1036223637Sbz 1037240233Sglebiusstatic int 1038223637Sbzpfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1039223637Sbz{ 1040223637Sbz struct mbuf *mp; 1041223637Sbz struct pfsync_state *sa, *sp; 1042223637Sbz struct pf_state *st; 1043223637Sbz int len = count * sizeof(*sp); 1044223637Sbz int offp, i; 1045223637Sbz 1046223637Sbz mp = m_pulldown(m, offset, len, &offp); 1047223637Sbz if (mp == NULL) { 1048223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1049223637Sbz return (-1); 1050223637Sbz } 1051223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1052223637Sbz 1053223637Sbz for (i = 0; i < count; i++) { 1054223637Sbz sp = &sa[i]; 1055223637Sbz 1056240233Sglebius st = pf_find_state_byid(sp->id, sp->creatorid); 1057223637Sbz if (st == NULL) { 1058223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1059223637Sbz continue; 1060130613Smlaier } 1061240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1062240233Sglebius pf_unlink_state(st, PF_ENTER_LOCKED); 1063223637Sbz } 1064130613Smlaier 1065223637Sbz return (len); 1066223637Sbz} 1067223637Sbz 1068240233Sglebiusstatic int 1069223637Sbzpfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1070223637Sbz{ 1071223637Sbz struct mbuf *mp; 1072223637Sbz struct pfsync_del_c *sa, *sp; 1073223637Sbz struct pf_state *st; 1074223637Sbz int len = count * sizeof(*sp); 1075223637Sbz int offp, i; 1076223637Sbz 1077223637Sbz mp = m_pulldown(m, offset, len, &offp); 1078223637Sbz if (mp == NULL) { 1079223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1080223637Sbz return (-1); 1081223637Sbz } 1082223637Sbz sa = (struct pfsync_del_c *)(mp->m_data + offp); 1083223637Sbz 1084223637Sbz for (i = 0; i < count; i++) { 1085223637Sbz sp = &sa[i]; 1086130613Smlaier 1087240233Sglebius st = pf_find_state_byid(sp->id, sp->creatorid); 1088223637Sbz if (st == NULL) { 1089223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1090223637Sbz continue; 1091223637Sbz } 1092223637Sbz 1093240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1094240233Sglebius pf_unlink_state(st, PF_ENTER_LOCKED); 1095223637Sbz } 1096223637Sbz 1097223637Sbz return (len); 1098223637Sbz} 1099223637Sbz 1100240233Sglebiusstatic int 1101223637Sbzpfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1102223637Sbz{ 1103223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1104223637Sbz struct pfsync_bus *bus; 1105223637Sbz struct mbuf *mp; 1106223637Sbz int len = count * sizeof(*bus); 1107223637Sbz int offp; 1108223637Sbz 1109240233Sglebius PFSYNC_BLOCK(sc); 1110240233Sglebius 1111223637Sbz /* If we're not waiting for a bulk update, who cares. */ 1112240233Sglebius if (sc->sc_ureq_sent == 0) { 1113240233Sglebius PFSYNC_BUNLOCK(sc); 1114223637Sbz return (len); 1115240233Sglebius } 1116223637Sbz 1117223637Sbz mp = m_pulldown(m, offset, len, &offp); 1118223637Sbz if (mp == NULL) { 1119240233Sglebius PFSYNC_BUNLOCK(sc); 1120223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1121223637Sbz return (-1); 1122223637Sbz } 1123223637Sbz bus = (struct pfsync_bus *)(mp->m_data + offp); 1124223637Sbz 1125223637Sbz switch (bus->status) { 1126223637Sbz case PFSYNC_BUS_START: 1127228814Sglebius callout_reset(&sc->sc_bulkfail_tmo, 4 * hz + 1128240233Sglebius V_pf_limits[PF_LIMIT_STATES].limit / 1129229777Sglebius ((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) / 1130228814Sglebius sizeof(struct pfsync_state)), 1131240233Sglebius pfsync_bulk_fail, sc); 1132223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1133223637Sbz printf("pfsync: received bulk update start\n"); 1134130613Smlaier break; 1135130613Smlaier 1136223637Sbz case PFSYNC_BUS_END: 1137223637Sbz if (time_uptime - ntohl(bus->endtime) >= 1138223637Sbz sc->sc_ureq_sent) { 1139223637Sbz /* that's it, we're happy */ 1140223637Sbz sc->sc_ureq_sent = 0; 1141223637Sbz sc->sc_bulk_tries = 0; 1142240233Sglebius callout_stop(&sc->sc_bulkfail_tmo); 1143240233Sglebius if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 1144228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, 1145228736Sglebius "pfsync bulk done"); 1146240233Sglebius sc->sc_flags |= PFSYNCF_OK; 1147223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1148223637Sbz printf("pfsync: received valid " 1149223637Sbz "bulk update end\n"); 1150223637Sbz } else { 1151223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1152223637Sbz printf("pfsync: received invalid " 1153223637Sbz "bulk update end: bad timestamp\n"); 1154130613Smlaier } 1155130613Smlaier break; 1156223637Sbz } 1157240233Sglebius PFSYNC_BUNLOCK(sc); 1158223637Sbz 1159223637Sbz return (len); 1160223637Sbz} 1161223637Sbz 1162240233Sglebiusstatic int 1163223637Sbzpfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1164223637Sbz{ 1165223637Sbz int len = count * sizeof(struct pfsync_tdb); 1166223637Sbz 1167223637Sbz#if defined(IPSEC) 1168223637Sbz struct pfsync_tdb *tp; 1169223637Sbz struct mbuf *mp; 1170223637Sbz int offp; 1171223637Sbz int i; 1172223637Sbz int s; 1173223637Sbz 1174223637Sbz mp = m_pulldown(m, offset, len, &offp); 1175223637Sbz if (mp == NULL) { 1176223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1177223637Sbz return (-1); 1178223637Sbz } 1179223637Sbz tp = (struct pfsync_tdb *)(mp->m_data + offp); 1180223637Sbz 1181223637Sbz for (i = 0; i < count; i++) 1182223637Sbz pfsync_update_net_tdb(&tp[i]); 1183171168Smlaier#endif 1184223637Sbz 1185223637Sbz return (len); 1186223637Sbz} 1187223637Sbz 1188223637Sbz#if defined(IPSEC) 1189223637Sbz/* Update an in-kernel tdb. Silently fail if no tdb is found. */ 1190240233Sglebiusstatic void 1191223637Sbzpfsync_update_net_tdb(struct pfsync_tdb *pt) 1192223637Sbz{ 1193223637Sbz struct tdb *tdb; 1194223637Sbz int s; 1195223637Sbz 1196223637Sbz /* check for invalid values */ 1197223637Sbz if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 1198223637Sbz (pt->dst.sa.sa_family != AF_INET && 1199240233Sglebius pt->dst.sa.sa_family != AF_INET6)) 1200223637Sbz goto bad; 1201223637Sbz 1202223637Sbz tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 1203223637Sbz if (tdb) { 1204223637Sbz pt->rpl = ntohl(pt->rpl); 1205240233Sglebius pt->cur_bytes = (unsigned long long)be64toh(pt->cur_bytes); 1206223637Sbz 1207223637Sbz /* Neither replay nor byte counter should ever decrease. */ 1208223637Sbz if (pt->rpl < tdb->tdb_rpl || 1209223637Sbz pt->cur_bytes < tdb->tdb_cur_bytes) { 1210223637Sbz goto bad; 1211223637Sbz } 1212223637Sbz 1213223637Sbz tdb->tdb_rpl = pt->rpl; 1214223637Sbz tdb->tdb_cur_bytes = pt->cur_bytes; 1215130613Smlaier } 1216223637Sbz return; 1217130613Smlaier 1218223637Sbzbad: 1219223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1220223637Sbz printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 1221223637Sbz "invalid value\n"); 1222223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1223223637Sbz return; 1224130613Smlaier} 1225223637Sbz#endif 1226130613Smlaier 1227223637Sbz 1228240233Sglebiusstatic int 1229223637Sbzpfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1230223637Sbz{ 1231223637Sbz /* check if we are at the right place in the packet */ 1232244185Sglebius if (offset != m->m_pkthdr.len) 1233244185Sglebius V_pfsyncstats.pfsyncs_badlen++; 1234223637Sbz 1235223637Sbz /* we're done. free and let the caller return */ 1236223637Sbz m_freem(m); 1237223637Sbz return (-1); 1238223637Sbz} 1239223637Sbz 1240240233Sglebiusstatic int 1241223637Sbzpfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1242223637Sbz{ 1243223637Sbz V_pfsyncstats.pfsyncs_badact++; 1244223637Sbz 1245223637Sbz m_freem(m); 1246223637Sbz return (-1); 1247223637Sbz} 1248223637Sbz 1249240233Sglebiusstatic int 1250126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 1251223637Sbz struct route *rt) 1252126258Smlaier{ 1253126258Smlaier m_freem(m); 1254126258Smlaier return (0); 1255126258Smlaier} 1256126258Smlaier 1257126258Smlaier/* ARGSUSED */ 1258240233Sglebiusstatic int 1259126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1260126258Smlaier{ 1261126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1262126258Smlaier struct ifreq *ifr = (struct ifreq *)data; 1263130613Smlaier struct pfsyncreq pfsyncr; 1264240233Sglebius int error; 1265126258Smlaier 1266126258Smlaier switch (cmd) { 1267126258Smlaier case SIOCSIFFLAGS: 1268240233Sglebius PFSYNC_LOCK(sc); 1269241057Sglebius if (ifp->if_flags & IFF_UP) { 1270148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1271241057Sglebius PFSYNC_UNLOCK(sc); 1272241057Sglebius pfsync_pointers_init(); 1273241057Sglebius } else { 1274148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1275241057Sglebius PFSYNC_UNLOCK(sc); 1276241057Sglebius pfsync_pointers_uninit(); 1277241057Sglebius } 1278126258Smlaier break; 1279126258Smlaier case SIOCSIFMTU: 1280229777Sglebius if (!sc->sc_sync_if || 1281229777Sglebius ifr->ifr_mtu <= PFSYNC_MINPKT || 1282229777Sglebius ifr->ifr_mtu > sc->sc_sync_if->if_mtu) 1283126258Smlaier return (EINVAL); 1284223637Sbz if (ifr->ifr_mtu < ifp->if_mtu) { 1285240233Sglebius PFSYNC_LOCK(sc); 1286240233Sglebius if (sc->sc_len > PFSYNC_MINPKT) 1287240233Sglebius pfsync_sendout(1); 1288240233Sglebius PFSYNC_UNLOCK(sc); 1289223637Sbz } 1290223637Sbz ifp->if_mtu = ifr->ifr_mtu; 1291126258Smlaier break; 1292130613Smlaier case SIOCGETPFSYNC: 1293130613Smlaier bzero(&pfsyncr, sizeof(pfsyncr)); 1294240233Sglebius PFSYNC_LOCK(sc); 1295223637Sbz if (sc->sc_sync_if) { 1296145836Smlaier strlcpy(pfsyncr.pfsyncr_syncdev, 1297223637Sbz sc->sc_sync_if->if_xname, IFNAMSIZ); 1298223637Sbz } 1299145836Smlaier pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1300130613Smlaier pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1301240233Sglebius pfsyncr.pfsyncr_defer = (PFSYNCF_DEFER == 1302240233Sglebius (sc->sc_flags & PFSYNCF_DEFER)); 1303240233Sglebius PFSYNC_UNLOCK(sc); 1304223637Sbz return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); 1305223637Sbz 1306130613Smlaier case SIOCSETPFSYNC: 1307240233Sglebius { 1308240233Sglebius struct ip_moptions *imo = &sc->sc_imo; 1309240233Sglebius struct ifnet *sifp; 1310240233Sglebius struct ip *ip; 1311240233Sglebius void *mship = NULL; 1312240233Sglebius 1313164033Srwatson if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1314130613Smlaier return (error); 1315130613Smlaier if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1316130613Smlaier return (error); 1317130613Smlaier 1318240233Sglebius if (pfsyncr.pfsyncr_maxupdates > 255) 1319240233Sglebius return (EINVAL); 1320240233Sglebius 1321240233Sglebius if (pfsyncr.pfsyncr_syncdev[0] == 0) 1322240233Sglebius sifp = NULL; 1323240233Sglebius else if ((sifp = ifunit_ref(pfsyncr.pfsyncr_syncdev)) == NULL) 1324240233Sglebius return (EINVAL); 1325240233Sglebius 1326240233Sglebius if (pfsyncr.pfsyncr_syncpeer.s_addr == 0 && sifp != NULL) 1327240233Sglebius mship = malloc((sizeof(struct in_multi *) * 1328240233Sglebius IP_MIN_MEMBERSHIPS), M_PFSYNC, M_WAITOK | M_ZERO); 1329240233Sglebius 1330240233Sglebius PFSYNC_LOCK(sc); 1331145836Smlaier if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1332159603Smlaier sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1333145836Smlaier else 1334145836Smlaier sc->sc_sync_peer.s_addr = 1335145836Smlaier pfsyncr.pfsyncr_syncpeer.s_addr; 1336145836Smlaier 1337240233Sglebius sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1338240233Sglebius if (pfsyncr.pfsyncr_defer) { 1339240233Sglebius sc->sc_flags |= PFSYNCF_DEFER; 1340240233Sglebius pfsync_defer_ptr = pfsync_defer; 1341240233Sglebius } else { 1342240233Sglebius sc->sc_flags &= ~PFSYNCF_DEFER; 1343240233Sglebius pfsync_defer_ptr = NULL; 1344171168Smlaier } 1345130613Smlaier 1346240233Sglebius if (sifp == NULL) { 1347240233Sglebius if (sc->sc_sync_if) 1348240233Sglebius if_rele(sc->sc_sync_if); 1349223637Sbz sc->sc_sync_if = NULL; 1350229850Sglebius if (imo->imo_membership) 1351229850Sglebius pfsync_multicast_cleanup(sc); 1352240233Sglebius PFSYNC_UNLOCK(sc); 1353130613Smlaier break; 1354130613Smlaier } 1355145836Smlaier 1356240233Sglebius if (sc->sc_len > PFSYNC_MINPKT && 1357240233Sglebius (sifp->if_mtu < sc->sc_ifp->if_mtu || 1358223637Sbz (sc->sc_sync_if != NULL && 1359223637Sbz sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1360240233Sglebius sifp->if_mtu < MCLBYTES - sizeof(struct ip))) 1361240233Sglebius pfsync_sendout(1); 1362130613Smlaier 1363240233Sglebius if (imo->imo_membership) 1364229850Sglebius pfsync_multicast_cleanup(sc); 1365130613Smlaier 1366240233Sglebius if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1367240233Sglebius error = pfsync_multicast_setup(sc, sifp, mship); 1368240233Sglebius if (error) { 1369240233Sglebius if_rele(sifp); 1370240233Sglebius free(mship, M_PFSYNC); 1371229850Sglebius return (error); 1372145836Smlaier } 1373145836Smlaier } 1374240233Sglebius if (sc->sc_sync_if) 1375240233Sglebius if_rele(sc->sc_sync_if); 1376240233Sglebius sc->sc_sync_if = sifp; 1377130613Smlaier 1378223637Sbz ip = &sc->sc_template; 1379223637Sbz bzero(ip, sizeof(*ip)); 1380223637Sbz ip->ip_v = IPVERSION; 1381223637Sbz ip->ip_hl = sizeof(sc->sc_template) >> 2; 1382223637Sbz ip->ip_tos = IPTOS_LOWDELAY; 1383240233Sglebius /* len and id are set later. */ 1384241913Sglebius ip->ip_off = htons(IP_DF); 1385223637Sbz ip->ip_ttl = PFSYNC_DFLTTL; 1386223637Sbz ip->ip_p = IPPROTO_PFSYNC; 1387223637Sbz ip->ip_src.s_addr = INADDR_ANY; 1388223637Sbz ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; 1389223637Sbz 1390240233Sglebius /* Request a full state table update. */ 1391240233Sglebius if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 1392240233Sglebius (*carp_demote_adj_p)(V_pfsync_carp_adj, 1393240233Sglebius "pfsync bulk start"); 1394240233Sglebius sc->sc_flags &= ~PFSYNCF_OK; 1395240233Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 1396240233Sglebius printf("pfsync: requesting bulk update\n"); 1397240233Sglebius pfsync_request_update(0, 0); 1398240233Sglebius PFSYNC_UNLOCK(sc); 1399240233Sglebius PFSYNC_BLOCK(sc); 1400240233Sglebius sc->sc_ureq_sent = time_uptime; 1401240233Sglebius callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, 1402240233Sglebius sc); 1403240233Sglebius PFSYNC_BUNLOCK(sc); 1404130613Smlaier 1405130613Smlaier break; 1406240233Sglebius } 1407126258Smlaier default: 1408126258Smlaier return (ENOTTY); 1409126258Smlaier } 1410126258Smlaier 1411126258Smlaier return (0); 1412126258Smlaier} 1413126258Smlaier 1414241056Sglebiusstatic void 1415241056Sglebiuspfsync_out_state(struct pf_state *st, void *buf) 1416130613Smlaier{ 1417241056Sglebius struct pfsync_state *sp = buf; 1418130613Smlaier 1419223637Sbz pfsync_state_export(sp, st); 1420223637Sbz} 1421223637Sbz 1422241056Sglebiusstatic void 1423241056Sglebiuspfsync_out_iack(struct pf_state *st, void *buf) 1424223637Sbz{ 1425241056Sglebius struct pfsync_ins_ack *iack = buf; 1426223637Sbz 1427223637Sbz iack->id = st->id; 1428223637Sbz iack->creatorid = st->creatorid; 1429223637Sbz} 1430223637Sbz 1431241056Sglebiusstatic void 1432241056Sglebiuspfsync_out_upd_c(struct pf_state *st, void *buf) 1433223637Sbz{ 1434241056Sglebius struct pfsync_upd_c *up = buf; 1435223637Sbz 1436232685Sglebius bzero(up, sizeof(*up)); 1437223637Sbz up->id = st->id; 1438223637Sbz pf_state_peer_hton(&st->src, &up->src); 1439223637Sbz pf_state_peer_hton(&st->dst, &up->dst); 1440223637Sbz up->creatorid = st->creatorid; 1441223637Sbz up->timeout = st->timeout; 1442223637Sbz} 1443223637Sbz 1444241056Sglebiusstatic void 1445241056Sglebiuspfsync_out_del(struct pf_state *st, void *buf) 1446223637Sbz{ 1447241056Sglebius struct pfsync_del_c *dp = buf; 1448223637Sbz 1449223637Sbz dp->id = st->id; 1450223637Sbz dp->creatorid = st->creatorid; 1451240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1452223637Sbz} 1453223637Sbz 1454240233Sglebiusstatic void 1455223637Sbzpfsync_drop(struct pfsync_softc *sc) 1456223637Sbz{ 1457240233Sglebius struct pf_state *st, *next; 1458223637Sbz struct pfsync_upd_req_item *ur; 1459223637Sbz int q; 1460223637Sbz 1461223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 1462223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 1463223637Sbz continue; 1464223637Sbz 1465240233Sglebius TAILQ_FOREACH_SAFE(st, &sc->sc_qs[q], sync_list, next) { 1466223637Sbz KASSERT(st->sync_state == q, 1467229964Sglebius ("%s: st->sync_state == q", 1468240233Sglebius __func__)); 1469223637Sbz st->sync_state = PFSYNC_S_NONE; 1470240233Sglebius pf_release_state(st); 1471223637Sbz } 1472223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 1473223637Sbz } 1474223637Sbz 1475223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 1476223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 1477240233Sglebius free(ur, M_PFSYNC); 1478223637Sbz } 1479223637Sbz 1480223637Sbz sc->sc_plus = NULL; 1481223637Sbz sc->sc_len = PFSYNC_MINPKT; 1482126258Smlaier} 1483126258Smlaier 1484229976Sglebiusstatic void 1485240233Sglebiuspfsync_sendout(int schedswi) 1486229976Sglebius{ 1487229976Sglebius struct pfsync_softc *sc = V_pfsyncif; 1488223637Sbz struct ifnet *ifp = sc->sc_ifp; 1489126258Smlaier struct mbuf *m; 1490223637Sbz struct ip *ip; 1491223637Sbz struct pfsync_header *ph; 1492223637Sbz struct pfsync_subheader *subh; 1493241056Sglebius struct pf_state *st; 1494223637Sbz struct pfsync_upd_req_item *ur; 1495223637Sbz int offset; 1496223637Sbz int q, count = 0; 1497126258Smlaier 1498240233Sglebius KASSERT(sc != NULL, ("%s: null sc", __func__)); 1499240233Sglebius KASSERT(sc->sc_len > PFSYNC_MINPKT, 1500240233Sglebius ("%s: sc_len %zu", __func__, sc->sc_len)); 1501240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1502223637Sbz 1503223637Sbz if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { 1504223637Sbz pfsync_drop(sc); 1505223637Sbz return; 1506223637Sbz } 1507223637Sbz 1508230265Sglebius m = m_get2(M_NOWAIT, MT_DATA, M_PKTHDR, max_linkhdr + sc->sc_len); 1509126258Smlaier if (m == NULL) { 1510171168Smlaier sc->sc_ifp->if_oerrors++; 1511230265Sglebius V_pfsyncstats.pfsyncs_onomem++; 1512230265Sglebius return; 1513230265Sglebius } 1514223637Sbz m->m_data += max_linkhdr; 1515223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 1516130613Smlaier 1517223637Sbz /* build the ip header */ 1518223637Sbz ip = (struct ip *)m->m_data; 1519223637Sbz bcopy(&sc->sc_template, ip, sizeof(*ip)); 1520223637Sbz offset = sizeof(*ip); 1521126258Smlaier 1522241913Sglebius ip->ip_len = htons(m->m_pkthdr.len); 1523223637Sbz ip->ip_id = htons(ip_randomid()); 1524126258Smlaier 1525223637Sbz /* build the pfsync header */ 1526223637Sbz ph = (struct pfsync_header *)(m->m_data + offset); 1527223637Sbz bzero(ph, sizeof(*ph)); 1528223637Sbz offset += sizeof(*ph); 1529126258Smlaier 1530223637Sbz ph->version = PFSYNC_VERSION; 1531223637Sbz ph->len = htons(sc->sc_len - sizeof(*ip)); 1532223637Sbz bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 1533171168Smlaier 1534223637Sbz /* walk the queues */ 1535223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 1536223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 1537223637Sbz continue; 1538223637Sbz 1539223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 1540223637Sbz offset += sizeof(*subh); 1541223637Sbz 1542223637Sbz count = 0; 1543241056Sglebius TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 1544223637Sbz KASSERT(st->sync_state == q, 1545223637Sbz ("%s: st->sync_state == q", 1546240233Sglebius __func__)); 1547240233Sglebius /* 1548240233Sglebius * XXXGL: some of write methods do unlocked reads 1549240233Sglebius * of state data :( 1550240233Sglebius */ 1551241056Sglebius pfsync_qs[q].write(st, m->m_data + offset); 1552241056Sglebius offset += pfsync_qs[q].len; 1553223637Sbz st->sync_state = PFSYNC_S_NONE; 1554240233Sglebius pf_release_state(st); 1555223637Sbz count++; 1556126258Smlaier } 1557223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 1558130613Smlaier 1559223637Sbz bzero(subh, sizeof(*subh)); 1560223637Sbz subh->action = pfsync_qs[q].action; 1561223637Sbz subh->count = htons(count); 1562240233Sglebius V_pfsyncstats.pfsyncs_oacts[pfsync_qs[q].action] += count; 1563126258Smlaier } 1564126258Smlaier 1565223637Sbz if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { 1566223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 1567223637Sbz offset += sizeof(*subh); 1568126258Smlaier 1569223637Sbz count = 0; 1570223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 1571223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 1572130613Smlaier 1573223637Sbz bcopy(&ur->ur_msg, m->m_data + offset, 1574223637Sbz sizeof(ur->ur_msg)); 1575223637Sbz offset += sizeof(ur->ur_msg); 1576240233Sglebius free(ur, M_PFSYNC); 1577223637Sbz count++; 1578223637Sbz } 1579130613Smlaier 1580223637Sbz bzero(subh, sizeof(*subh)); 1581223637Sbz subh->action = PFSYNC_ACT_UPD_REQ; 1582223637Sbz subh->count = htons(count); 1583240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_UPD_REQ] += count; 1584223637Sbz } 1585130613Smlaier 1586223637Sbz /* has someone built a custom region for us to add? */ 1587223637Sbz if (sc->sc_plus != NULL) { 1588223637Sbz bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); 1589223637Sbz offset += sc->sc_pluslen; 1590130613Smlaier 1591223637Sbz sc->sc_plus = NULL; 1592130613Smlaier } 1593130613Smlaier 1594223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 1595223637Sbz offset += sizeof(*subh); 1596130613Smlaier 1597223637Sbz bzero(subh, sizeof(*subh)); 1598223637Sbz subh->action = PFSYNC_ACT_EOF; 1599223637Sbz subh->count = htons(1); 1600240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_EOF]++; 1601130613Smlaier 1602223637Sbz /* we're done, let's put it on the wire */ 1603223637Sbz if (ifp->if_bpf) { 1604223637Sbz m->m_data += sizeof(*ip); 1605223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); 1606223637Sbz BPF_MTAP(ifp, m); 1607223637Sbz m->m_data -= sizeof(*ip); 1608223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 1609130613Smlaier } 1610130613Smlaier 1611223637Sbz if (sc->sc_sync_if == NULL) { 1612223637Sbz sc->sc_len = PFSYNC_MINPKT; 1613223637Sbz m_freem(m); 1614223637Sbz return; 1615223637Sbz } 1616126258Smlaier 1617223637Sbz sc->sc_ifp->if_opackets++; 1618223637Sbz sc->sc_ifp->if_obytes += m->m_pkthdr.len; 1619226660Sglebius sc->sc_len = PFSYNC_MINPKT; 1620226660Sglebius 1621229976Sglebius if (!_IF_QFULL(&sc->sc_ifp->if_snd)) 1622229976Sglebius _IF_ENQUEUE(&sc->sc_ifp->if_snd, m); 1623229976Sglebius else { 1624229976Sglebius m_freem(m); 1625240233Sglebius sc->sc_ifp->if_snd.ifq_drops++; 1626229976Sglebius } 1627229976Sglebius if (schedswi) 1628229976Sglebius swi_sched(V_pfsync_swi_cookie, 0); 1629126258Smlaier} 1630126258Smlaier 1631240233Sglebiusstatic void 1632223637Sbzpfsync_insert_state(struct pf_state *st) 1633126258Smlaier{ 1634223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1635130613Smlaier 1636240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) 1637240233Sglebius return; 1638130613Smlaier 1639240233Sglebius if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) || 1640223637Sbz st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 1641240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1642223637Sbz return; 1643130613Smlaier } 1644130613Smlaier 1645223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 1646240233Sglebius ("%s: st->sync_state == PFSYNC_S_NONE", __func__)); 1647223637Sbz 1648240233Sglebius PFSYNC_LOCK(sc); 1649223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 1650240233Sglebius callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif); 1651223637Sbz 1652223637Sbz pfsync_q_ins(st, PFSYNC_S_INS); 1653240233Sglebius PFSYNC_UNLOCK(sc); 1654223637Sbz 1655233846Sglebius st->sync_updates = 0; 1656130613Smlaier} 1657130613Smlaier 1658240233Sglebiusstatic int 1659223637Sbzpfsync_defer(struct pf_state *st, struct mbuf *m) 1660130613Smlaier{ 1661223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1662223637Sbz struct pfsync_deferral *pd; 1663126258Smlaier 1664240233Sglebius if (m->m_flags & (M_BCAST|M_MCAST)) 1665240233Sglebius return (0); 1666223637Sbz 1667240233Sglebius PFSYNC_LOCK(sc); 1668240233Sglebius 1669240233Sglebius if (sc == NULL || !(sc->sc_ifp->if_flags & IFF_DRV_RUNNING) || 1670240233Sglebius !(sc->sc_flags & PFSYNCF_DEFER)) { 1671240233Sglebius PFSYNC_UNLOCK(sc); 1672233846Sglebius return (0); 1673240233Sglebius } 1674233846Sglebius 1675240233Sglebius if (sc->sc_deferred >= 128) 1676223637Sbz pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 1677223637Sbz 1678240233Sglebius pd = malloc(sizeof(*pd), M_PFSYNC, M_NOWAIT); 1679223637Sbz if (pd == NULL) 1680171168Smlaier return (0); 1681223637Sbz sc->sc_deferred++; 1682171168Smlaier 1683223637Sbz m->m_flags |= M_SKIP_FIREWALL; 1684240233Sglebius st->state_flags |= PFSTATE_ACK; 1685223637Sbz 1686240233Sglebius pd->pd_sc = sc; 1687240233Sglebius pd->pd_refs = 0; 1688223637Sbz pd->pd_st = st; 1689240233Sglebius pf_ref_state(st); 1690223637Sbz pd->pd_m = m; 1691223637Sbz 1692223637Sbz TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); 1693240233Sglebius callout_init_mtx(&pd->pd_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED); 1694240233Sglebius callout_reset(&pd->pd_tmo, 10, pfsync_defer_tmo, pd); 1695126258Smlaier 1696240233Sglebius pfsync_push(sc); 1697233846Sglebius 1698223637Sbz return (1); 1699126258Smlaier} 1700126258Smlaier 1701240233Sglebiusstatic void 1702223637Sbzpfsync_undefer(struct pfsync_deferral *pd, int drop) 1703126258Smlaier{ 1704240233Sglebius struct pfsync_softc *sc = pd->pd_sc; 1705240233Sglebius struct mbuf *m = pd->pd_m; 1706240233Sglebius struct pf_state *st = pd->pd_st; 1707126258Smlaier 1708240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1709223637Sbz 1710223637Sbz TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 1711223637Sbz sc->sc_deferred--; 1712240233Sglebius pd->pd_st->state_flags &= ~PFSTATE_ACK; /* XXX: locking! */ 1713240233Sglebius free(pd, M_PFSYNC); 1714240233Sglebius pf_release_state(st); 1715223637Sbz 1716223637Sbz if (drop) 1717240233Sglebius m_freem(m); 1718223637Sbz else { 1719240233Sglebius _IF_ENQUEUE(&sc->sc_ifp->if_snd, m); 1720240233Sglebius pfsync_push(sc); 1721223637Sbz } 1722126258Smlaier} 1723126258Smlaier 1724240233Sglebiusstatic void 1725223637Sbzpfsync_defer_tmo(void *arg) 1726171168Smlaier{ 1727223637Sbz struct pfsync_deferral *pd = arg; 1728240233Sglebius struct pfsync_softc *sc = pd->pd_sc; 1729240233Sglebius struct mbuf *m = pd->pd_m; 1730240233Sglebius struct pf_state *st = pd->pd_st; 1731171168Smlaier 1732240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1733240233Sglebius 1734240233Sglebius CURVNET_SET(m->m_pkthdr.rcvif->if_vnet); 1735240233Sglebius 1736240233Sglebius TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 1737240233Sglebius sc->sc_deferred--; 1738240233Sglebius pd->pd_st->state_flags &= ~PFSTATE_ACK; /* XXX: locking! */ 1739240233Sglebius if (pd->pd_refs == 0) 1740240233Sglebius free(pd, M_PFSYNC); 1741240233Sglebius PFSYNC_UNLOCK(sc); 1742240233Sglebius 1743240233Sglebius ip_output(m, NULL, NULL, 0, NULL, NULL); 1744240233Sglebius 1745240233Sglebius pf_release_state(st); 1746240233Sglebius 1747223637Sbz CURVNET_RESTORE(); 1748171168Smlaier} 1749223637Sbz 1750240233Sglebiusstatic void 1751240233Sglebiuspfsync_undefer_state(struct pf_state *st, int drop) 1752223637Sbz{ 1753223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1754223637Sbz struct pfsync_deferral *pd; 1755171168Smlaier 1756240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1757240233Sglebius 1758223637Sbz TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { 1759223637Sbz if (pd->pd_st == st) { 1760240233Sglebius if (callout_stop(&pd->pd_tmo)) 1761240233Sglebius pfsync_undefer(pd, drop); 1762223637Sbz return; 1763223637Sbz } 1764223637Sbz } 1765223637Sbz 1766240233Sglebius panic("%s: unable to find deferred state", __func__); 1767223637Sbz} 1768223637Sbz 1769240233Sglebiusstatic void 1770223637Sbzpfsync_update_state(struct pf_state *st) 1771130613Smlaier{ 1772223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1773223637Sbz int sync = 0; 1774130613Smlaier 1775240233Sglebius PF_STATE_LOCK_ASSERT(st); 1776240233Sglebius PFSYNC_LOCK(sc); 1777130613Smlaier 1778240233Sglebius if (st->state_flags & PFSTATE_ACK) 1779240233Sglebius pfsync_undefer_state(st, 0); 1780240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1781223637Sbz if (st->sync_state != PFSYNC_S_NONE) 1782223637Sbz pfsync_q_del(st); 1783240233Sglebius PFSYNC_UNLOCK(sc); 1784223637Sbz return; 1785130613Smlaier } 1786223637Sbz 1787223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 1788240233Sglebius callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif); 1789223637Sbz 1790223637Sbz switch (st->sync_state) { 1791223637Sbz case PFSYNC_S_UPD_C: 1792223637Sbz case PFSYNC_S_UPD: 1793223637Sbz case PFSYNC_S_INS: 1794223637Sbz /* we're already handling it */ 1795223637Sbz 1796228816Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) { 1797228816Sglebius st->sync_updates++; 1798228816Sglebius if (st->sync_updates >= sc->sc_maxupdates) 1799228816Sglebius sync = 1; 1800228816Sglebius } 1801223637Sbz break; 1802223637Sbz 1803223637Sbz case PFSYNC_S_IACK: 1804223637Sbz pfsync_q_del(st); 1805223637Sbz case PFSYNC_S_NONE: 1806223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD_C); 1807223637Sbz st->sync_updates = 0; 1808223637Sbz break; 1809223637Sbz 1810223637Sbz default: 1811240233Sglebius panic("%s: unexpected sync state %d", __func__, st->sync_state); 1812223637Sbz } 1813223637Sbz 1814240233Sglebius if (sync || (time_uptime - st->pfsync_time) < 2) 1815240233Sglebius pfsync_push(sc); 1816240233Sglebius 1817240233Sglebius PFSYNC_UNLOCK(sc); 1818130613Smlaier} 1819130613Smlaier 1820240233Sglebiusstatic void 1821223637Sbzpfsync_request_update(u_int32_t creatorid, u_int64_t id) 1822130613Smlaier{ 1823223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1824223637Sbz struct pfsync_upd_req_item *item; 1825223637Sbz size_t nlen = sizeof(struct pfsync_upd_req); 1826130613Smlaier 1827240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1828226544Sbz 1829130613Smlaier /* 1830241131Sglebius * This code does a bit to prevent multiple update requests for the 1831241131Sglebius * same state being generated. It searches current subheader queue, 1832241131Sglebius * but it doesn't lookup into queue of already packed datagrams. 1833130613Smlaier */ 1834241131Sglebius TAILQ_FOREACH(item, &sc->sc_upd_req_list, ur_entry) 1835241131Sglebius if (item->ur_msg.id == id && 1836241131Sglebius item->ur_msg.creatorid == creatorid) 1837241131Sglebius return; 1838241131Sglebius 1839240233Sglebius item = malloc(sizeof(*item), M_PFSYNC, M_NOWAIT); 1840240233Sglebius if (item == NULL) 1841240233Sglebius return; /* XXX stats */ 1842130613Smlaier 1843223637Sbz item->ur_msg.id = id; 1844223637Sbz item->ur_msg.creatorid = creatorid; 1845171168Smlaier 1846223637Sbz if (TAILQ_EMPTY(&sc->sc_upd_req_list)) 1847223637Sbz nlen += sizeof(struct pfsync_subheader); 1848223637Sbz 1849229777Sglebius if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 1850240233Sglebius pfsync_sendout(1); 1851223637Sbz 1852223637Sbz nlen = sizeof(struct pfsync_subheader) + 1853223637Sbz sizeof(struct pfsync_upd_req); 1854130613Smlaier } 1855223637Sbz 1856223637Sbz TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); 1857223637Sbz sc->sc_len += nlen; 1858223637Sbz} 1859223637Sbz 1860240233Sglebiusstatic void 1861223637Sbzpfsync_update_state_req(struct pf_state *st) 1862223637Sbz{ 1863223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1864223637Sbz 1865240233Sglebius PF_STATE_LOCK_ASSERT(st); 1866240233Sglebius PFSYNC_LOCK(sc); 1867226544Sbz 1868240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1869223637Sbz if (st->sync_state != PFSYNC_S_NONE) 1870223637Sbz pfsync_q_del(st); 1871240233Sglebius PFSYNC_UNLOCK(sc); 1872223637Sbz return; 1873223637Sbz } 1874223637Sbz 1875223637Sbz switch (st->sync_state) { 1876223637Sbz case PFSYNC_S_UPD_C: 1877223637Sbz case PFSYNC_S_IACK: 1878223637Sbz pfsync_q_del(st); 1879223637Sbz case PFSYNC_S_NONE: 1880223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD); 1881240233Sglebius pfsync_push(sc); 1882240233Sglebius break; 1883223637Sbz 1884223637Sbz case PFSYNC_S_INS: 1885223637Sbz case PFSYNC_S_UPD: 1886223637Sbz case PFSYNC_S_DEL: 1887223637Sbz /* we're already handling it */ 1888240233Sglebius break; 1889223637Sbz 1890223637Sbz default: 1891240233Sglebius panic("%s: unexpected sync state %d", __func__, st->sync_state); 1892223637Sbz } 1893240233Sglebius 1894240233Sglebius PFSYNC_UNLOCK(sc); 1895130613Smlaier} 1896130613Smlaier 1897240233Sglebiusstatic void 1898223637Sbzpfsync_delete_state(struct pf_state *st) 1899130613Smlaier{ 1900223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1901223637Sbz 1902240233Sglebius PFSYNC_LOCK(sc); 1903240233Sglebius if (st->state_flags & PFSTATE_ACK) 1904240233Sglebius pfsync_undefer_state(st, 1); 1905240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1906223637Sbz if (st->sync_state != PFSYNC_S_NONE) 1907223637Sbz pfsync_q_del(st); 1908240233Sglebius PFSYNC_UNLOCK(sc); 1909223637Sbz return; 1910223637Sbz } 1911223637Sbz 1912223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 1913240233Sglebius callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif); 1914223637Sbz 1915223637Sbz switch (st->sync_state) { 1916223637Sbz case PFSYNC_S_INS: 1917240233Sglebius /* We never got to tell the world so just forget about it. */ 1918223637Sbz pfsync_q_del(st); 1919240233Sglebius break; 1920223637Sbz 1921223637Sbz case PFSYNC_S_UPD_C: 1922223637Sbz case PFSYNC_S_UPD: 1923223637Sbz case PFSYNC_S_IACK: 1924223637Sbz pfsync_q_del(st); 1925223637Sbz /* FALLTHROUGH to putting it on the del list */ 1926223637Sbz 1927223637Sbz case PFSYNC_S_NONE: 1928223637Sbz pfsync_q_ins(st, PFSYNC_S_DEL); 1929240233Sglebius break; 1930223637Sbz 1931223637Sbz default: 1932240233Sglebius panic("%s: unexpected sync state %d", __func__, st->sync_state); 1933130613Smlaier } 1934240233Sglebius PFSYNC_UNLOCK(sc); 1935223637Sbz} 1936223637Sbz 1937240233Sglebiusstatic void 1938223637Sbzpfsync_clear_states(u_int32_t creatorid, const char *ifname) 1939223637Sbz{ 1940240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 1941223637Sbz struct { 1942223637Sbz struct pfsync_subheader subh; 1943223637Sbz struct pfsync_clr clr; 1944223637Sbz } __packed r; 1945223637Sbz 1946223637Sbz bzero(&r, sizeof(r)); 1947223637Sbz 1948223637Sbz r.subh.action = PFSYNC_ACT_CLR; 1949223637Sbz r.subh.count = htons(1); 1950240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_CLR]++; 1951223637Sbz 1952223637Sbz strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 1953223637Sbz r.clr.creatorid = creatorid; 1954223637Sbz 1955240233Sglebius PFSYNC_LOCK(sc); 1956223637Sbz pfsync_send_plus(&r, sizeof(r)); 1957240233Sglebius PFSYNC_UNLOCK(sc); 1958130613Smlaier} 1959130613Smlaier 1960240233Sglebiusstatic void 1961223637Sbzpfsync_q_ins(struct pf_state *st, int q) 1962126258Smlaier{ 1963223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1964223637Sbz size_t nlen = pfsync_qs[q].len; 1965223637Sbz 1966240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1967226544Sbz 1968223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 1969240233Sglebius ("%s: st->sync_state == PFSYNC_S_NONE", __func__)); 1970240233Sglebius KASSERT(sc->sc_len >= PFSYNC_MINPKT, ("pfsync pkt len is too low %zu", 1971240233Sglebius sc->sc_len)); 1972126258Smlaier 1973223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 1974223637Sbz nlen += sizeof(struct pfsync_subheader); 1975130613Smlaier 1976223637Sbz if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 1977240233Sglebius pfsync_sendout(1); 1978126258Smlaier 1979223637Sbz nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 1980130613Smlaier } 1981126258Smlaier 1982223637Sbz sc->sc_len += nlen; 1983223637Sbz TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); 1984223637Sbz st->sync_state = q; 1985240233Sglebius pf_ref_state(st); 1986171168Smlaier} 1987171168Smlaier 1988240233Sglebiusstatic void 1989223637Sbzpfsync_q_del(struct pf_state *st) 1990171168Smlaier{ 1991223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1992223637Sbz int q = st->sync_state; 1993171168Smlaier 1994240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1995229964Sglebius KASSERT(st->sync_state != PFSYNC_S_NONE, 1996240233Sglebius ("%s: st->sync_state != PFSYNC_S_NONE", __func__)); 1997171168Smlaier 1998223637Sbz sc->sc_len -= pfsync_qs[q].len; 1999223637Sbz TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); 2000223637Sbz st->sync_state = PFSYNC_S_NONE; 2001240233Sglebius pf_release_state(st); 2002171168Smlaier 2003223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2004223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2005223637Sbz} 2006223637Sbz 2007240233Sglebiusstatic void 2008223637Sbzpfsync_bulk_start(void) 2009223637Sbz{ 2010223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2011223637Sbz 2012226663Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 2013226663Sglebius printf("pfsync: received bulk update request\n"); 2014223637Sbz 2015240233Sglebius PFSYNC_BLOCK(sc); 2016223637Sbz 2017240233Sglebius sc->sc_ureq_received = time_uptime; 2018240233Sglebius sc->sc_bulk_hashid = 0; 2019240233Sglebius sc->sc_bulk_stateid = 0; 2020240233Sglebius pfsync_bulk_status(PFSYNC_BUS_START); 2021240233Sglebius callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, sc); 2022240233Sglebius PFSYNC_BUNLOCK(sc); 2023223637Sbz} 2024223637Sbz 2025240233Sglebiusstatic void 2026223637Sbzpfsync_bulk_update(void *arg) 2027223637Sbz{ 2028223637Sbz struct pfsync_softc *sc = arg; 2029240233Sglebius struct pf_state *s; 2030240233Sglebius int i, sent = 0; 2031223637Sbz 2032240233Sglebius PFSYNC_BLOCK_ASSERT(sc); 2033223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 2034223637Sbz 2035240233Sglebius /* 2036240233Sglebius * Start with last state from previous invocation. 2037240233Sglebius * It may had gone, in this case start from the 2038240233Sglebius * hash slot. 2039240233Sglebius */ 2040240233Sglebius s = pf_find_state_byid(sc->sc_bulk_stateid, sc->sc_bulk_creatorid); 2041223637Sbz 2042240233Sglebius if (s != NULL) 2043240233Sglebius i = PF_IDHASH(s); 2044240233Sglebius else 2045240233Sglebius i = sc->sc_bulk_hashid; 2046240233Sglebius 2047240233Sglebius for (; i <= V_pf_hashmask; i++) { 2048240233Sglebius struct pf_idhash *ih = &V_pf_idhash[i]; 2049240233Sglebius 2050240233Sglebius if (s != NULL) 2051240233Sglebius PF_HASHROW_ASSERT(ih); 2052240233Sglebius else { 2053240233Sglebius PF_HASHROW_LOCK(ih); 2054240233Sglebius s = LIST_FIRST(&ih->states); 2055226663Sglebius } 2056226663Sglebius 2057240233Sglebius for (; s; s = LIST_NEXT(s, entry)) { 2058240233Sglebius 2059240233Sglebius if (sent > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) < 2060240233Sglebius sizeof(struct pfsync_state)) { 2061240233Sglebius /* We've filled a packet. */ 2062240233Sglebius sc->sc_bulk_hashid = i; 2063240233Sglebius sc->sc_bulk_stateid = s->id; 2064240233Sglebius sc->sc_bulk_creatorid = s->creatorid; 2065240233Sglebius PF_HASHROW_UNLOCK(ih); 2066240233Sglebius callout_reset(&sc->sc_bulk_tmo, 1, 2067240233Sglebius pfsync_bulk_update, sc); 2068240233Sglebius goto full; 2069240233Sglebius } 2070240233Sglebius 2071240233Sglebius if (s->sync_state == PFSYNC_S_NONE && 2072240233Sglebius s->timeout < PFTM_MAX && 2073240233Sglebius s->pfsync_time <= sc->sc_ureq_received) { 2074240233Sglebius pfsync_update_state_req(s); 2075240233Sglebius sent++; 2076240233Sglebius } 2077223637Sbz } 2078240233Sglebius PF_HASHROW_UNLOCK(ih); 2079226663Sglebius } 2080130613Smlaier 2081240233Sglebius /* We're done. */ 2082240233Sglebius pfsync_bulk_status(PFSYNC_BUS_END); 2083240233Sglebius 2084240233Sglebiusfull: 2085223637Sbz CURVNET_RESTORE(); 2086223637Sbz} 2087223637Sbz 2088240233Sglebiusstatic void 2089223637Sbzpfsync_bulk_status(u_int8_t status) 2090223637Sbz{ 2091223637Sbz struct { 2092223637Sbz struct pfsync_subheader subh; 2093223637Sbz struct pfsync_bus bus; 2094223637Sbz } __packed r; 2095223637Sbz 2096223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2097130613Smlaier 2098223637Sbz bzero(&r, sizeof(r)); 2099171168Smlaier 2100223637Sbz r.subh.action = PFSYNC_ACT_BUS; 2101223637Sbz r.subh.count = htons(1); 2102240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_BUS]++; 2103223637Sbz 2104223637Sbz r.bus.creatorid = V_pf_status.hostid; 2105223637Sbz r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 2106223637Sbz r.bus.status = status; 2107130613Smlaier 2108240233Sglebius PFSYNC_LOCK(sc); 2109223637Sbz pfsync_send_plus(&r, sizeof(r)); 2110240233Sglebius PFSYNC_UNLOCK(sc); 2111126258Smlaier} 2112126261Smlaier 2113240233Sglebiusstatic void 2114223637Sbzpfsync_bulk_fail(void *arg) 2115171168Smlaier{ 2116223637Sbz struct pfsync_softc *sc = arg; 2117171168Smlaier 2118223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 2119171168Smlaier 2120240233Sglebius PFSYNC_BLOCK_ASSERT(sc); 2121240233Sglebius 2122223637Sbz if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 2123223637Sbz /* Try again */ 2124223637Sbz callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 2125223637Sbz pfsync_bulk_fail, V_pfsyncif); 2126240233Sglebius PFSYNC_LOCK(sc); 2127223637Sbz pfsync_request_update(0, 0); 2128240233Sglebius PFSYNC_UNLOCK(sc); 2129223637Sbz } else { 2130240233Sglebius /* Pretend like the transfer was ok. */ 2131223637Sbz sc->sc_ureq_sent = 0; 2132223637Sbz sc->sc_bulk_tries = 0; 2133240233Sglebius PFSYNC_LOCK(sc); 2134240233Sglebius if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 2135228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, 2136228736Sglebius "pfsync bulk fail"); 2137240233Sglebius sc->sc_flags |= PFSYNCF_OK; 2138240233Sglebius PFSYNC_UNLOCK(sc); 2139223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 2140223637Sbz printf("pfsync: failed to receive bulk update\n"); 2141223637Sbz } 2142171168Smlaier 2143223637Sbz CURVNET_RESTORE(); 2144223637Sbz} 2145171168Smlaier 2146240233Sglebiusstatic void 2147223637Sbzpfsync_send_plus(void *plus, size_t pluslen) 2148223637Sbz{ 2149223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2150223637Sbz 2151240233Sglebius PFSYNC_LOCK_ASSERT(sc); 2152226544Sbz 2153240233Sglebius if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) 2154240233Sglebius pfsync_sendout(1); 2155223637Sbz 2156223637Sbz sc->sc_plus = plus; 2157223637Sbz sc->sc_len += (sc->sc_pluslen = pluslen); 2158223637Sbz 2159240233Sglebius pfsync_sendout(1); 2160171168Smlaier} 2161171168Smlaier 2162240233Sglebiusstatic void 2163223637Sbzpfsync_timeout(void *arg) 2164223637Sbz{ 2165223637Sbz struct pfsync_softc *sc = arg; 2166223637Sbz 2167223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 2168240233Sglebius PFSYNC_LOCK(sc); 2169240233Sglebius pfsync_push(sc); 2170240233Sglebius PFSYNC_UNLOCK(sc); 2171240233Sglebius CURVNET_RESTORE(); 2172240233Sglebius} 2173223637Sbz 2174240233Sglebiusstatic void 2175240233Sglebiuspfsync_push(struct pfsync_softc *sc) 2176240233Sglebius{ 2177223637Sbz 2178240233Sglebius PFSYNC_LOCK_ASSERT(sc); 2179171168Smlaier 2180240233Sglebius sc->sc_flags |= PFSYNCF_PUSH; 2181240233Sglebius swi_sched(V_pfsync_swi_cookie, 0); 2182223637Sbz} 2183171168Smlaier 2184240233Sglebiusstatic void 2185223637Sbzpfsyncintr(void *arg) 2186226660Sglebius{ 2187226660Sglebius struct pfsync_softc *sc = arg; 2188226831Sglebius struct mbuf *m, *n; 2189226660Sglebius 2190226660Sglebius CURVNET_SET(sc->sc_ifp->if_vnet); 2191226660Sglebius 2192240233Sglebius PFSYNC_LOCK(sc); 2193240233Sglebius if ((sc->sc_flags & PFSYNCF_PUSH) && sc->sc_len > PFSYNC_MINPKT) { 2194240233Sglebius pfsync_sendout(0); 2195240233Sglebius sc->sc_flags &= ~PFSYNCF_PUSH; 2196240233Sglebius } 2197229976Sglebius _IF_DEQUEUE_ALL(&sc->sc_ifp->if_snd, m); 2198240233Sglebius PFSYNC_UNLOCK(sc); 2199226660Sglebius 2200226831Sglebius for (; m != NULL; m = n) { 2201226831Sglebius 2202226831Sglebius n = m->m_nextpkt; 2203226831Sglebius m->m_nextpkt = NULL; 2204240233Sglebius 2205240233Sglebius /* 2206240233Sglebius * We distinguish between a deferral packet and our 2207240233Sglebius * own pfsync packet based on M_SKIP_FIREWALL 2208240233Sglebius * flag. This is XXX. 2209240233Sglebius */ 2210240233Sglebius if (m->m_flags & M_SKIP_FIREWALL) 2211240233Sglebius ip_output(m, NULL, NULL, 0, NULL, NULL); 2212240233Sglebius else if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, 2213240233Sglebius NULL) == 0) 2214226660Sglebius V_pfsyncstats.pfsyncs_opackets++; 2215226660Sglebius else 2216226660Sglebius V_pfsyncstats.pfsyncs_oerrors++; 2217226660Sglebius } 2218226660Sglebius CURVNET_RESTORE(); 2219226660Sglebius} 2220171168Smlaier 2221229850Sglebiusstatic int 2222240233Sglebiuspfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) 2223167710Sbms{ 2224229850Sglebius struct ip_moptions *imo = &sc->sc_imo; 2225229850Sglebius int error; 2226167710Sbms 2227240233Sglebius if (!(ifp->if_flags & IFF_MULTICAST)) 2228229850Sglebius return (EADDRNOTAVAIL); 2229167710Sbms 2230240233Sglebius imo->imo_membership = (struct in_multi **)mship; 2231229850Sglebius imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 2232229850Sglebius imo->imo_multicast_vif = -1; 2233223637Sbz 2234240233Sglebius if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL, 2235229850Sglebius &imo->imo_membership[0])) != 0) { 2236240233Sglebius imo->imo_membership = NULL; 2237229850Sglebius return (error); 2238167710Sbms } 2239229850Sglebius imo->imo_num_memberships++; 2240240233Sglebius imo->imo_multicast_ifp = ifp; 2241229850Sglebius imo->imo_multicast_ttl = PFSYNC_DFLTTL; 2242229850Sglebius imo->imo_multicast_loop = 0; 2243167710Sbms 2244229850Sglebius return (0); 2245167710Sbms} 2246167710Sbms 2247229850Sglebiusstatic void 2248229850Sglebiuspfsync_multicast_cleanup(struct pfsync_softc *sc) 2249229850Sglebius{ 2250229850Sglebius struct ip_moptions *imo = &sc->sc_imo; 2251229850Sglebius 2252229850Sglebius in_leavegroup(imo->imo_membership[0], NULL); 2253229850Sglebius free(imo->imo_membership, M_PFSYNC); 2254229850Sglebius imo->imo_membership = NULL; 2255229850Sglebius imo->imo_multicast_ifp = NULL; 2256229850Sglebius} 2257229850Sglebius 2258229850Sglebius#ifdef INET 2259229850Sglebiusextern struct domain inetdomain; 2260229850Sglebiusstatic struct protosw in_pfsync_protosw = { 2261229964Sglebius .pr_type = SOCK_RAW, 2262229964Sglebius .pr_domain = &inetdomain, 2263229964Sglebius .pr_protocol = IPPROTO_PFSYNC, 2264229964Sglebius .pr_flags = PR_ATOMIC|PR_ADDR, 2265229964Sglebius .pr_input = pfsync_input, 2266229964Sglebius .pr_output = (pr_output_t *)rip_output, 2267229964Sglebius .pr_ctloutput = rip_ctloutput, 2268229964Sglebius .pr_usrreqs = &rip_usrreqs 2269229850Sglebius}; 2270229850Sglebius#endif 2271229850Sglebius 2272241057Sglebiusstatic void 2273241057Sglebiuspfsync_pointers_init() 2274241057Sglebius{ 2275241057Sglebius 2276241057Sglebius PF_RULES_WLOCK(); 2277241057Sglebius pfsync_state_import_ptr = pfsync_state_import; 2278241057Sglebius pfsync_insert_state_ptr = pfsync_insert_state; 2279241057Sglebius pfsync_update_state_ptr = pfsync_update_state; 2280241057Sglebius pfsync_delete_state_ptr = pfsync_delete_state; 2281241057Sglebius pfsync_clear_states_ptr = pfsync_clear_states; 2282241057Sglebius pfsync_defer_ptr = pfsync_defer; 2283241057Sglebius PF_RULES_WUNLOCK(); 2284241057Sglebius} 2285241057Sglebius 2286241057Sglebiusstatic void 2287241057Sglebiuspfsync_pointers_uninit() 2288241057Sglebius{ 2289241057Sglebius 2290241057Sglebius PF_RULES_WLOCK(); 2291241057Sglebius pfsync_state_import_ptr = NULL; 2292241057Sglebius pfsync_insert_state_ptr = NULL; 2293241057Sglebius pfsync_update_state_ptr = NULL; 2294241057Sglebius pfsync_delete_state_ptr = NULL; 2295241057Sglebius pfsync_clear_states_ptr = NULL; 2296241057Sglebius pfsync_defer_ptr = NULL; 2297241057Sglebius PF_RULES_WUNLOCK(); 2298241057Sglebius} 2299241057Sglebius 2300223637Sbzstatic int 2301229850Sglebiuspfsync_init() 2302147261Smlaier{ 2303229850Sglebius VNET_ITERATOR_DECL(vnet_iter); 2304223637Sbz int error = 0; 2305126261Smlaier 2306229850Sglebius VNET_LIST_RLOCK(); 2307229850Sglebius VNET_FOREACH(vnet_iter) { 2308229850Sglebius CURVNET_SET(vnet_iter); 2309241610Sglebius V_pfsync_cloner = if_clone_simple(pfsyncname, 2310241610Sglebius pfsync_clone_create, pfsync_clone_destroy, 1); 2311241610Sglebius error = swi_add(NULL, pfsyncname, pfsyncintr, V_pfsyncif, 2312229850Sglebius SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie); 2313229850Sglebius CURVNET_RESTORE(); 2314229850Sglebius if (error) 2315229850Sglebius goto fail_locked; 2316229850Sglebius } 2317229850Sglebius VNET_LIST_RUNLOCK(); 2318229850Sglebius#ifdef INET 2319229850Sglebius error = pf_proto_register(PF_INET, &in_pfsync_protosw); 2320223637Sbz if (error) 2321229850Sglebius goto fail; 2322229850Sglebius error = ipproto_register(IPPROTO_PFSYNC); 2323229850Sglebius if (error) { 2324229850Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 2325229850Sglebius goto fail; 2326229850Sglebius } 2327229850Sglebius#endif 2328241057Sglebius pfsync_pointers_init(); 2329223637Sbz 2330223637Sbz return (0); 2331229850Sglebius 2332229850Sglebiusfail: 2333229850Sglebius VNET_LIST_RLOCK(); 2334229850Sglebiusfail_locked: 2335229850Sglebius VNET_FOREACH(vnet_iter) { 2336229850Sglebius CURVNET_SET(vnet_iter); 2337229850Sglebius if (V_pfsync_swi_cookie) { 2338229850Sglebius swi_remove(V_pfsync_swi_cookie); 2339241610Sglebius if_clone_detach(V_pfsync_cloner); 2340229850Sglebius } 2341229850Sglebius CURVNET_RESTORE(); 2342229850Sglebius } 2343229850Sglebius VNET_LIST_RUNLOCK(); 2344229850Sglebius 2345229850Sglebius return (error); 2346147261Smlaier} 2347147261Smlaier 2348229850Sglebiusstatic void 2349229850Sglebiuspfsync_uninit() 2350223637Sbz{ 2351229850Sglebius VNET_ITERATOR_DECL(vnet_iter); 2352223637Sbz 2353241057Sglebius pfsync_pointers_uninit(); 2354223637Sbz 2355229850Sglebius ipproto_unregister(IPPROTO_PFSYNC); 2356229850Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 2357229850Sglebius VNET_LIST_RLOCK(); 2358229850Sglebius VNET_FOREACH(vnet_iter) { 2359229850Sglebius CURVNET_SET(vnet_iter); 2360241610Sglebius if_clone_detach(V_pfsync_cloner); 2361229850Sglebius swi_remove(V_pfsync_swi_cookie); 2362229850Sglebius CURVNET_RESTORE(); 2363229850Sglebius } 2364229850Sglebius VNET_LIST_RUNLOCK(); 2365223637Sbz} 2366223637Sbz 2367223637Sbzstatic int 2368126261Smlaierpfsync_modevent(module_t mod, int type, void *data) 2369126261Smlaier{ 2370126261Smlaier int error = 0; 2371126261Smlaier 2372126261Smlaier switch (type) { 2373126261Smlaier case MOD_LOAD: 2374229850Sglebius error = pfsync_init(); 2375126261Smlaier break; 2376229850Sglebius case MOD_QUIESCE: 2377229850Sglebius /* 2378229850Sglebius * Module should not be unloaded due to race conditions. 2379229850Sglebius */ 2380240836Sglebius error = EBUSY; 2381229850Sglebius break; 2382126261Smlaier case MOD_UNLOAD: 2383229850Sglebius pfsync_uninit(); 2384126261Smlaier break; 2385126261Smlaier default: 2386126261Smlaier error = EINVAL; 2387126261Smlaier break; 2388126261Smlaier } 2389126261Smlaier 2390229850Sglebius return (error); 2391126261Smlaier} 2392126261Smlaier 2393126261Smlaierstatic moduledata_t pfsync_mod = { 2394241610Sglebius pfsyncname, 2395126261Smlaier pfsync_modevent, 2396241394Skevlo 0 2397126261Smlaier}; 2398126261Smlaier 2399126261Smlaier#define PFSYNC_MODVER 1 2400126261Smlaier 2401229853SglebiusDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 2402126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER); 2403223637SbzMODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 2404