if_pfsync.c revision 233917
1223637Sbz/* $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ */ 2126258Smlaier 3126258Smlaier/* 4126258Smlaier * Copyright (c) 2002 Michael Shalayeff 5126258Smlaier * All rights reserved. 6126258Smlaier * 7126258Smlaier * Redistribution and use in source and binary forms, with or without 8126258Smlaier * modification, are permitted provided that the following conditions 9126258Smlaier * are met: 10126258Smlaier * 1. Redistributions of source code must retain the above copyright 11126258Smlaier * notice, this list of conditions and the following disclaimer. 12126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright 13126258Smlaier * notice, this list of conditions and the following disclaimer in the 14126258Smlaier * documentation and/or other materials provided with the distribution. 15126258Smlaier * 16126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE. 27126258Smlaier */ 28126258Smlaier 29223637Sbz/* 30223637Sbz * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> 31223637Sbz * 32223637Sbz * Permission to use, copy, modify, and distribute this software for any 33223637Sbz * purpose with or without fee is hereby granted, provided that the above 34223637Sbz * copyright notice and this permission notice appear in all copies. 35223637Sbz * 36223637Sbz * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 37223637Sbz * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 38223637Sbz * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 39223637Sbz * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 40223637Sbz * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 41223637Sbz * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 42223637Sbz * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 43223637Sbz */ 44223637Sbz 45228814Sglebius/* 46228814Sglebius * Revisions picked from OpenBSD after revision 1.110 import: 47228814Sglebius * 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates 48228815Sglebius * 1.120, 1.175 - use monotonic time_uptime 49228816Sglebius * 1.122 - reduce number of updates for non-TCP sessions 50229961Sglebius * 1.128 - cleanups 51232685Sglebius * 1.146 - bzero() mbuf before sparsely filling it with data 52229777Sglebius * 1.170 - SIOCSIFMTU checks 53233846Sglebius * 1.126, 1.142 - deferred packets processing 54233874Sglebius * 1.173 - correct expire time processing 55228814Sglebius */ 56228814Sglebius 57127145Smlaier#ifdef __FreeBSD__ 58126261Smlaier#include "opt_inet.h" 59126261Smlaier#include "opt_inet6.h" 60126261Smlaier#include "opt_pf.h" 61153110Sru 62171168Smlaier#include <sys/cdefs.h> 63171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 233917 2012-04-05 04:41:06Z ae $"); 64171168Smlaier 65228811Sglebius#define NBPFILTER 1 66171168Smlaier#endif /* __FreeBSD__ */ 67153110Sru 68126258Smlaier#include <sys/param.h> 69223637Sbz#include <sys/kernel.h> 70164033Srwatson#ifdef __FreeBSD__ 71223637Sbz#include <sys/bus.h> 72223637Sbz#include <sys/interrupt.h> 73164033Srwatson#include <sys/priv.h> 74164033Srwatson#endif 75130613Smlaier#include <sys/proc.h> 76126258Smlaier#include <sys/systm.h> 77126258Smlaier#include <sys/time.h> 78126258Smlaier#include <sys/mbuf.h> 79126258Smlaier#include <sys/socket.h> 80127145Smlaier#ifdef __FreeBSD__ 81145836Smlaier#include <sys/endian.h> 82126261Smlaier#include <sys/malloc.h> 83129907Smlaier#include <sys/module.h> 84126261Smlaier#include <sys/sockio.h> 85171168Smlaier#include <sys/taskqueue.h> 86130613Smlaier#include <sys/lock.h> 87130613Smlaier#include <sys/mutex.h> 88229850Sglebius#include <sys/protosw.h> 89126261Smlaier#else 90126258Smlaier#include <sys/ioctl.h> 91126258Smlaier#include <sys/timeout.h> 92126261Smlaier#endif 93223637Sbz#include <sys/sysctl.h> 94223637Sbz#ifndef __FreeBSD__ 95223637Sbz#include <sys/pool.h> 96223637Sbz#endif 97126258Smlaier 98126258Smlaier#include <net/if.h> 99171168Smlaier#ifdef __FreeBSD__ 100130933Sbrooks#include <net/if_clone.h> 101130933Sbrooks#endif 102126258Smlaier#include <net/if_types.h> 103126258Smlaier#include <net/route.h> 104126258Smlaier#include <net/bpf.h> 105223637Sbz#include <net/netisr.h> 106223637Sbz#ifdef __FreeBSD__ 107223637Sbz#include <net/vnet.h> 108223637Sbz#endif 109223637Sbz 110171168Smlaier#include <netinet/in.h> 111171168Smlaier#include <netinet/if_ether.h> 112145836Smlaier#include <netinet/tcp.h> 113145836Smlaier#include <netinet/tcp_seq.h> 114126258Smlaier 115126258Smlaier#ifdef INET 116130613Smlaier#include <netinet/in_systm.h> 117126258Smlaier#include <netinet/in_var.h> 118130613Smlaier#include <netinet/ip.h> 119130613Smlaier#include <netinet/ip_var.h> 120126258Smlaier#endif 121126258Smlaier 122126258Smlaier#ifdef INET6 123126258Smlaier#include <netinet6/nd6.h> 124126258Smlaier#endif /* INET6 */ 125126258Smlaier 126228736Sglebius#ifdef __FreeBSD__ 127228736Sglebius#include <netinet/ip_carp.h> 128228736Sglebius#else 129145836Smlaier#include "carp.h" 130145836Smlaier#if NCARP > 0 131171168Smlaier#include <netinet/ip_carp.h> 132145836Smlaier#endif 133228736Sglebius#endif 134145836Smlaier 135126258Smlaier#include <net/pfvar.h> 136126258Smlaier#include <net/if_pfsync.h> 137126258Smlaier 138171168Smlaier#ifndef __FreeBSD__ 139171168Smlaier#include "bpfilter.h" 140171168Smlaier#include "pfsync.h" 141126261Smlaier#endif 142126261Smlaier 143223637Sbz#define PFSYNC_MINPKT ( \ 144223637Sbz sizeof(struct ip) + \ 145223637Sbz sizeof(struct pfsync_header) + \ 146223637Sbz sizeof(struct pfsync_subheader) + \ 147223637Sbz sizeof(struct pfsync_eof)) 148126258Smlaier 149223637Sbzstruct pfsync_pkt { 150223637Sbz struct ip *ip; 151223637Sbz struct in_addr src; 152223637Sbz u_int8_t flags; 153223637Sbz}; 154223637Sbz 155223637Sbzint pfsync_input_hmac(struct mbuf *, int); 156223637Sbz 157223637Sbzint pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *, 158223637Sbz struct pfsync_state_peer *); 159223637Sbz 160223637Sbzint pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int); 161223637Sbzint pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int); 162223637Sbzint pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int); 163223637Sbzint pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int); 164223637Sbzint pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int); 165223637Sbzint pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int); 166223637Sbzint pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int); 167223637Sbzint pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int); 168223637Sbzint pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int); 169223637Sbzint pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int); 170223637Sbzint pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int); 171223637Sbz 172223637Sbzint pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int); 173223637Sbz 174223637Sbzint (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = { 175223637Sbz pfsync_in_clr, /* PFSYNC_ACT_CLR */ 176223637Sbz pfsync_in_ins, /* PFSYNC_ACT_INS */ 177223637Sbz pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ 178223637Sbz pfsync_in_upd, /* PFSYNC_ACT_UPD */ 179223637Sbz pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ 180223637Sbz pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ 181223637Sbz pfsync_in_del, /* PFSYNC_ACT_DEL */ 182223637Sbz pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ 183223637Sbz pfsync_in_error, /* PFSYNC_ACT_INS_F */ 184223637Sbz pfsync_in_error, /* PFSYNC_ACT_DEL_F */ 185223637Sbz pfsync_in_bus, /* PFSYNC_ACT_BUS */ 186223637Sbz pfsync_in_tdb, /* PFSYNC_ACT_TDB */ 187223637Sbz pfsync_in_eof /* PFSYNC_ACT_EOF */ 188223637Sbz}; 189223637Sbz 190223637Sbzstruct pfsync_q { 191223637Sbz int (*write)(struct pf_state *, struct mbuf *, int); 192223637Sbz size_t len; 193223637Sbz u_int8_t action; 194223637Sbz}; 195223637Sbz 196223637Sbz/* we have one of these for every PFSYNC_S_ */ 197223637Sbzint pfsync_out_state(struct pf_state *, struct mbuf *, int); 198223637Sbzint pfsync_out_iack(struct pf_state *, struct mbuf *, int); 199223637Sbzint pfsync_out_upd_c(struct pf_state *, struct mbuf *, int); 200223637Sbzint pfsync_out_del(struct pf_state *, struct mbuf *, int); 201223637Sbz 202223637Sbzstruct pfsync_q pfsync_qs[] = { 203223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS }, 204223637Sbz { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, 205223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD }, 206223637Sbz { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, 207223637Sbz { pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } 208223637Sbz}; 209223637Sbz 210223637Sbzvoid pfsync_q_ins(struct pf_state *, int); 211223637Sbzvoid pfsync_q_del(struct pf_state *); 212223637Sbz 213223637Sbzstruct pfsync_upd_req_item { 214223637Sbz TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; 215223637Sbz struct pfsync_upd_req ur_msg; 216223637Sbz}; 217223637SbzTAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item); 218223637Sbz 219223637Sbzstruct pfsync_deferral { 220223637Sbz TAILQ_ENTRY(pfsync_deferral) pd_entry; 221223637Sbz struct pf_state *pd_st; 222223637Sbz struct mbuf *pd_m; 223223637Sbz#ifdef __FreeBSD__ 224223637Sbz struct callout pd_tmo; 225126258Smlaier#else 226223637Sbz struct timeout pd_tmo; 227126258Smlaier#endif 228223637Sbz}; 229223637SbzTAILQ_HEAD(pfsync_deferrals, pfsync_deferral); 230126258Smlaier 231223637Sbz#define PFSYNC_PLSIZE MAX(sizeof(struct pfsync_upd_req_item), \ 232223637Sbz sizeof(struct pfsync_deferral)) 233223637Sbz 234223637Sbz#ifdef notyet 235223637Sbzint pfsync_out_tdb(struct tdb *, struct mbuf *, int); 236223637Sbz#endif 237223637Sbz 238223637Sbzstruct pfsync_softc { 239223637Sbz#ifdef __FreeBSD__ 240223637Sbz struct ifnet *sc_ifp; 241223637Sbz#else 242223637Sbz struct ifnet sc_if; 243223637Sbz#endif 244223637Sbz struct ifnet *sc_sync_if; 245223637Sbz 246223637Sbz#ifdef __FreeBSD__ 247223637Sbz uma_zone_t sc_pool; 248223637Sbz#else 249223637Sbz struct pool sc_pool; 250223637Sbz#endif 251223637Sbz 252223637Sbz struct ip_moptions sc_imo; 253223637Sbz 254223637Sbz struct in_addr sc_sync_peer; 255223637Sbz u_int8_t sc_maxupdates; 256223637Sbz#ifdef __FreeBSD__ 257223637Sbz int pfsync_sync_ok; 258223637Sbz#endif 259223637Sbz 260223637Sbz struct ip sc_template; 261223637Sbz 262223637Sbz struct pf_state_queue sc_qs[PFSYNC_S_COUNT]; 263223637Sbz size_t sc_len; 264223637Sbz 265223637Sbz struct pfsync_upd_reqs sc_upd_req_list; 266223637Sbz 267233846Sglebius int sc_defer; 268223637Sbz struct pfsync_deferrals sc_deferrals; 269223637Sbz u_int sc_deferred; 270223637Sbz 271223637Sbz void *sc_plus; 272223637Sbz size_t sc_pluslen; 273223637Sbz 274223637Sbz u_int32_t sc_ureq_sent; 275223637Sbz int sc_bulk_tries; 276223637Sbz#ifdef __FreeBSD__ 277223637Sbz struct callout sc_bulkfail_tmo; 278223637Sbz#else 279223637Sbz struct timeout sc_bulkfail_tmo; 280223637Sbz#endif 281223637Sbz 282223637Sbz u_int32_t sc_ureq_received; 283223637Sbz struct pf_state *sc_bulk_next; 284223637Sbz struct pf_state *sc_bulk_last; 285223637Sbz#ifdef __FreeBSD__ 286223637Sbz struct callout sc_bulk_tmo; 287223637Sbz#else 288223637Sbz struct timeout sc_bulk_tmo; 289223637Sbz#endif 290223637Sbz 291223637Sbz TAILQ_HEAD(, tdb) sc_tdb_q; 292223637Sbz 293223637Sbz#ifdef __FreeBSD__ 294223637Sbz struct callout sc_tmo; 295223637Sbz#else 296223637Sbz struct timeout sc_tmo; 297223637Sbz#endif 298223637Sbz}; 299223637Sbz 300223637Sbz#ifdef __FreeBSD__ 301229850Sglebiusstatic MALLOC_DEFINE(M_PFSYNC, "pfsync", "pfsync data"); 302223637Sbzstatic VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 303223637Sbz#define V_pfsyncif VNET(pfsyncif) 304229850Sglebiusstatic VNET_DEFINE(void *, pfsync_swi_cookie) = NULL; 305229850Sglebius#define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) 306223637Sbzstatic VNET_DEFINE(struct pfsyncstats, pfsyncstats); 307223637Sbz#define V_pfsyncstats VNET(pfsyncstats) 308228736Sglebiusstatic VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW; 309228736Sglebius#define V_pfsync_carp_adj VNET(pfsync_carp_adj) 310223637Sbz 311229850Sglebiusstatic void pfsyncintr(void *); 312229850Sglebiusstatic int pfsync_multicast_setup(struct pfsync_softc *); 313229850Sglebiusstatic void pfsync_multicast_cleanup(struct pfsync_softc *); 314229850Sglebiusstatic int pfsync_init(void); 315229850Sglebiusstatic void pfsync_uninit(void); 316229976Sglebiusstatic void pfsync_sendout1(int); 317229850Sglebius 318229976Sglebius#define schednetisr(NETISR_PFSYNC) swi_sched(V_pfsync_swi_cookie, 0) 319229976Sglebius 320223637SbzSYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 321223637SbzSYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 322223637Sbz &VNET_NAME(pfsyncstats), pfsyncstats, 323223637Sbz "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 324228736SglebiusSYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_RW, 325228736Sglebius &VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment"); 326223637Sbz#else 327171168Smlaierstruct pfsync_softc *pfsyncif = NULL; 328171168Smlaierstruct pfsyncstats pfsyncstats; 329223637Sbz#define V_pfsyncstats pfsyncstats 330223637Sbz#endif 331223637Sbz 332171168Smlaiervoid pfsyncattach(int); 333171168Smlaier#ifdef __FreeBSD__ 334171168Smlaierint pfsync_clone_create(struct if_clone *, int, caddr_t); 335171168Smlaiervoid pfsync_clone_destroy(struct ifnet *); 336126261Smlaier#else 337171168Smlaierint pfsync_clone_create(struct if_clone *, int); 338171168Smlaierint pfsync_clone_destroy(struct ifnet *); 339126261Smlaier#endif 340171168Smlaierint pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 341171168Smlaier struct pf_state_peer *); 342171168Smlaiervoid pfsync_update_net_tdb(struct pfsync_tdb *); 343126258Smlaierint pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 344223637Sbz#ifdef __FreeBSD__ 345191148Skmacy struct route *); 346223637Sbz#else 347223637Sbz struct rtentry *); 348223637Sbz#endif 349126258Smlaierint pfsyncioctl(struct ifnet *, u_long, caddr_t); 350126258Smlaiervoid pfsyncstart(struct ifnet *); 351126258Smlaier 352223637Sbzstruct mbuf *pfsync_if_dequeue(struct ifnet *); 353223637Sbz 354223637Sbzvoid pfsync_deferred(struct pf_state *, int); 355223637Sbzvoid pfsync_undefer(struct pfsync_deferral *, int); 356223637Sbzvoid pfsync_defer_tmo(void *); 357223637Sbz 358223637Sbzvoid pfsync_request_update(u_int32_t, u_int64_t); 359223637Sbzvoid pfsync_update_state_req(struct pf_state *); 360223637Sbz 361223637Sbzvoid pfsync_drop(struct pfsync_softc *); 362223637Sbzvoid pfsync_sendout(void); 363223637Sbzvoid pfsync_send_plus(void *, size_t); 364130613Smlaiervoid pfsync_timeout(void *); 365171168Smlaiervoid pfsync_tdb_timeout(void *); 366223637Sbz 367223637Sbzvoid pfsync_bulk_start(void); 368223637Sbzvoid pfsync_bulk_status(u_int8_t); 369130613Smlaiervoid pfsync_bulk_update(void *); 370223637Sbzvoid pfsync_bulk_fail(void *); 371171168Smlaier 372167710Sbms#ifdef __FreeBSD__ 373171168Smlaier/* XXX: ugly */ 374171168Smlaier#define betoh64 (unsigned long long)be64toh 375171168Smlaier#define timeout_del callout_stop 376167710Sbms#endif 377126258Smlaier 378223637Sbz#define PFSYNC_MAX_BULKTRIES 12 379223637Sbz#ifndef __FreeBSD__ 380145836Smlaierint pfsync_sync_ok; 381126261Smlaier#endif 382126258Smlaier 383127145Smlaier#ifdef __FreeBSD__ 384229850SglebiusVNET_DEFINE(struct ifc_simple_data, pfsync_cloner_data); 385229850SglebiusVNET_DEFINE(struct if_clone, pfsync_cloner); 386229850Sglebius#define V_pfsync_cloner_data VNET(pfsync_cloner_data) 387229850Sglebius#define V_pfsync_cloner VNET(pfsync_cloner) 388130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1); 389171168Smlaier#else 390171168Smlaierstruct if_clone pfsync_cloner = 391171168Smlaier IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy); 392171168Smlaier#endif 393126261Smlaier 394171168Smlaiervoid 395171168Smlaierpfsyncattach(int npfsync) 396126261Smlaier{ 397171168Smlaier if_clone_attach(&pfsync_cloner); 398126261Smlaier} 399171168Smlaierint 400160195Ssam#ifdef __FreeBSD__ 401171168Smlaierpfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 402160195Ssam#else 403126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit) 404160195Ssam#endif 405126261Smlaier{ 406223637Sbz struct pfsync_softc *sc; 407130613Smlaier struct ifnet *ifp; 408223637Sbz int q; 409126261Smlaier 410171168Smlaier if (unit != 0) 411171168Smlaier return (EINVAL); 412171168Smlaier 413229850Sglebius#ifdef __FreeBSD__ 414229850Sglebius sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); 415229850Sglebius sc->pfsync_sync_ok = 1; 416229850Sglebius#else 417171168Smlaier pfsync_sync_ok = 1; 418229850Sglebius sc = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT | M_ZERO); 419223637Sbz#endif 420223637Sbz 421223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) 422223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 423223637Sbz 424171168Smlaier#ifdef __FreeBSD__ 425229850Sglebius sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, NULL, NULL, NULL, 426229850Sglebius NULL, UMA_ALIGN_PTR, 0); 427223637Sbz#else 428223637Sbz pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL); 429223637Sbz#endif 430223637Sbz TAILQ_INIT(&sc->sc_upd_req_list); 431223637Sbz TAILQ_INIT(&sc->sc_deferrals); 432223637Sbz sc->sc_deferred = 0; 433171168Smlaier 434223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 435223637Sbz 436223637Sbz sc->sc_len = PFSYNC_MINPKT; 437223637Sbz sc->sc_maxupdates = 128; 438223637Sbz 439229850Sglebius#ifndef __FreeBSD__ 440223637Sbz sc->sc_imo.imo_membership = (struct in_multi **)malloc( 441223637Sbz (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, 442223637Sbz M_WAITOK | M_ZERO); 443223637Sbz sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 444223637Sbz#endif 445223637Sbz 446223637Sbz#ifdef __FreeBSD__ 447223637Sbz ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 448147256Sbrooks if (ifp == NULL) { 449223637Sbz uma_zdestroy(sc->sc_pool); 450229850Sglebius free(sc, M_PFSYNC); 451147256Sbrooks return (ENOSPC); 452147256Sbrooks } 453171168Smlaier if_initname(ifp, ifc->ifc_name, unit); 454223637Sbz#else 455223637Sbz ifp = &sc->sc_if; 456171168Smlaier snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); 457171168Smlaier#endif 458223637Sbz ifp->if_softc = sc; 459130613Smlaier ifp->if_ioctl = pfsyncioctl; 460130613Smlaier ifp->if_output = pfsyncoutput; 461130613Smlaier ifp->if_start = pfsyncstart; 462171168Smlaier ifp->if_type = IFT_PFSYNC; 463130613Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 464223637Sbz ifp->if_hdrlen = sizeof(struct pfsync_header); 465229777Sglebius ifp->if_mtu = ETHERMTU; 466171168Smlaier#ifdef __FreeBSD__ 467223637Sbz callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); 468226661Sglebius callout_init_mtx(&sc->sc_bulk_tmo, &pf_task_mtx, 0); 469223637Sbz callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE); 470171168Smlaier#else 471223637Sbz timeout_set(&sc->sc_tmo, pfsync_timeout, sc); 472223637Sbz timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc); 473223637Sbz timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc); 474171168Smlaier#endif 475223637Sbz 476141584Smlaier if_attach(ifp); 477171168Smlaier#ifndef __FreeBSD__ 478171168Smlaier if_alloc_sadl(ifp); 479126261Smlaier 480171168Smlaier#if NCARP > 0 481171168Smlaier if_addgroup(ifp, "carp"); 482171168Smlaier#endif 483228736Sglebius#endif 484171168Smlaier 485126261Smlaier#if NBPFILTER > 0 486171168Smlaier#ifdef __FreeBSD__ 487141584Smlaier bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 488171168Smlaier#else 489223637Sbz bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 490126261Smlaier#endif 491171168Smlaier#endif 492126261Smlaier 493223637Sbz#ifdef __FreeBSD__ 494223637Sbz V_pfsyncif = sc; 495223637Sbz#else 496223637Sbz pfsyncif = sc; 497223637Sbz#endif 498223637Sbz 499126261Smlaier return (0); 500126261Smlaier} 501171168Smlaier 502171168Smlaier#ifdef __FreeBSD__ 503126261Smlaiervoid 504171168Smlaier#else 505171168Smlaierint 506171168Smlaier#endif 507171168Smlaierpfsync_clone_destroy(struct ifnet *ifp) 508126258Smlaier{ 509223637Sbz struct pfsync_softc *sc = ifp->if_softc; 510223637Sbz 511171168Smlaier#ifdef __FreeBSD__ 512228732Sglebius PF_LOCK(); 513171168Smlaier#endif 514228814Sglebius timeout_del(&sc->sc_bulkfail_tmo); 515228732Sglebius timeout_del(&sc->sc_bulk_tmo); 516223637Sbz timeout_del(&sc->sc_tmo); 517228732Sglebius#ifdef __FreeBSD__ 518228732Sglebius PF_UNLOCK(); 519228736Sglebius if (!sc->pfsync_sync_ok && carp_demote_adj_p) 520228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy"); 521228736Sglebius#else 522223637Sbz#if NCARP > 0 523223637Sbz if (!pfsync_sync_ok) 524223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 525223637Sbz#endif 526223637Sbz#endif 527126258Smlaier#if NBPFILTER > 0 528171168Smlaier bpfdetach(ifp); 529126258Smlaier#endif 530171168Smlaier if_detach(ifp); 531223637Sbz 532223637Sbz pfsync_drop(sc); 533223637Sbz 534223637Sbz while (sc->sc_deferred > 0) 535223637Sbz pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 536223637Sbz 537171168Smlaier#ifdef __FreeBSD__ 538223637Sbz UMA_DESTROY(sc->sc_pool); 539223637Sbz#else 540223637Sbz pool_destroy(&sc->sc_pool); 541223637Sbz#endif 542223637Sbz#ifdef __FreeBSD__ 543171168Smlaier if_free(ifp); 544229850Sglebius if (sc->sc_imo.imo_membership) 545229850Sglebius pfsync_multicast_cleanup(sc); 546229850Sglebius free(sc, M_PFSYNC); 547223637Sbz#else 548223637Sbz free(sc->sc_imo.imo_membership, M_IPMOPTS); 549229850Sglebius free(sc, M_DEVBUF); 550171168Smlaier#endif 551223637Sbz 552223637Sbz#ifdef __FreeBSD__ 553223637Sbz V_pfsyncif = NULL; 554223637Sbz#else 555171168Smlaier pfsyncif = NULL; 556223637Sbz#endif 557223637Sbz 558171168Smlaier#ifndef __FreeBSD__ 559171168Smlaier return (0); 560171168Smlaier#endif 561126258Smlaier} 562126258Smlaier 563223637Sbzstruct mbuf * 564223637Sbzpfsync_if_dequeue(struct ifnet *ifp) 565223637Sbz{ 566223637Sbz struct mbuf *m; 567223637Sbz#ifndef __FreeBSD__ 568223637Sbz int s; 569223637Sbz#endif 570223637Sbz 571223637Sbz#ifdef __FreeBSD__ 572223637Sbz IF_LOCK(&ifp->if_snd); 573223637Sbz _IF_DROP(&ifp->if_snd); 574223637Sbz _IF_DEQUEUE(&ifp->if_snd, m); 575223637Sbz IF_UNLOCK(&ifp->if_snd); 576223637Sbz#else 577223637Sbz s = splnet(); 578223637Sbz IF_DEQUEUE(&ifp->if_snd, m); 579223637Sbz splx(s); 580223637Sbz#endif 581223637Sbz 582223637Sbz return (m); 583223637Sbz} 584223637Sbz 585126258Smlaier/* 586126258Smlaier * Start output on the pfsync interface. 587126258Smlaier */ 588126258Smlaiervoid 589126258Smlaierpfsyncstart(struct ifnet *ifp) 590126258Smlaier{ 591126258Smlaier struct mbuf *m; 592223637Sbz 593223637Sbz while ((m = pfsync_if_dequeue(ifp)) != NULL) { 594171168Smlaier#ifndef __FreeBSD__ 595126258Smlaier IF_DROP(&ifp->if_snd); 596171168Smlaier#endif 597223637Sbz m_freem(m); 598126258Smlaier } 599126258Smlaier} 600126258Smlaier 601126258Smlaierint 602171168Smlaierpfsync_alloc_scrub_memory(struct pfsync_state_peer *s, 603171168Smlaier struct pf_state_peer *d) 604130613Smlaier{ 605171168Smlaier if (s->scrub.scrub_flag && d->scrub == NULL) { 606223637Sbz#ifdef __FreeBSD__ 607223637Sbz d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 608223637Sbz#else 609223637Sbz d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 610223637Sbz#endif 611171168Smlaier if (d->scrub == NULL) 612171168Smlaier return (ENOMEM); 613171168Smlaier } 614171168Smlaier 615171168Smlaier return (0); 616171168Smlaier} 617171168Smlaier 618223637Sbz#ifndef __FreeBSD__ 619223637Sbzvoid 620223637Sbzpfsync_state_export(struct pfsync_state *sp, struct pf_state *st) 621223637Sbz{ 622223637Sbz bzero(sp, sizeof(struct pfsync_state)); 623223637Sbz 624223637Sbz /* copy from state key */ 625223637Sbz sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; 626223637Sbz sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; 627223637Sbz sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; 628223637Sbz sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; 629223637Sbz sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; 630223637Sbz sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; 631223637Sbz sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; 632223637Sbz sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; 633223637Sbz sp->proto = st->key[PF_SK_WIRE]->proto; 634223637Sbz sp->af = st->key[PF_SK_WIRE]->af; 635223637Sbz 636223637Sbz /* copy from state */ 637223637Sbz strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); 638223637Sbz bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 639228815Sglebius sp->creation = htonl(time_uptime - st->creation); 640223637Sbz sp->expire = pf_state_expires(st); 641223637Sbz if (sp->expire <= time_second) 642223637Sbz sp->expire = htonl(0); 643223637Sbz else 644223637Sbz sp->expire = htonl(sp->expire - time_second); 645223637Sbz 646223637Sbz sp->direction = st->direction; 647223637Sbz sp->log = st->log; 648223637Sbz sp->timeout = st->timeout; 649223637Sbz sp->state_flags = st->state_flags; 650223637Sbz if (st->src_node) 651223637Sbz sp->sync_flags |= PFSYNC_FLAG_SRCNODE; 652223637Sbz if (st->nat_src_node) 653223637Sbz sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; 654223637Sbz 655223637Sbz bcopy(&st->id, &sp->id, sizeof(sp->id)); 656223637Sbz sp->creatorid = st->creatorid; 657223637Sbz pf_state_peer_hton(&st->src, &sp->src); 658223637Sbz pf_state_peer_hton(&st->dst, &sp->dst); 659223637Sbz 660223637Sbz if (st->rule.ptr == NULL) 661223637Sbz sp->rule = htonl(-1); 662223637Sbz else 663223637Sbz sp->rule = htonl(st->rule.ptr->nr); 664223637Sbz if (st->anchor.ptr == NULL) 665223637Sbz sp->anchor = htonl(-1); 666223637Sbz else 667223637Sbz sp->anchor = htonl(st->anchor.ptr->nr); 668223637Sbz if (st->nat_rule.ptr == NULL) 669223637Sbz sp->nat_rule = htonl(-1); 670223637Sbz else 671223637Sbz sp->nat_rule = htonl(st->nat_rule.ptr->nr); 672223637Sbz 673223637Sbz pf_state_counter_hton(st->packets[0], sp->packets[0]); 674223637Sbz pf_state_counter_hton(st->packets[1], sp->packets[1]); 675223637Sbz pf_state_counter_hton(st->bytes[0], sp->bytes[0]); 676223637Sbz pf_state_counter_hton(st->bytes[1], sp->bytes[1]); 677223637Sbz 678223637Sbz} 679223637Sbz#endif 680223637Sbz 681171168Smlaierint 682223637Sbzpfsync_state_import(struct pfsync_state *sp, u_int8_t flags) 683171168Smlaier{ 684130613Smlaier struct pf_state *st = NULL; 685223637Sbz struct pf_state_key *skw = NULL, *sks = NULL; 686130613Smlaier struct pf_rule *r = NULL; 687130613Smlaier struct pfi_kif *kif; 688223637Sbz int pool_flags; 689223637Sbz int error; 690130613Smlaier 691229962Sglebius#ifdef __FreeBSD__ 692226544Sbz PF_LOCK_ASSERT(); 693226544Sbz 694223637Sbz if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) { 695223637Sbz#else 696130613Smlaier if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 697223637Sbz#endif 698223637Sbz printf("pfsync_state_import: invalid creator id:" 699130613Smlaier " %08x\n", ntohl(sp->creatorid)); 700130613Smlaier return (EINVAL); 701130613Smlaier } 702130613Smlaier 703223637Sbz if ((kif = pfi_kif_get(sp->ifname)) == NULL) { 704223637Sbz#ifdef __FreeBSD__ 705223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 706223637Sbz#else 707130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 708223637Sbz#endif 709223637Sbz printf("pfsync_state_import: " 710130613Smlaier "unknown interface: %s\n", sp->ifname); 711223637Sbz if (flags & PFSYNC_SI_IOCTL) 712223637Sbz return (EINVAL); 713223637Sbz return (0); /* skip this state */ 714130613Smlaier } 715130613Smlaier 716130613Smlaier /* 717223637Sbz * If the ruleset checksums match or the state is coming from the ioctl, 718223637Sbz * it's safe to associate the state with the rule of that number. 719130613Smlaier */ 720223637Sbz if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && 721223637Sbz (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < 722223637Sbz pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 723171168Smlaier r = pf_main_ruleset.rules[ 724171168Smlaier PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; 725171168Smlaier else 726223637Sbz#ifdef __FreeBSD__ 727223637Sbz r = &V_pf_default_rule; 728223637Sbz#else 729171168Smlaier r = &pf_default_rule; 730223637Sbz#endif 731130613Smlaier 732223637Sbz if ((r->max_states && r->states_cur >= r->max_states)) 733223637Sbz goto cleanup; 734130613Smlaier 735223637Sbz#ifdef __FreeBSD__ 736223637Sbz if (flags & PFSYNC_SI_IOCTL) 737223637Sbz pool_flags = PR_WAITOK | PR_ZERO; 738223637Sbz else 739226656Sglebius pool_flags = PR_NOWAIT | PR_ZERO; 740171168Smlaier 741223637Sbz if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL) 742223637Sbz goto cleanup; 743223637Sbz#else 744223637Sbz if (flags & PFSYNC_SI_IOCTL) 745223637Sbz pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; 746223637Sbz else 747223637Sbz pool_flags = PR_LIMITFAIL | PR_ZERO; 748130613Smlaier 749223637Sbz if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) 750223637Sbz goto cleanup; 751223637Sbz#endif 752145836Smlaier 753223637Sbz if ((skw = pf_alloc_state_key(pool_flags)) == NULL) 754223637Sbz goto cleanup; 755130613Smlaier 756223637Sbz if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], 757223637Sbz &sp->key[PF_SK_STACK].addr[0], sp->af) || 758223637Sbz PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], 759223637Sbz &sp->key[PF_SK_STACK].addr[1], sp->af) || 760223637Sbz sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || 761223637Sbz sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { 762223637Sbz if ((sks = pf_alloc_state_key(pool_flags)) == NULL) 763223637Sbz goto cleanup; 764223637Sbz } else 765223637Sbz sks = skw; 766130613Smlaier 767223637Sbz /* allocate memory for scrub info */ 768223637Sbz if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || 769223637Sbz pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) 770223637Sbz goto cleanup; 771223637Sbz 772223637Sbz /* copy to state key(s) */ 773223637Sbz skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; 774223637Sbz skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; 775223637Sbz skw->port[0] = sp->key[PF_SK_WIRE].port[0]; 776223637Sbz skw->port[1] = sp->key[PF_SK_WIRE].port[1]; 777223637Sbz skw->proto = sp->proto; 778223637Sbz skw->af = sp->af; 779223637Sbz if (sks != skw) { 780223637Sbz sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; 781223637Sbz sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; 782223637Sbz sks->port[0] = sp->key[PF_SK_STACK].port[0]; 783223637Sbz sks->port[1] = sp->key[PF_SK_STACK].port[1]; 784223637Sbz sks->proto = sp->proto; 785223637Sbz sks->af = sp->af; 786223637Sbz } 787223637Sbz 788223637Sbz /* copy to state */ 789130613Smlaier bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 790228815Sglebius st->creation = time_uptime - ntohl(sp->creation); 791223637Sbz st->expire = time_second; 792223637Sbz if (sp->expire) { 793233874Sglebius uint32_t timeout; 794233874Sglebius 795233874Sglebius timeout = r->timeout[sp->timeout]; 796233874Sglebius if (!timeout) 797233917Sae#ifdef __FreeBSD__ 798233917Sae timeout = V_pf_default_rule.timeout[sp->timeout]; 799233917Sae#else 800233874Sglebius timeout = pf_default_rule.timeout[sp->timeout]; 801233917Sae#endif 802233874Sglebius 803233874Sglebius /* sp->expire may have been adaptively scaled by export. */ 804233874Sglebius st->expire -= timeout - ntohl(sp->expire); 805223637Sbz } 806223637Sbz 807130613Smlaier st->direction = sp->direction; 808130613Smlaier st->log = sp->log; 809130613Smlaier st->timeout = sp->timeout; 810200930Sdelphij st->state_flags = sp->state_flags; 811130613Smlaier 812130613Smlaier bcopy(sp->id, &st->id, sizeof(st->id)); 813130613Smlaier st->creatorid = sp->creatorid; 814223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 815223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 816130613Smlaier 817223637Sbz st->rule.ptr = r; 818223637Sbz st->nat_rule.ptr = NULL; 819223637Sbz st->anchor.ptr = NULL; 820223637Sbz st->rt_kif = NULL; 821223637Sbz 822228815Sglebius st->pfsync_time = time_uptime; 823223637Sbz st->sync_state = PFSYNC_S_NONE; 824223637Sbz 825223637Sbz /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 826223637Sbz r->states_cur++; 827223637Sbz r->states_tot++; 828223637Sbz 829223637Sbz if (!ISSET(flags, PFSYNC_SI_IOCTL)) 830223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 831223637Sbz 832223637Sbz if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { 833145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 834223637Sbz r->states_cur--; 835223637Sbz goto cleanup_state; 836223637Sbz } 837223637Sbz 838223637Sbz if (!ISSET(flags, PFSYNC_SI_IOCTL)) { 839223637Sbz CLR(st->state_flags, PFSTATE_NOSYNC); 840223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) { 841223637Sbz pfsync_q_ins(st, PFSYNC_S_IACK); 842223637Sbz schednetisr(NETISR_PFSYNC); 843223637Sbz } 844223637Sbz } 845223637Sbz CLR(st->state_flags, PFSTATE_ACK); 846223637Sbz 847223637Sbz return (0); 848223637Sbz 849223637Sbzcleanup: 850223637Sbz error = ENOMEM; 851223637Sbz if (skw == sks) 852223637Sbz sks = NULL; 853223637Sbz#ifdef __FreeBSD__ 854223637Sbz if (skw != NULL) 855223637Sbz pool_put(&V_pf_state_key_pl, skw); 856223637Sbz if (sks != NULL) 857223637Sbz pool_put(&V_pf_state_key_pl, sks); 858223637Sbz#else 859223637Sbz if (skw != NULL) 860223637Sbz pool_put(&pf_state_key_pl, skw); 861223637Sbz if (sks != NULL) 862223637Sbz pool_put(&pf_state_key_pl, sks); 863223637Sbz#endif 864223637Sbz 865223637Sbzcleanup_state: /* pf_state_insert frees the state keys */ 866223637Sbz if (st) { 867223637Sbz#ifdef __FreeBSD__ 868171168Smlaier if (st->dst.scrub) 869223637Sbz pool_put(&V_pf_state_scrub_pl, st->dst.scrub); 870223637Sbz if (st->src.scrub) 871223637Sbz pool_put(&V_pf_state_scrub_pl, st->src.scrub); 872223637Sbz pool_put(&V_pf_state_pl, st); 873223637Sbz#else 874223637Sbz if (st->dst.scrub) 875171168Smlaier pool_put(&pf_state_scrub_pl, st->dst.scrub); 876171168Smlaier if (st->src.scrub) 877171168Smlaier pool_put(&pf_state_scrub_pl, st->src.scrub); 878130613Smlaier pool_put(&pf_state_pl, st); 879223637Sbz#endif 880130613Smlaier } 881223637Sbz return (error); 882130613Smlaier} 883130613Smlaier 884130613Smlaiervoid 885130613Smlaier#ifdef __FreeBSD__ 886130613Smlaierpfsync_input(struct mbuf *m, __unused int off) 887130613Smlaier#else 888130613Smlaierpfsync_input(struct mbuf *m, ...) 889130613Smlaier#endif 890130613Smlaier{ 891223637Sbz#ifdef __FreeBSD__ 892223637Sbz struct pfsync_softc *sc = V_pfsyncif; 893223637Sbz#else 894223637Sbz struct pfsync_softc *sc = pfsyncif; 895223637Sbz#endif 896223637Sbz struct pfsync_pkt pkt; 897130613Smlaier struct ip *ip = mtod(m, struct ip *); 898130613Smlaier struct pfsync_header *ph; 899223637Sbz struct pfsync_subheader subh; 900130613Smlaier 901223637Sbz int offset; 902223637Sbz int rv; 903130613Smlaier 904223637Sbz V_pfsyncstats.pfsyncs_ipackets++; 905223637Sbz 906130613Smlaier /* verify that we have a sync interface configured */ 907223637Sbz#ifdef __FreeBSD__ 908223637Sbz if (!sc || !sc->sc_sync_if || !V_pf_status.running) 909223637Sbz#else 910223637Sbz if (!sc || !sc->sc_sync_if || !pf_status.running) 911223637Sbz#endif 912130613Smlaier goto done; 913130613Smlaier 914130613Smlaier /* verify that the packet came in on the right interface */ 915223637Sbz if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 916223637Sbz V_pfsyncstats.pfsyncs_badif++; 917130613Smlaier goto done; 918130613Smlaier } 919130613Smlaier 920223637Sbz#ifdef __FreeBSD__ 921223637Sbz sc->sc_ifp->if_ipackets++; 922223637Sbz sc->sc_ifp->if_ibytes += m->m_pkthdr.len; 923223637Sbz#else 924223637Sbz sc->sc_if.if_ipackets++; 925223637Sbz sc->sc_if.if_ibytes += m->m_pkthdr.len; 926223637Sbz#endif 927223637Sbz /* verify that the IP TTL is 255. */ 928130613Smlaier if (ip->ip_ttl != PFSYNC_DFLTTL) { 929223637Sbz V_pfsyncstats.pfsyncs_badttl++; 930130613Smlaier goto done; 931130613Smlaier } 932130613Smlaier 933223637Sbz offset = ip->ip_hl << 2; 934223637Sbz if (m->m_pkthdr.len < offset + sizeof(*ph)) { 935223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 936130613Smlaier goto done; 937130613Smlaier } 938130613Smlaier 939223637Sbz if (offset + sizeof(*ph) > m->m_len) { 940223637Sbz if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 941223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 942223637Sbz return; 943130613Smlaier } 944130613Smlaier ip = mtod(m, struct ip *); 945130613Smlaier } 946223637Sbz ph = (struct pfsync_header *)((char *)ip + offset); 947130613Smlaier 948130613Smlaier /* verify the version */ 949130613Smlaier if (ph->version != PFSYNC_VERSION) { 950223637Sbz V_pfsyncstats.pfsyncs_badver++; 951130613Smlaier goto done; 952130613Smlaier } 953130613Smlaier 954223637Sbz#if 0 955223637Sbz if (pfsync_input_hmac(m, offset) != 0) { 956223637Sbz /* XXX stats */ 957130613Smlaier goto done; 958130613Smlaier } 959223637Sbz#endif 960130613Smlaier 961130613Smlaier /* Cheaper to grab this now than having to mess with mbufs later */ 962223637Sbz pkt.ip = ip; 963223637Sbz pkt.src = ip->ip_src; 964223637Sbz pkt.flags = 0; 965130613Smlaier 966223637Sbz#ifdef __FreeBSD__ 967223637Sbz if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 968223637Sbz#else 969223637Sbz if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 970223637Sbz#endif 971223637Sbz pkt.flags |= PFSYNC_SI_CKSUM; 972171168Smlaier 973223637Sbz offset += sizeof(*ph); 974223637Sbz for (;;) { 975223637Sbz m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 976223637Sbz offset += sizeof(subh); 977223637Sbz 978223637Sbz if (subh.action >= PFSYNC_ACT_MAX) { 979223637Sbz V_pfsyncstats.pfsyncs_badact++; 980223637Sbz goto done; 981130613Smlaier } 982130613Smlaier 983223637Sbz rv = (*pfsync_acts[subh.action])(&pkt, m, offset, 984223637Sbz ntohs(subh.count)); 985223637Sbz if (rv == -1) 986223637Sbz return; 987223637Sbz 988223637Sbz offset += rv; 989223637Sbz } 990223637Sbz 991223637Sbzdone: 992223637Sbz m_freem(m); 993223637Sbz} 994223637Sbz 995223637Sbzint 996223637Sbzpfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 997223637Sbz{ 998223637Sbz struct pfsync_clr *clr; 999223637Sbz struct mbuf *mp; 1000223637Sbz int len = sizeof(*clr) * count; 1001223637Sbz int i, offp; 1002223637Sbz 1003223637Sbz struct pf_state *st, *nexts; 1004223637Sbz struct pf_state_key *sk, *nextsk; 1005223637Sbz struct pf_state_item *si; 1006223637Sbz u_int32_t creatorid; 1007223637Sbz int s; 1008223637Sbz 1009223637Sbz mp = m_pulldown(m, offset, len, &offp); 1010223637Sbz if (mp == NULL) { 1011223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1012223637Sbz return (-1); 1013223637Sbz } 1014223637Sbz clr = (struct pfsync_clr *)(mp->m_data + offp); 1015223637Sbz 1016223637Sbz s = splsoftnet(); 1017130613Smlaier#ifdef __FreeBSD__ 1018223637Sbz PF_LOCK(); 1019130613Smlaier#endif 1020223637Sbz for (i = 0; i < count; i++) { 1021223637Sbz creatorid = clr[i].creatorid; 1022223637Sbz 1023223637Sbz if (clr[i].ifname[0] == '\0') { 1024223637Sbz#ifdef __FreeBSD__ 1025223637Sbz for (st = RB_MIN(pf_state_tree_id, &V_tree_id); 1026223637Sbz st; st = nexts) { 1027223637Sbz nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st); 1028223637Sbz#else 1029145836Smlaier for (st = RB_MIN(pf_state_tree_id, &tree_id); 1030145836Smlaier st; st = nexts) { 1031171168Smlaier nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 1032223637Sbz#endif 1033145836Smlaier if (st->creatorid == creatorid) { 1034223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1035171168Smlaier pf_unlink_state(st); 1036145836Smlaier } 1037130613Smlaier } 1038130613Smlaier } else { 1039223637Sbz if (pfi_kif_get(clr[i].ifname) == NULL) 1040223637Sbz continue; 1041223637Sbz 1042223637Sbz /* XXX correct? */ 1043130613Smlaier#ifdef __FreeBSD__ 1044223637Sbz for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl); 1045223637Sbz#else 1046223637Sbz for (sk = RB_MIN(pf_state_tree, &pf_statetbl); 1047130613Smlaier#endif 1048223637Sbz sk; sk = nextsk) { 1049223637Sbz nextsk = RB_NEXT(pf_state_tree, 1050223637Sbz#ifdef __FreeBSD__ 1051223637Sbz &V_pf_statetbl, sk); 1052223637Sbz#else 1053223637Sbz &pf_statetbl, sk); 1054223637Sbz#endif 1055223637Sbz TAILQ_FOREACH(si, &sk->states, entry) { 1056223637Sbz if (si->s->creatorid == creatorid) { 1057223637Sbz SET(si->s->state_flags, 1058223637Sbz PFSTATE_NOSYNC); 1059223637Sbz pf_unlink_state(si->s); 1060223637Sbz } 1061145836Smlaier } 1062130613Smlaier } 1063130613Smlaier } 1064223637Sbz } 1065130613Smlaier#ifdef __FreeBSD__ 1066223637Sbz PF_UNLOCK(); 1067130613Smlaier#endif 1068223637Sbz splx(s); 1069130613Smlaier 1070223637Sbz return (len); 1071223637Sbz} 1072223637Sbz 1073223637Sbzint 1074223637Sbzpfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1075223637Sbz{ 1076223637Sbz struct mbuf *mp; 1077223637Sbz struct pfsync_state *sa, *sp; 1078223637Sbz int len = sizeof(*sp) * count; 1079223637Sbz int i, offp; 1080223637Sbz 1081223637Sbz int s; 1082223637Sbz 1083223637Sbz mp = m_pulldown(m, offset, len, &offp); 1084223637Sbz if (mp == NULL) { 1085223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1086223637Sbz return (-1); 1087130613Smlaier } 1088223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1089130613Smlaier 1090223637Sbz s = splsoftnet(); 1091130613Smlaier#ifdef __FreeBSD__ 1092223637Sbz PF_LOCK(); 1093130613Smlaier#endif 1094223637Sbz for (i = 0; i < count; i++) { 1095223637Sbz sp = &sa[i]; 1096130613Smlaier 1097223637Sbz /* check for invalid values */ 1098223637Sbz if (sp->timeout >= PFTM_MAX || 1099223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 1100223637Sbz sp->dst.state > PF_TCPS_PROXY_DST || 1101223637Sbz sp->direction > PF_OUT || 1102223637Sbz (sp->af != AF_INET && sp->af != AF_INET6)) { 1103130613Smlaier#ifdef __FreeBSD__ 1104223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1105223637Sbz#else 1106223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1107130613Smlaier#endif 1108223637Sbz printf("pfsync_input: PFSYNC5_ACT_INS: " 1109223637Sbz "invalid value\n"); 1110130613Smlaier } 1111223637Sbz V_pfsyncstats.pfsyncs_badval++; 1112223637Sbz continue; 1113130613Smlaier } 1114223637Sbz 1115223637Sbz if (pfsync_state_import(sp, pkt->flags) == ENOMEM) { 1116223637Sbz /* drop out, but process the rest of the actions */ 1117223637Sbz break; 1118223637Sbz } 1119223637Sbz } 1120130613Smlaier#ifdef __FreeBSD__ 1121223637Sbz PF_UNLOCK(); 1122130613Smlaier#endif 1123223637Sbz splx(s); 1124130613Smlaier 1125223637Sbz return (len); 1126223637Sbz} 1127223637Sbz 1128223637Sbzint 1129223637Sbzpfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1130223637Sbz{ 1131223637Sbz struct pfsync_ins_ack *ia, *iaa; 1132223637Sbz struct pf_state_cmp id_key; 1133223637Sbz struct pf_state *st; 1134223637Sbz 1135223637Sbz struct mbuf *mp; 1136223637Sbz int len = count * sizeof(*ia); 1137223637Sbz int offp, i; 1138223637Sbz int s; 1139223637Sbz 1140223637Sbz mp = m_pulldown(m, offset, len, &offp); 1141223637Sbz if (mp == NULL) { 1142223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1143223637Sbz return (-1); 1144223637Sbz } 1145223637Sbz iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 1146223637Sbz 1147223637Sbz s = splsoftnet(); 1148130613Smlaier#ifdef __FreeBSD__ 1149223637Sbz PF_LOCK(); 1150130613Smlaier#endif 1151223637Sbz for (i = 0; i < count; i++) { 1152223637Sbz ia = &iaa[i]; 1153145836Smlaier 1154223637Sbz bcopy(&ia->id, &id_key.id, sizeof(id_key.id)); 1155223637Sbz id_key.creatorid = ia->creatorid; 1156130613Smlaier 1157223637Sbz st = pf_find_state_byid(&id_key); 1158223637Sbz if (st == NULL) 1159223637Sbz continue; 1160130613Smlaier 1161223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1162223637Sbz pfsync_deferred(st, 0); 1163223637Sbz } 1164130613Smlaier#ifdef __FreeBSD__ 1165223637Sbz PF_UNLOCK(); 1166130613Smlaier#endif 1167223637Sbz splx(s); 1168130613Smlaier /* 1169223637Sbz * XXX this is not yet implemented, but we know the size of the 1170223637Sbz * message so we can skip it. 1171130613Smlaier */ 1172130613Smlaier 1173223637Sbz return (count * sizeof(struct pfsync_ins_ack)); 1174223637Sbz} 1175223637Sbz 1176223637Sbzint 1177223637Sbzpfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, 1178223637Sbz struct pfsync_state_peer *dst) 1179223637Sbz{ 1180223637Sbz int sfail = 0; 1181223637Sbz 1182223637Sbz /* 1183223637Sbz * The state should never go backwards except 1184223637Sbz * for syn-proxy states. Neither should the 1185223637Sbz * sequence window slide backwards. 1186223637Sbz */ 1187223637Sbz if (st->src.state > src->state && 1188223637Sbz (st->src.state < PF_TCPS_PROXY_SRC || 1189223637Sbz src->state >= PF_TCPS_PROXY_SRC)) 1190223637Sbz sfail = 1; 1191223637Sbz else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo))) 1192223637Sbz sfail = 3; 1193223637Sbz else if (st->dst.state > dst->state) { 1194223637Sbz /* There might still be useful 1195223637Sbz * information about the src state here, 1196223637Sbz * so import that part of the update, 1197223637Sbz * then "fail" so we send the updated 1198223637Sbz * state back to the peer who is missing 1199223637Sbz * our what we know. */ 1200223637Sbz pf_state_peer_ntoh(src, &st->src); 1201223637Sbz /* XXX do anything with timeouts? */ 1202223637Sbz sfail = 7; 1203223637Sbz } else if (st->dst.state >= TCPS_SYN_SENT && 1204223637Sbz SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo))) 1205223637Sbz sfail = 4; 1206223637Sbz 1207223637Sbz return (sfail); 1208223637Sbz} 1209223637Sbz 1210223637Sbzint 1211223637Sbzpfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1212223637Sbz{ 1213223637Sbz struct pfsync_state *sa, *sp; 1214223637Sbz struct pf_state_cmp id_key; 1215223637Sbz struct pf_state_key *sk; 1216223637Sbz struct pf_state *st; 1217223637Sbz int sfail; 1218223637Sbz 1219223637Sbz struct mbuf *mp; 1220223637Sbz int len = count * sizeof(*sp); 1221223637Sbz int offp, i; 1222223637Sbz int s; 1223223637Sbz 1224223637Sbz mp = m_pulldown(m, offset, len, &offp); 1225223637Sbz if (mp == NULL) { 1226223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1227223637Sbz return (-1); 1228223637Sbz } 1229223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1230223637Sbz 1231223637Sbz s = splsoftnet(); 1232130613Smlaier#ifdef __FreeBSD__ 1233223637Sbz PF_LOCK(); 1234130613Smlaier#endif 1235223637Sbz for (i = 0; i < count; i++) { 1236223637Sbz sp = &sa[i]; 1237130613Smlaier 1238223637Sbz /* check for invalid values */ 1239223637Sbz if (sp->timeout >= PFTM_MAX || 1240223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 1241223637Sbz sp->dst.state > PF_TCPS_PROXY_DST) { 1242223637Sbz#ifdef __FreeBSD__ 1243223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1244223637Sbz#else 1245223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1246223637Sbz#endif 1247223637Sbz printf("pfsync_input: PFSYNC_ACT_UPD: " 1248223637Sbz "invalid value\n"); 1249130613Smlaier } 1250223637Sbz V_pfsyncstats.pfsyncs_badval++; 1251223637Sbz continue; 1252130613Smlaier } 1253223637Sbz 1254223637Sbz bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1255223637Sbz id_key.creatorid = sp->creatorid; 1256223637Sbz 1257223637Sbz st = pf_find_state_byid(&id_key); 1258223637Sbz if (st == NULL) { 1259223637Sbz /* insert the update */ 1260223637Sbz if (pfsync_state_import(sp, 0)) 1261223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1262223637Sbz continue; 1263223637Sbz } 1264223637Sbz 1265223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1266223637Sbz pfsync_deferred(st, 1); 1267223637Sbz 1268223637Sbz sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1269223637Sbz sfail = 0; 1270223637Sbz if (sk->proto == IPPROTO_TCP) 1271223637Sbz sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst); 1272223637Sbz else { 1273223637Sbz /* 1274223637Sbz * Non-TCP protocol state machine always go 1275223637Sbz * forwards 1276223637Sbz */ 1277223637Sbz if (st->src.state > sp->src.state) 1278223637Sbz sfail = 5; 1279223637Sbz else if (st->dst.state > sp->dst.state) 1280223637Sbz sfail = 6; 1281223637Sbz } 1282223637Sbz 1283223637Sbz if (sfail) { 1284130613Smlaier#ifdef __FreeBSD__ 1285223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1286223637Sbz#else 1287223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1288130613Smlaier#endif 1289223637Sbz printf("pfsync: %s stale update (%d)" 1290223637Sbz " id: %016llx creatorid: %08x\n", 1291223637Sbz (sfail < 7 ? "ignoring" : "partial"), 1292223637Sbz sfail, betoh64(st->id), 1293223637Sbz ntohl(st->creatorid)); 1294223637Sbz } 1295223637Sbz V_pfsyncstats.pfsyncs_stale++; 1296130613Smlaier 1297223637Sbz pfsync_update_state(st); 1298223637Sbz schednetisr(NETISR_PFSYNC); 1299223637Sbz continue; 1300130613Smlaier } 1301223637Sbz pfsync_alloc_scrub_memory(&sp->dst, &st->dst); 1302223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 1303223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 1304233874Sglebius st->expire = time_second; 1305223637Sbz st->timeout = sp->timeout; 1306228815Sglebius st->pfsync_time = time_uptime; 1307223637Sbz } 1308223637Sbz#ifdef __FreeBSD__ 1309223637Sbz PF_UNLOCK(); 1310223637Sbz#endif 1311223637Sbz splx(s); 1312130613Smlaier 1313223637Sbz return (len); 1314223637Sbz} 1315223637Sbz 1316223637Sbzint 1317223637Sbzpfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1318223637Sbz{ 1319223637Sbz struct pfsync_upd_c *ua, *up; 1320223637Sbz struct pf_state_key *sk; 1321223637Sbz struct pf_state_cmp id_key; 1322223637Sbz struct pf_state *st; 1323223637Sbz 1324223637Sbz int len = count * sizeof(*up); 1325223637Sbz int sfail; 1326223637Sbz 1327223637Sbz struct mbuf *mp; 1328223637Sbz int offp, i; 1329223637Sbz int s; 1330223637Sbz 1331223637Sbz mp = m_pulldown(m, offset, len, &offp); 1332223637Sbz if (mp == NULL) { 1333223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1334223637Sbz return (-1); 1335223637Sbz } 1336223637Sbz ua = (struct pfsync_upd_c *)(mp->m_data + offp); 1337223637Sbz 1338223637Sbz s = splsoftnet(); 1339130613Smlaier#ifdef __FreeBSD__ 1340223637Sbz PF_LOCK(); 1341130613Smlaier#endif 1342223637Sbz for (i = 0; i < count; i++) { 1343223637Sbz up = &ua[i]; 1344223637Sbz 1345223637Sbz /* check for invalid values */ 1346223637Sbz if (up->timeout >= PFTM_MAX || 1347223637Sbz up->src.state > PF_TCPS_PROXY_DST || 1348223637Sbz up->dst.state > PF_TCPS_PROXY_DST) { 1349223637Sbz#ifdef __FreeBSD__ 1350223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1351223637Sbz#else 1352223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1353223637Sbz#endif 1354223637Sbz printf("pfsync_input: " 1355223637Sbz "PFSYNC_ACT_UPD_C: " 1356223637Sbz "invalid value\n"); 1357130613Smlaier } 1358223637Sbz V_pfsyncstats.pfsyncs_badval++; 1359223637Sbz continue; 1360223637Sbz } 1361130613Smlaier 1362223637Sbz bcopy(&up->id, &id_key.id, sizeof(id_key.id)); 1363223637Sbz id_key.creatorid = up->creatorid; 1364130613Smlaier 1365223637Sbz st = pf_find_state_byid(&id_key); 1366223637Sbz if (st == NULL) { 1367223637Sbz /* We don't have this state. Ask for it. */ 1368223637Sbz pfsync_request_update(id_key.creatorid, id_key.id); 1369223637Sbz continue; 1370223637Sbz } 1371223637Sbz 1372223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1373223637Sbz pfsync_deferred(st, 1); 1374223637Sbz 1375223637Sbz sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1376223637Sbz sfail = 0; 1377223637Sbz if (sk->proto == IPPROTO_TCP) 1378223637Sbz sfail = pfsync_upd_tcp(st, &up->src, &up->dst); 1379223637Sbz else { 1380223637Sbz /* 1381223637Sbz * Non-TCP protocol state machine always go forwards 1382223637Sbz */ 1383223637Sbz if (st->src.state > up->src.state) 1384223637Sbz sfail = 5; 1385223637Sbz else if (st->dst.state > up->dst.state) 1386223637Sbz sfail = 6; 1387223637Sbz } 1388223637Sbz 1389223637Sbz if (sfail) { 1390171168Smlaier#ifdef __FreeBSD__ 1391223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1392223637Sbz#else 1393223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1394171168Smlaier#endif 1395223637Sbz printf("pfsync: ignoring stale update " 1396223637Sbz "(%d) id: %016llx " 1397223637Sbz "creatorid: %08x\n", sfail, 1398223637Sbz betoh64(st->id), 1399223637Sbz ntohl(st->creatorid)); 1400130613Smlaier } 1401223637Sbz V_pfsyncstats.pfsyncs_stale++; 1402145836Smlaier 1403223637Sbz pfsync_update_state(st); 1404223637Sbz schednetisr(NETISR_PFSYNC); 1405223637Sbz continue; 1406130613Smlaier } 1407223637Sbz pfsync_alloc_scrub_memory(&up->dst, &st->dst); 1408223637Sbz pf_state_peer_ntoh(&up->src, &st->src); 1409223637Sbz pf_state_peer_ntoh(&up->dst, &st->dst); 1410233874Sglebius st->expire = time_second; 1411223637Sbz st->timeout = up->timeout; 1412228815Sglebius st->pfsync_time = time_uptime; 1413223637Sbz } 1414130613Smlaier#ifdef __FreeBSD__ 1415223637Sbz PF_UNLOCK(); 1416130613Smlaier#endif 1417223637Sbz splx(s); 1418223637Sbz 1419223637Sbz return (len); 1420223637Sbz} 1421223637Sbz 1422223637Sbzint 1423223637Sbzpfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1424223637Sbz{ 1425223637Sbz struct pfsync_upd_req *ur, *ura; 1426223637Sbz struct mbuf *mp; 1427223637Sbz int len = count * sizeof(*ur); 1428223637Sbz int i, offp; 1429223637Sbz 1430223637Sbz struct pf_state_cmp id_key; 1431223637Sbz struct pf_state *st; 1432223637Sbz 1433223637Sbz mp = m_pulldown(m, offset, len, &offp); 1434223637Sbz if (mp == NULL) { 1435223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1436223637Sbz return (-1); 1437130613Smlaier } 1438223637Sbz ura = (struct pfsync_upd_req *)(mp->m_data + offp); 1439130613Smlaier 1440229963Sglebius#ifdef __FreeBSD__ 1441229963Sglebius PF_LOCK(); 1442229963Sglebius#endif 1443223637Sbz for (i = 0; i < count; i++) { 1444223637Sbz ur = &ura[i]; 1445130613Smlaier 1446223637Sbz bcopy(&ur->id, &id_key.id, sizeof(id_key.id)); 1447223637Sbz id_key.creatorid = ur->creatorid; 1448223637Sbz 1449223637Sbz if (id_key.id == 0 && id_key.creatorid == 0) 1450223637Sbz pfsync_bulk_start(); 1451223637Sbz else { 1452223637Sbz st = pf_find_state_byid(&id_key); 1453130613Smlaier if (st == NULL) { 1454223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1455130613Smlaier continue; 1456130613Smlaier } 1457223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) 1458223637Sbz continue; 1459223637Sbz 1460223637Sbz pfsync_update_state_req(st); 1461130613Smlaier } 1462223637Sbz } 1463229963Sglebius#ifdef __FreeBSD__ 1464229963Sglebius PF_UNLOCK(); 1465229963Sglebius#endif 1466223637Sbz 1467223637Sbz return (len); 1468223637Sbz} 1469223637Sbz 1470223637Sbzint 1471223637Sbzpfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1472223637Sbz{ 1473223637Sbz struct mbuf *mp; 1474223637Sbz struct pfsync_state *sa, *sp; 1475223637Sbz struct pf_state_cmp id_key; 1476223637Sbz struct pf_state *st; 1477223637Sbz int len = count * sizeof(*sp); 1478223637Sbz int offp, i; 1479223637Sbz int s; 1480223637Sbz 1481223637Sbz mp = m_pulldown(m, offset, len, &offp); 1482223637Sbz if (mp == NULL) { 1483223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1484223637Sbz return (-1); 1485223637Sbz } 1486223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1487223637Sbz 1488223637Sbz s = splsoftnet(); 1489130613Smlaier#ifdef __FreeBSD__ 1490223637Sbz PF_LOCK(); 1491130613Smlaier#endif 1492223637Sbz for (i = 0; i < count; i++) { 1493223637Sbz sp = &sa[i]; 1494223637Sbz 1495223637Sbz bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1496223637Sbz id_key.creatorid = sp->creatorid; 1497223637Sbz 1498223637Sbz st = pf_find_state_byid(&id_key); 1499223637Sbz if (st == NULL) { 1500223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1501223637Sbz continue; 1502130613Smlaier } 1503223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1504223637Sbz pf_unlink_state(st); 1505223637Sbz } 1506223637Sbz#ifdef __FreeBSD__ 1507223637Sbz PF_UNLOCK(); 1508223637Sbz#endif 1509223637Sbz splx(s); 1510130613Smlaier 1511223637Sbz return (len); 1512223637Sbz} 1513223637Sbz 1514223637Sbzint 1515223637Sbzpfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1516223637Sbz{ 1517223637Sbz struct mbuf *mp; 1518223637Sbz struct pfsync_del_c *sa, *sp; 1519223637Sbz struct pf_state_cmp id_key; 1520223637Sbz struct pf_state *st; 1521223637Sbz int len = count * sizeof(*sp); 1522223637Sbz int offp, i; 1523223637Sbz int s; 1524223637Sbz 1525223637Sbz mp = m_pulldown(m, offset, len, &offp); 1526223637Sbz if (mp == NULL) { 1527223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1528223637Sbz return (-1); 1529223637Sbz } 1530223637Sbz sa = (struct pfsync_del_c *)(mp->m_data + offp); 1531223637Sbz 1532223637Sbz s = splsoftnet(); 1533130613Smlaier#ifdef __FreeBSD__ 1534223637Sbz PF_LOCK(); 1535130613Smlaier#endif 1536223637Sbz for (i = 0; i < count; i++) { 1537223637Sbz sp = &sa[i]; 1538130613Smlaier 1539223637Sbz bcopy(&sp->id, &id_key.id, sizeof(id_key.id)); 1540223637Sbz id_key.creatorid = sp->creatorid; 1541223637Sbz 1542223637Sbz st = pf_find_state_byid(&id_key); 1543223637Sbz if (st == NULL) { 1544223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1545223637Sbz continue; 1546223637Sbz } 1547223637Sbz 1548223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1549223637Sbz pf_unlink_state(st); 1550223637Sbz } 1551130613Smlaier#ifdef __FreeBSD__ 1552226531Sbz PF_UNLOCK(); 1553223637Sbz#endif 1554223637Sbz splx(s); 1555223637Sbz 1556223637Sbz return (len); 1557223637Sbz} 1558223637Sbz 1559223637Sbzint 1560223637Sbzpfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1561223637Sbz{ 1562223637Sbz#ifdef __FreeBSD__ 1563223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1564130613Smlaier#else 1565223637Sbz struct pfsync_softc *sc = pfsyncif; 1566130613Smlaier#endif 1567223637Sbz struct pfsync_bus *bus; 1568223637Sbz struct mbuf *mp; 1569223637Sbz int len = count * sizeof(*bus); 1570223637Sbz int offp; 1571223637Sbz 1572223637Sbz /* If we're not waiting for a bulk update, who cares. */ 1573223637Sbz if (sc->sc_ureq_sent == 0) 1574223637Sbz return (len); 1575223637Sbz 1576223637Sbz mp = m_pulldown(m, offset, len, &offp); 1577223637Sbz if (mp == NULL) { 1578223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1579223637Sbz return (-1); 1580223637Sbz } 1581223637Sbz bus = (struct pfsync_bus *)(mp->m_data + offp); 1582223637Sbz 1583223637Sbz switch (bus->status) { 1584223637Sbz case PFSYNC_BUS_START: 1585130613Smlaier#ifdef __FreeBSD__ 1586228814Sglebius callout_reset(&sc->sc_bulkfail_tmo, 4 * hz + 1587228855Spluknet V_pf_pool_limits[PF_LIMIT_STATES].limit / 1588229777Sglebius ((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) / 1589228814Sglebius sizeof(struct pfsync_state)), 1590228814Sglebius pfsync_bulk_fail, V_pfsyncif); 1591223637Sbz#else 1592228814Sglebius timeout_add(&sc->sc_bulkfail_tmo, 4 * hz + 1593223637Sbz pf_pool_limits[PF_LIMIT_STATES].limit / 1594228814Sglebius ((sc->sc_if.if_mtu - PFSYNC_MINPKT) / 1595228814Sglebius sizeof(struct pfsync_state))); 1596223637Sbz#endif 1597223637Sbz#ifdef __FreeBSD__ 1598223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1599223637Sbz#else 1600223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1601223637Sbz#endif 1602223637Sbz printf("pfsync: received bulk update start\n"); 1603130613Smlaier break; 1604130613Smlaier 1605223637Sbz case PFSYNC_BUS_END: 1606223637Sbz if (time_uptime - ntohl(bus->endtime) >= 1607223637Sbz sc->sc_ureq_sent) { 1608223637Sbz /* that's it, we're happy */ 1609223637Sbz sc->sc_ureq_sent = 0; 1610223637Sbz sc->sc_bulk_tries = 0; 1611223637Sbz timeout_del(&sc->sc_bulkfail_tmo); 1612130613Smlaier#ifdef __FreeBSD__ 1613228736Sglebius if (!sc->pfsync_sync_ok && carp_demote_adj_p) 1614228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, 1615228736Sglebius "pfsync bulk done"); 1616228736Sglebius sc->pfsync_sync_ok = 1; 1617130613Smlaier#else 1618228736Sglebius#if NCARP > 0 1619223637Sbz if (!pfsync_sync_ok) 1620223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 1621223637Sbz#endif 1622223637Sbz pfsync_sync_ok = 1; 1623171168Smlaier#endif 1624223637Sbz#ifdef __FreeBSD__ 1625223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1626130613Smlaier#else 1627223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1628130613Smlaier#endif 1629223637Sbz printf("pfsync: received valid " 1630223637Sbz "bulk update end\n"); 1631223637Sbz } else { 1632223637Sbz#ifdef __FreeBSD__ 1633223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1634223637Sbz#else 1635223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1636145836Smlaier#endif 1637223637Sbz printf("pfsync: received invalid " 1638223637Sbz "bulk update end: bad timestamp\n"); 1639130613Smlaier } 1640130613Smlaier break; 1641223637Sbz } 1642223637Sbz 1643223637Sbz return (len); 1644223637Sbz} 1645223637Sbz 1646223637Sbzint 1647223637Sbzpfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1648223637Sbz{ 1649223637Sbz int len = count * sizeof(struct pfsync_tdb); 1650223637Sbz 1651223637Sbz#if defined(IPSEC) 1652223637Sbz struct pfsync_tdb *tp; 1653223637Sbz struct mbuf *mp; 1654223637Sbz int offp; 1655223637Sbz int i; 1656223637Sbz int s; 1657223637Sbz 1658223637Sbz mp = m_pulldown(m, offset, len, &offp); 1659223637Sbz if (mp == NULL) { 1660223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1661223637Sbz return (-1); 1662223637Sbz } 1663223637Sbz tp = (struct pfsync_tdb *)(mp->m_data + offp); 1664223637Sbz 1665223637Sbz s = splsoftnet(); 1666171168Smlaier#ifdef __FreeBSD__ 1667223637Sbz PF_LOCK(); 1668171168Smlaier#endif 1669223637Sbz for (i = 0; i < count; i++) 1670223637Sbz pfsync_update_net_tdb(&tp[i]); 1671171168Smlaier#ifdef __FreeBSD__ 1672223637Sbz PF_UNLOCK(); 1673171168Smlaier#endif 1674223637Sbz splx(s); 1675171168Smlaier#endif 1676223637Sbz 1677223637Sbz return (len); 1678223637Sbz} 1679223637Sbz 1680223637Sbz#if defined(IPSEC) 1681223637Sbz/* Update an in-kernel tdb. Silently fail if no tdb is found. */ 1682223637Sbzvoid 1683223637Sbzpfsync_update_net_tdb(struct pfsync_tdb *pt) 1684223637Sbz{ 1685223637Sbz struct tdb *tdb; 1686223637Sbz int s; 1687223637Sbz 1688223637Sbz /* check for invalid values */ 1689223637Sbz if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 1690223637Sbz (pt->dst.sa.sa_family != AF_INET && 1691223637Sbz pt->dst.sa.sa_family != AF_INET6)) 1692223637Sbz goto bad; 1693223637Sbz 1694223637Sbz s = spltdb(); 1695223637Sbz tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 1696223637Sbz if (tdb) { 1697223637Sbz pt->rpl = ntohl(pt->rpl); 1698223637Sbz pt->cur_bytes = betoh64(pt->cur_bytes); 1699223637Sbz 1700223637Sbz /* Neither replay nor byte counter should ever decrease. */ 1701223637Sbz if (pt->rpl < tdb->tdb_rpl || 1702223637Sbz pt->cur_bytes < tdb->tdb_cur_bytes) { 1703223637Sbz splx(s); 1704223637Sbz goto bad; 1705223637Sbz } 1706223637Sbz 1707223637Sbz tdb->tdb_rpl = pt->rpl; 1708223637Sbz tdb->tdb_cur_bytes = pt->cur_bytes; 1709130613Smlaier } 1710223637Sbz splx(s); 1711223637Sbz return; 1712130613Smlaier 1713223637Sbzbad: 1714223637Sbz#ifdef __FreeBSD__ 1715223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1716223637Sbz#else 1717223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1718223637Sbz#endif 1719223637Sbz printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 1720223637Sbz "invalid value\n"); 1721223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1722223637Sbz return; 1723130613Smlaier} 1724223637Sbz#endif 1725130613Smlaier 1726223637Sbz 1727130613Smlaierint 1728223637Sbzpfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1729223637Sbz{ 1730223637Sbz /* check if we are at the right place in the packet */ 1731223637Sbz if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof)) 1732223637Sbz V_pfsyncstats.pfsyncs_badact++; 1733223637Sbz 1734223637Sbz /* we're done. free and let the caller return */ 1735223637Sbz m_freem(m); 1736223637Sbz return (-1); 1737223637Sbz} 1738223637Sbz 1739223637Sbzint 1740223637Sbzpfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1741223637Sbz{ 1742223637Sbz V_pfsyncstats.pfsyncs_badact++; 1743223637Sbz 1744223637Sbz m_freem(m); 1745223637Sbz return (-1); 1746223637Sbz} 1747223637Sbz 1748223637Sbzint 1749126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 1750223637Sbz#ifdef __FreeBSD__ 1751223637Sbz struct route *rt) 1752223637Sbz#else 1753223637Sbz struct rtentry *rt) 1754223637Sbz#endif 1755126258Smlaier{ 1756126258Smlaier m_freem(m); 1757126258Smlaier return (0); 1758126258Smlaier} 1759126258Smlaier 1760126258Smlaier/* ARGSUSED */ 1761126258Smlaierint 1762126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1763126258Smlaier{ 1764130613Smlaier#ifndef __FreeBSD__ 1765130613Smlaier struct proc *p = curproc; 1766130613Smlaier#endif 1767126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1768126258Smlaier struct ifreq *ifr = (struct ifreq *)data; 1769130613Smlaier struct ip_moptions *imo = &sc->sc_imo; 1770130613Smlaier struct pfsyncreq pfsyncr; 1771130613Smlaier struct ifnet *sifp; 1772223637Sbz struct ip *ip; 1773130613Smlaier int s, error; 1774126258Smlaier 1775126258Smlaier switch (cmd) { 1776223637Sbz#if 0 1777126258Smlaier case SIOCSIFADDR: 1778126258Smlaier case SIOCAIFADDR: 1779126258Smlaier case SIOCSIFDSTADDR: 1780223637Sbz#endif 1781126258Smlaier case SIOCSIFFLAGS: 1782148891Smlaier#ifdef __FreeBSD__ 1783126258Smlaier if (ifp->if_flags & IFF_UP) 1784148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1785126258Smlaier else 1786148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1787148891Smlaier#else 1788148891Smlaier if (ifp->if_flags & IFF_UP) 1789148891Smlaier ifp->if_flags |= IFF_RUNNING; 1790148891Smlaier else 1791148891Smlaier ifp->if_flags &= ~IFF_RUNNING; 1792148891Smlaier#endif 1793126258Smlaier break; 1794126258Smlaier case SIOCSIFMTU: 1795229777Sglebius if (!sc->sc_sync_if || 1796229777Sglebius ifr->ifr_mtu <= PFSYNC_MINPKT || 1797229777Sglebius ifr->ifr_mtu > sc->sc_sync_if->if_mtu) 1798126258Smlaier return (EINVAL); 1799223637Sbz if (ifr->ifr_mtu < ifp->if_mtu) { 1800223637Sbz s = splnet(); 1801130613Smlaier#ifdef __FreeBSD__ 1802223637Sbz PF_LOCK(); 1803130613Smlaier#endif 1804223637Sbz pfsync_sendout(); 1805130613Smlaier#ifdef __FreeBSD__ 1806223637Sbz PF_UNLOCK(); 1807130613Smlaier#endif 1808223637Sbz splx(s); 1809223637Sbz } 1810223637Sbz ifp->if_mtu = ifr->ifr_mtu; 1811126258Smlaier break; 1812130613Smlaier case SIOCGETPFSYNC: 1813130613Smlaier bzero(&pfsyncr, sizeof(pfsyncr)); 1814223637Sbz if (sc->sc_sync_if) { 1815145836Smlaier strlcpy(pfsyncr.pfsyncr_syncdev, 1816223637Sbz sc->sc_sync_if->if_xname, IFNAMSIZ); 1817223637Sbz } 1818145836Smlaier pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1819130613Smlaier pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1820233846Sglebius pfsyncr.pfsyncr_defer = sc->sc_defer; 1821223637Sbz return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); 1822223637Sbz 1823130613Smlaier case SIOCSETPFSYNC: 1824130613Smlaier#ifdef __FreeBSD__ 1825164033Srwatson if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1826130613Smlaier#else 1827130613Smlaier if ((error = suser(p, p->p_acflag)) != 0) 1828130613Smlaier#endif 1829130613Smlaier return (error); 1830130613Smlaier if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1831130613Smlaier return (error); 1832130613Smlaier 1833171168Smlaier#ifdef __FreeBSD__ 1834171168Smlaier PF_LOCK(); 1835171168Smlaier#endif 1836145836Smlaier if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1837159603Smlaier#ifdef __FreeBSD__ 1838159603Smlaier sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1839159603Smlaier#else 1840145836Smlaier sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1841159603Smlaier#endif 1842145836Smlaier else 1843145836Smlaier sc->sc_sync_peer.s_addr = 1844145836Smlaier pfsyncr.pfsyncr_syncpeer.s_addr; 1845145836Smlaier 1846130613Smlaier if (pfsyncr.pfsyncr_maxupdates > 255) 1847171168Smlaier#ifdef __FreeBSD__ 1848171168Smlaier { 1849171168Smlaier PF_UNLOCK(); 1850171168Smlaier#endif 1851130613Smlaier return (EINVAL); 1852130613Smlaier#ifdef __FreeBSD__ 1853171168Smlaier } 1854130613Smlaier#endif 1855130613Smlaier sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1856233846Sglebius sc->sc_defer = pfsyncr.pfsyncr_defer; 1857130613Smlaier 1858145836Smlaier if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1859223637Sbz sc->sc_sync_if = NULL; 1860171168Smlaier#ifdef __FreeBSD__ 1861171168Smlaier PF_UNLOCK(); 1862229850Sglebius if (imo->imo_membership) 1863229850Sglebius pfsync_multicast_cleanup(sc); 1864229850Sglebius#else 1865145836Smlaier if (imo->imo_num_memberships > 0) { 1866223637Sbz in_delmulti(imo->imo_membership[ 1867223637Sbz --imo->imo_num_memberships]); 1868145836Smlaier imo->imo_multicast_ifp = NULL; 1869145836Smlaier } 1870229850Sglebius#endif 1871130613Smlaier break; 1872130613Smlaier } 1873145836Smlaier 1874130613Smlaier#ifdef __FreeBSD__ 1875171168Smlaier PF_UNLOCK(); 1876130613Smlaier#endif 1877171168Smlaier if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) 1878130613Smlaier return (EINVAL); 1879223637Sbz 1880171168Smlaier#ifdef __FreeBSD__ 1881171168Smlaier PF_LOCK(); 1882171168Smlaier#endif 1883130613Smlaier s = splnet(); 1884141584Smlaier#ifdef __FreeBSD__ 1885171168Smlaier if (sifp->if_mtu < sc->sc_ifp->if_mtu || 1886141584Smlaier#else 1887130613Smlaier if (sifp->if_mtu < sc->sc_if.if_mtu || 1888141584Smlaier#endif 1889223637Sbz (sc->sc_sync_if != NULL && 1890223637Sbz sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1891130613Smlaier sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1892223637Sbz pfsync_sendout(); 1893223637Sbz sc->sc_sync_if = sifp; 1894130613Smlaier 1895171168Smlaier#ifdef __FreeBSD__ 1896229850Sglebius if (imo->imo_membership) { 1897171168Smlaier PF_UNLOCK(); 1898229850Sglebius pfsync_multicast_cleanup(sc); 1899229850Sglebius PF_LOCK(); 1900229850Sglebius } 1901229850Sglebius#else 1902229850Sglebius if (imo->imo_num_memberships > 0) { 1903130613Smlaier in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1904130613Smlaier imo->imo_multicast_ifp = NULL; 1905130613Smlaier } 1906229850Sglebius#endif 1907130613Smlaier 1908229850Sglebius#ifdef __FreeBSD__ 1909223637Sbz if (sc->sc_sync_if && 1910159603Smlaier sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1911229850Sglebius PF_UNLOCK(); 1912229850Sglebius error = pfsync_multicast_setup(sc); 1913229850Sglebius if (error) 1914229850Sglebius return (error); 1915229850Sglebius PF_LOCK(); 1916229850Sglebius } 1917159603Smlaier#else 1918229850Sglebius if (sc->sc_sync_if && 1919145836Smlaier sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1920130613Smlaier struct in_addr addr; 1921130613Smlaier 1922223637Sbz if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 1923223637Sbz sc->sc_sync_if = NULL; 1924145836Smlaier splx(s); 1925145836Smlaier return (EADDRNOTAVAIL); 1926145836Smlaier } 1927171168Smlaier 1928130613Smlaier addr.s_addr = INADDR_PFSYNC_GROUP; 1929145836Smlaier 1930130613Smlaier if ((imo->imo_membership[0] = 1931223637Sbz in_addmulti(&addr, sc->sc_sync_if)) == NULL) { 1932223637Sbz sc->sc_sync_if = NULL; 1933130613Smlaier splx(s); 1934130613Smlaier return (ENOBUFS); 1935130613Smlaier } 1936130613Smlaier imo->imo_num_memberships++; 1937223637Sbz imo->imo_multicast_ifp = sc->sc_sync_if; 1938130613Smlaier imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1939130613Smlaier imo->imo_multicast_loop = 0; 1940145836Smlaier } 1941229850Sglebius#endif /* !__FreeBSD__ */ 1942130613Smlaier 1943223637Sbz ip = &sc->sc_template; 1944223637Sbz bzero(ip, sizeof(*ip)); 1945223637Sbz ip->ip_v = IPVERSION; 1946223637Sbz ip->ip_hl = sizeof(sc->sc_template) >> 2; 1947223637Sbz ip->ip_tos = IPTOS_LOWDELAY; 1948223637Sbz /* len and id are set later */ 1949226609Sglebius#ifdef __FreeBSD__ 1950226609Sglebius ip->ip_off = IP_DF; 1951226609Sglebius#else 1952223637Sbz ip->ip_off = htons(IP_DF); 1953226609Sglebius#endif 1954223637Sbz ip->ip_ttl = PFSYNC_DFLTTL; 1955223637Sbz ip->ip_p = IPPROTO_PFSYNC; 1956223637Sbz ip->ip_src.s_addr = INADDR_ANY; 1957223637Sbz ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; 1958223637Sbz 1959223637Sbz if (sc->sc_sync_if) { 1960130613Smlaier /* Request a full state table update. */ 1961130613Smlaier sc->sc_ureq_sent = time_uptime; 1962223637Sbz#ifdef __FreeBSD__ 1963228736Sglebius if (sc->pfsync_sync_ok && carp_demote_adj_p) 1964228736Sglebius (*carp_demote_adj_p)(V_pfsync_carp_adj, 1965228736Sglebius "pfsync bulk start"); 1966228736Sglebius sc->pfsync_sync_ok = 0; 1967223637Sbz#else 1968228736Sglebius#if NCARP > 0 1969145836Smlaier if (pfsync_sync_ok) 1970171168Smlaier carp_group_demote_adj(&sc->sc_if, 1); 1971171168Smlaier#endif 1972130613Smlaier pfsync_sync_ok = 0; 1973223637Sbz#endif 1974223637Sbz#ifdef __FreeBSD__ 1975223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1976223637Sbz#else 1977130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1978223637Sbz#endif 1979130613Smlaier printf("pfsync: requesting bulk update\n"); 1980130613Smlaier#ifdef __FreeBSD__ 1981226662Sglebius callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 1982226662Sglebius pfsync_bulk_fail, V_pfsyncif); 1983130613Smlaier#else 1984223637Sbz timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 1985130613Smlaier#endif 1986223637Sbz pfsync_request_update(0, 0); 1987130613Smlaier } 1988130613Smlaier#ifdef __FreeBSD__ 1989130613Smlaier PF_UNLOCK(); 1990130613Smlaier#endif 1991130613Smlaier splx(s); 1992130613Smlaier 1993130613Smlaier break; 1994130613Smlaier 1995126258Smlaier default: 1996126258Smlaier return (ENOTTY); 1997126258Smlaier } 1998126258Smlaier 1999126258Smlaier return (0); 2000126258Smlaier} 2001126258Smlaier 2002223637Sbzint 2003223637Sbzpfsync_out_state(struct pf_state *st, struct mbuf *m, int offset) 2004130613Smlaier{ 2005223637Sbz struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset); 2006130613Smlaier 2007223637Sbz pfsync_state_export(sp, st); 2008223637Sbz 2009223637Sbz return (sizeof(*sp)); 2010223637Sbz} 2011223637Sbz 2012223637Sbzint 2013223637Sbzpfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset) 2014223637Sbz{ 2015223637Sbz struct pfsync_ins_ack *iack = 2016223637Sbz (struct pfsync_ins_ack *)(m->m_data + offset); 2017223637Sbz 2018223637Sbz iack->id = st->id; 2019223637Sbz iack->creatorid = st->creatorid; 2020223637Sbz 2021223637Sbz return (sizeof(*iack)); 2022223637Sbz} 2023223637Sbz 2024223637Sbzint 2025223637Sbzpfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset) 2026223637Sbz{ 2027223637Sbz struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset); 2028223637Sbz 2029232685Sglebius bzero(up, sizeof(*up)); 2030223637Sbz up->id = st->id; 2031223637Sbz pf_state_peer_hton(&st->src, &up->src); 2032223637Sbz pf_state_peer_hton(&st->dst, &up->dst); 2033223637Sbz up->creatorid = st->creatorid; 2034223637Sbz up->timeout = st->timeout; 2035130613Smlaier 2036223637Sbz return (sizeof(*up)); 2037223637Sbz} 2038223637Sbz 2039223637Sbzint 2040223637Sbzpfsync_out_del(struct pf_state *st, struct mbuf *m, int offset) 2041223637Sbz{ 2042223637Sbz struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset); 2043223637Sbz 2044223637Sbz dp->id = st->id; 2045223637Sbz dp->creatorid = st->creatorid; 2046223637Sbz 2047223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 2048223637Sbz 2049223637Sbz return (sizeof(*dp)); 2050223637Sbz} 2051223637Sbz 2052223637Sbzvoid 2053223637Sbzpfsync_drop(struct pfsync_softc *sc) 2054223637Sbz{ 2055223637Sbz struct pf_state *st; 2056223637Sbz struct pfsync_upd_req_item *ur; 2057223637Sbz#ifdef notyet 2058223637Sbz struct tdb *t; 2059223637Sbz#endif 2060223637Sbz int q; 2061223637Sbz 2062223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 2063223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2064223637Sbz continue; 2065223637Sbz 2066223637Sbz TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2067223637Sbz#ifdef PFSYNC_DEBUG 2068141584Smlaier#ifdef __FreeBSD__ 2069223637Sbz KASSERT(st->sync_state == q, 2070229964Sglebius ("%s: st->sync_state == q", 2071223637Sbz __FUNCTION__)); 2072141584Smlaier#else 2073223637Sbz KASSERT(st->sync_state == q); 2074171168Smlaier#endif 2075223637Sbz#endif 2076223637Sbz st->sync_state = PFSYNC_S_NONE; 2077223637Sbz } 2078223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 2079223637Sbz } 2080223637Sbz 2081223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2082223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2083223637Sbz pool_put(&sc->sc_pool, ur); 2084223637Sbz } 2085223637Sbz 2086223637Sbz sc->sc_plus = NULL; 2087223637Sbz 2088223637Sbz#ifdef notyet 2089223637Sbz if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2090223637Sbz TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) 2091223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2092223637Sbz 2093223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 2094223637Sbz } 2095223637Sbz#endif 2096223637Sbz 2097223637Sbz sc->sc_len = PFSYNC_MINPKT; 2098126258Smlaier} 2099126258Smlaier 2100229976Sglebius#ifdef __FreeBSD__ 2101229976Sglebiusvoid pfsync_sendout() 2102229976Sglebius{ 2103229976Sglebius pfsync_sendout1(1); 2104229976Sglebius} 2105229976Sglebius 2106229976Sglebiusstatic void 2107229976Sglebiuspfsync_sendout1(int schedswi) 2108229976Sglebius{ 2109229976Sglebius struct pfsync_softc *sc = V_pfsyncif; 2110229976Sglebius#else 2111223637Sbzvoid 2112223637Sbzpfsync_sendout(void) 2113126258Smlaier{ 2114223637Sbz struct pfsync_softc *sc = pfsyncif; 2115223637Sbz#endif 2116223637Sbz#if NBPFILTER > 0 2117223637Sbz#ifdef __FreeBSD__ 2118223637Sbz struct ifnet *ifp = sc->sc_ifp; 2119223637Sbz#else 2120223637Sbz struct ifnet *ifp = &sc->sc_if; 2121223637Sbz#endif 2122224936Spluknet#endif 2123126258Smlaier struct mbuf *m; 2124223637Sbz struct ip *ip; 2125223637Sbz struct pfsync_header *ph; 2126223637Sbz struct pfsync_subheader *subh; 2127223637Sbz struct pf_state *st; 2128223637Sbz struct pfsync_upd_req_item *ur; 2129223637Sbz#ifdef notyet 2130223637Sbz struct tdb *t; 2131223637Sbz#endif 2132223637Sbz int offset; 2133223637Sbz int q, count = 0; 2134126258Smlaier 2135223637Sbz#ifdef __FreeBSD__ 2136226535Sbz PF_LOCK_ASSERT(); 2137223637Sbz#else 2138223637Sbz splassert(IPL_NET); 2139223637Sbz#endif 2140223637Sbz 2141223637Sbz if (sc == NULL || sc->sc_len == PFSYNC_MINPKT) 2142223637Sbz return; 2143223637Sbz 2144223637Sbz#if NBPFILTER > 0 2145223637Sbz if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { 2146223637Sbz#else 2147223637Sbz if (sc->sc_sync_if == NULL) { 2148223637Sbz#endif 2149223637Sbz pfsync_drop(sc); 2150223637Sbz return; 2151223637Sbz } 2152223637Sbz 2153230265Sglebius#ifdef __FreeBSD__ 2154230265Sglebius m = m_get2(M_NOWAIT, MT_DATA, M_PKTHDR, max_linkhdr + sc->sc_len); 2155126258Smlaier if (m == NULL) { 2156171168Smlaier sc->sc_ifp->if_oerrors++; 2157230265Sglebius V_pfsyncstats.pfsyncs_onomem++; 2158230265Sglebius return; 2159230265Sglebius } 2160141584Smlaier#else 2161230265Sglebius MGETHDR(m, M_DONTWAIT, MT_DATA); 2162230265Sglebius if (m == NULL) { 2163126258Smlaier sc->sc_if.if_oerrors++; 2164230265Sglebius pfsyncstats.pfsyncs_onomem++; 2165223637Sbz pfsync_drop(sc); 2166223637Sbz return; 2167126258Smlaier } 2168126258Smlaier 2169223637Sbz if (max_linkhdr + sc->sc_len > MHLEN) { 2170223637Sbz MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len); 2171223637Sbz if (!ISSET(m->m_flags, M_EXT)) { 2172126258Smlaier m_free(m); 2173126258Smlaier sc->sc_if.if_oerrors++; 2174230265Sglebius pfsyncstats.pfsyncs_onomem++; 2175223637Sbz pfsync_drop(sc); 2176223637Sbz return; 2177126258Smlaier } 2178223637Sbz } 2179230265Sglebius#endif 2180223637Sbz m->m_data += max_linkhdr; 2181223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 2182130613Smlaier 2183223637Sbz /* build the ip header */ 2184223637Sbz ip = (struct ip *)m->m_data; 2185223637Sbz bcopy(&sc->sc_template, ip, sizeof(*ip)); 2186223637Sbz offset = sizeof(*ip); 2187126258Smlaier 2188226609Sglebius#ifdef __FreeBSD__ 2189226609Sglebius ip->ip_len = m->m_pkthdr.len; 2190226609Sglebius#else 2191223637Sbz ip->ip_len = htons(m->m_pkthdr.len); 2192226609Sglebius#endif 2193223637Sbz ip->ip_id = htons(ip_randomid()); 2194126258Smlaier 2195223637Sbz /* build the pfsync header */ 2196223637Sbz ph = (struct pfsync_header *)(m->m_data + offset); 2197223637Sbz bzero(ph, sizeof(*ph)); 2198223637Sbz offset += sizeof(*ph); 2199126258Smlaier 2200223637Sbz ph->version = PFSYNC_VERSION; 2201223637Sbz ph->len = htons(sc->sc_len - sizeof(*ip)); 2202130613Smlaier#ifdef __FreeBSD__ 2203223637Sbz bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2204171168Smlaier#else 2205223637Sbz bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2206130613Smlaier#endif 2207171168Smlaier 2208223637Sbz /* walk the queues */ 2209223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 2210223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2211223637Sbz continue; 2212223637Sbz 2213223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2214223637Sbz offset += sizeof(*subh); 2215223637Sbz 2216223637Sbz count = 0; 2217223637Sbz TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2218223637Sbz#ifdef PFSYNC_DEBUG 2219159603Smlaier#ifdef __FreeBSD__ 2220223637Sbz KASSERT(st->sync_state == q, 2221223637Sbz ("%s: st->sync_state == q", 2222223637Sbz __FUNCTION__)); 2223159603Smlaier#else 2224223637Sbz KASSERT(st->sync_state == q); 2225159603Smlaier#endif 2226223637Sbz#endif 2227130613Smlaier 2228223637Sbz offset += pfsync_qs[q].write(st, m, offset); 2229223637Sbz st->sync_state = PFSYNC_S_NONE; 2230223637Sbz count++; 2231126258Smlaier } 2232223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 2233130613Smlaier 2234223637Sbz bzero(subh, sizeof(*subh)); 2235223637Sbz subh->action = pfsync_qs[q].action; 2236223637Sbz subh->count = htons(count); 2237126258Smlaier } 2238126258Smlaier 2239223637Sbz if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { 2240223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2241223637Sbz offset += sizeof(*subh); 2242126258Smlaier 2243223637Sbz count = 0; 2244223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2245223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2246130613Smlaier 2247223637Sbz bcopy(&ur->ur_msg, m->m_data + offset, 2248223637Sbz sizeof(ur->ur_msg)); 2249223637Sbz offset += sizeof(ur->ur_msg); 2250130613Smlaier 2251223637Sbz pool_put(&sc->sc_pool, ur); 2252130613Smlaier 2253223637Sbz count++; 2254223637Sbz } 2255130613Smlaier 2256223637Sbz bzero(subh, sizeof(*subh)); 2257223637Sbz subh->action = PFSYNC_ACT_UPD_REQ; 2258223637Sbz subh->count = htons(count); 2259223637Sbz } 2260130613Smlaier 2261223637Sbz /* has someone built a custom region for us to add? */ 2262223637Sbz if (sc->sc_plus != NULL) { 2263223637Sbz bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); 2264223637Sbz offset += sc->sc_pluslen; 2265130613Smlaier 2266223637Sbz sc->sc_plus = NULL; 2267130613Smlaier } 2268130613Smlaier 2269223637Sbz#ifdef notyet 2270223637Sbz if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2271223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2272223637Sbz offset += sizeof(*subh); 2273126258Smlaier 2274223637Sbz count = 0; 2275223637Sbz TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) { 2276223637Sbz offset += pfsync_out_tdb(t, m, offset); 2277223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2278126258Smlaier 2279223637Sbz count++; 2280130613Smlaier } 2281223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 2282223637Sbz 2283223637Sbz bzero(subh, sizeof(*subh)); 2284223637Sbz subh->action = PFSYNC_ACT_TDB; 2285223637Sbz subh->count = htons(count); 2286130613Smlaier } 2287223637Sbz#endif 2288130613Smlaier 2289223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2290223637Sbz offset += sizeof(*subh); 2291130613Smlaier 2292223637Sbz bzero(subh, sizeof(*subh)); 2293223637Sbz subh->action = PFSYNC_ACT_EOF; 2294223637Sbz subh->count = htons(1); 2295130613Smlaier 2296223637Sbz /* XXX write checksum in EOF here */ 2297130613Smlaier 2298223637Sbz /* we're done, let's put it on the wire */ 2299223637Sbz#if NBPFILTER > 0 2300223637Sbz if (ifp->if_bpf) { 2301223637Sbz m->m_data += sizeof(*ip); 2302223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); 2303223637Sbz#ifdef __FreeBSD__ 2304223637Sbz BPF_MTAP(ifp, m); 2305223637Sbz#else 2306223637Sbz bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 2307223637Sbz#endif 2308223637Sbz m->m_data -= sizeof(*ip); 2309223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 2310130613Smlaier } 2311130613Smlaier 2312223637Sbz if (sc->sc_sync_if == NULL) { 2313223637Sbz sc->sc_len = PFSYNC_MINPKT; 2314223637Sbz m_freem(m); 2315223637Sbz return; 2316223637Sbz } 2317223637Sbz#endif 2318126258Smlaier 2319223637Sbz#ifdef __FreeBSD__ 2320223637Sbz sc->sc_ifp->if_opackets++; 2321223637Sbz sc->sc_ifp->if_obytes += m->m_pkthdr.len; 2322226660Sglebius sc->sc_len = PFSYNC_MINPKT; 2323226660Sglebius 2324229976Sglebius if (!_IF_QFULL(&sc->sc_ifp->if_snd)) 2325229976Sglebius _IF_ENQUEUE(&sc->sc_ifp->if_snd, m); 2326229976Sglebius else { 2327229976Sglebius m_freem(m); 2328229976Sglebius sc->sc_ifp->if_snd.ifq_drops++; 2329229976Sglebius } 2330229976Sglebius if (schedswi) 2331229976Sglebius swi_sched(V_pfsync_swi_cookie, 0); 2332223637Sbz#else 2333223637Sbz sc->sc_if.if_opackets++; 2334223637Sbz sc->sc_if.if_obytes += m->m_pkthdr.len; 2335223637Sbz 2336223637Sbz if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0) 2337226660Sglebius pfsyncstats.pfsyncs_opackets++; 2338223637Sbz else 2339226660Sglebius pfsyncstats.pfsyncs_oerrors++; 2340226660Sglebius 2341226660Sglebius /* start again */ 2342226660Sglebius sc->sc_len = PFSYNC_MINPKT; 2343223637Sbz#endif 2344126258Smlaier} 2345126258Smlaier 2346223637Sbzvoid 2347223637Sbzpfsync_insert_state(struct pf_state *st) 2348126258Smlaier{ 2349223637Sbz#ifdef __FreeBSD__ 2350223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2351223637Sbz#else 2352171168Smlaier struct pfsync_softc *sc = pfsyncif; 2353223637Sbz#endif 2354130613Smlaier 2355130613Smlaier#ifdef __FreeBSD__ 2356226535Sbz PF_LOCK_ASSERT(); 2357171168Smlaier#else 2358223637Sbz splassert(IPL_SOFTNET); 2359126261Smlaier#endif 2360130613Smlaier 2361223637Sbz if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) || 2362223637Sbz st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 2363223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 2364223637Sbz return; 2365130613Smlaier } 2366130613Smlaier 2367223637Sbz if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC)) 2368223637Sbz return; 2369130613Smlaier 2370223637Sbz#ifdef PFSYNC_DEBUG 2371223637Sbz#ifdef __FreeBSD__ 2372223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 2373223637Sbz ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2374223637Sbz#else 2375223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE); 2376223637Sbz#endif 2377223637Sbz#endif 2378223637Sbz 2379223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2380223637Sbz#ifdef __FreeBSD__ 2381223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2382223637Sbz V_pfsyncif); 2383223637Sbz#else 2384223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2385223637Sbz#endif 2386223637Sbz 2387223637Sbz pfsync_q_ins(st, PFSYNC_S_INS); 2388223637Sbz 2389233846Sglebius st->sync_updates = 0; 2390130613Smlaier} 2391130613Smlaier 2392223637Sbzint defer = 10; 2393223637Sbz 2394130613Smlaierint 2395223637Sbzpfsync_defer(struct pf_state *st, struct mbuf *m) 2396130613Smlaier{ 2397223637Sbz#ifdef __FreeBSD__ 2398223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2399223637Sbz#else 2400171168Smlaier struct pfsync_softc *sc = pfsyncif; 2401223637Sbz#endif 2402223637Sbz struct pfsync_deferral *pd; 2403126258Smlaier 2404223637Sbz#ifdef __FreeBSD__ 2405226535Sbz PF_LOCK_ASSERT(); 2406223637Sbz#else 2407223637Sbz splassert(IPL_SOFTNET); 2408223637Sbz#endif 2409223637Sbz 2410233846Sglebius if (!sc->sc_defer || m->m_flags & (M_BCAST|M_MCAST)) 2411233846Sglebius return (0); 2412233846Sglebius 2413223637Sbz if (sc->sc_deferred >= 128) 2414223637Sbz pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 2415223637Sbz 2416223637Sbz pd = pool_get(&sc->sc_pool, M_NOWAIT); 2417223637Sbz if (pd == NULL) 2418171168Smlaier return (0); 2419223637Sbz sc->sc_deferred++; 2420171168Smlaier 2421130613Smlaier#ifdef __FreeBSD__ 2422223637Sbz m->m_flags |= M_SKIP_FIREWALL; 2423171168Smlaier#else 2424223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2425171168Smlaier#endif 2426223637Sbz SET(st->state_flags, PFSTATE_ACK); 2427223637Sbz 2428223637Sbz pd->pd_st = st; 2429223637Sbz pd->pd_m = m; 2430223637Sbz 2431223637Sbz TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); 2432171168Smlaier#ifdef __FreeBSD__ 2433223637Sbz callout_init(&pd->pd_tmo, CALLOUT_MPSAFE); 2434223637Sbz callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo, 2435223637Sbz pd); 2436223637Sbz#else 2437223637Sbz timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd); 2438223637Sbz timeout_add(&pd->pd_tmo, defer); 2439130613Smlaier#endif 2440126258Smlaier 2441233846Sglebius swi_sched(V_pfsync_swi_cookie, 0); 2442233846Sglebius 2443223637Sbz return (1); 2444126258Smlaier} 2445126258Smlaier 2446126258Smlaiervoid 2447223637Sbzpfsync_undefer(struct pfsync_deferral *pd, int drop) 2448126258Smlaier{ 2449223637Sbz#ifdef __FreeBSD__ 2450223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2451223637Sbz#else 2452223637Sbz struct pfsync_softc *sc = pfsyncif; 2453223637Sbz#endif 2454126258Smlaier int s; 2455126258Smlaier 2456130613Smlaier#ifdef __FreeBSD__ 2457226535Sbz PF_LOCK_ASSERT(); 2458223637Sbz#else 2459223637Sbz splassert(IPL_SOFTNET); 2460130613Smlaier#endif 2461223637Sbz 2462223637Sbz TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 2463223637Sbz sc->sc_deferred--; 2464223637Sbz 2465223637Sbz CLR(pd->pd_st->state_flags, PFSTATE_ACK); 2466223637Sbz timeout_del(&pd->pd_tmo); /* bah */ 2467223637Sbz if (drop) 2468223637Sbz m_freem(pd->pd_m); 2469223637Sbz else { 2470223637Sbz s = splnet(); 2471130613Smlaier#ifdef __FreeBSD__ 2472223637Sbz /* XXX: use pf_defered?! */ 2473223637Sbz PF_UNLOCK(); 2474130613Smlaier#endif 2475223637Sbz ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0, 2476223637Sbz (void *)NULL, (void *)NULL); 2477223637Sbz#ifdef __FreeBSD__ 2478223637Sbz PF_LOCK(); 2479223637Sbz#endif 2480223637Sbz splx(s); 2481223637Sbz } 2482223637Sbz 2483223637Sbz pool_put(&sc->sc_pool, pd); 2484126258Smlaier} 2485126258Smlaier 2486171168Smlaiervoid 2487223637Sbzpfsync_defer_tmo(void *arg) 2488171168Smlaier{ 2489223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE) 2490223637Sbz struct pfsync_deferral *pd = arg; 2491223637Sbz#endif 2492171168Smlaier int s; 2493171168Smlaier 2494223637Sbz s = splsoftnet(); 2495171168Smlaier#ifdef __FreeBSD__ 2496223637Sbz CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */ 2497171168Smlaier PF_LOCK(); 2498171168Smlaier#endif 2499223637Sbz pfsync_undefer(arg, 0); 2500171168Smlaier#ifdef __FreeBSD__ 2501171168Smlaier PF_UNLOCK(); 2502223637Sbz CURVNET_RESTORE(); 2503171168Smlaier#endif 2504171168Smlaier splx(s); 2505171168Smlaier} 2506223637Sbz 2507223637Sbzvoid 2508223637Sbzpfsync_deferred(struct pf_state *st, int drop) 2509223637Sbz{ 2510223637Sbz#ifdef __FreeBSD__ 2511223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2512223637Sbz#else 2513223637Sbz struct pfsync_softc *sc = pfsyncif; 2514171168Smlaier#endif 2515223637Sbz struct pfsync_deferral *pd; 2516171168Smlaier 2517223637Sbz TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { 2518223637Sbz if (pd->pd_st == st) { 2519223637Sbz pfsync_undefer(pd, drop); 2520223637Sbz return; 2521223637Sbz } 2522223637Sbz } 2523223637Sbz 2524223637Sbz panic("pfsync_send_deferred: unable to find deferred state"); 2525223637Sbz} 2526223637Sbz 2527223637Sbzu_int pfsync_upds = 0; 2528223637Sbz 2529130613Smlaiervoid 2530223637Sbzpfsync_update_state(struct pf_state *st) 2531130613Smlaier{ 2532223637Sbz#ifdef __FreeBSD__ 2533223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2534223637Sbz#else 2535223637Sbz struct pfsync_softc *sc = pfsyncif; 2536223637Sbz#endif 2537223637Sbz int sync = 0; 2538130613Smlaier 2539130613Smlaier#ifdef __FreeBSD__ 2540226535Sbz PF_LOCK_ASSERT(); 2541223637Sbz#else 2542223637Sbz splassert(IPL_SOFTNET); 2543130613Smlaier#endif 2544130613Smlaier 2545223637Sbz if (sc == NULL) 2546223637Sbz return; 2547223637Sbz 2548223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2549223637Sbz pfsync_deferred(st, 0); 2550223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2551223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2552223637Sbz pfsync_q_del(st); 2553223637Sbz return; 2554130613Smlaier } 2555223637Sbz 2556223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2557223637Sbz#ifdef __FreeBSD__ 2558223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2559223637Sbz V_pfsyncif); 2560223637Sbz#else 2561223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2562223637Sbz#endif 2563223637Sbz 2564223637Sbz switch (st->sync_state) { 2565223637Sbz case PFSYNC_S_UPD_C: 2566223637Sbz case PFSYNC_S_UPD: 2567223637Sbz case PFSYNC_S_INS: 2568223637Sbz /* we're already handling it */ 2569223637Sbz 2570228816Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) { 2571228816Sglebius st->sync_updates++; 2572228816Sglebius if (st->sync_updates >= sc->sc_maxupdates) 2573228816Sglebius sync = 1; 2574228816Sglebius } 2575223637Sbz break; 2576223637Sbz 2577223637Sbz case PFSYNC_S_IACK: 2578223637Sbz pfsync_q_del(st); 2579223637Sbz case PFSYNC_S_NONE: 2580223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD_C); 2581223637Sbz st->sync_updates = 0; 2582223637Sbz break; 2583223637Sbz 2584223637Sbz default: 2585223637Sbz panic("pfsync_update_state: unexpected sync state %d", 2586223637Sbz st->sync_state); 2587223637Sbz } 2588223637Sbz 2589228815Sglebius if (sync || (time_uptime - st->pfsync_time) < 2) { 2590223637Sbz pfsync_upds++; 2591223637Sbz schednetisr(NETISR_PFSYNC); 2592223637Sbz } 2593130613Smlaier} 2594130613Smlaier 2595130613Smlaiervoid 2596223637Sbzpfsync_request_update(u_int32_t creatorid, u_int64_t id) 2597130613Smlaier{ 2598130613Smlaier#ifdef __FreeBSD__ 2599223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2600223637Sbz#else 2601223637Sbz struct pfsync_softc *sc = pfsyncif; 2602130613Smlaier#endif 2603223637Sbz struct pfsync_upd_req_item *item; 2604223637Sbz size_t nlen = sizeof(struct pfsync_upd_req); 2605223637Sbz int s; 2606130613Smlaier 2607226544Sbz PF_LOCK_ASSERT(); 2608226544Sbz 2609130613Smlaier /* 2610223637Sbz * this code does nothing to prevent multiple update requests for the 2611223637Sbz * same state being generated. 2612130613Smlaier */ 2613130613Smlaier 2614223637Sbz item = pool_get(&sc->sc_pool, PR_NOWAIT); 2615223637Sbz if (item == NULL) { 2616223637Sbz /* XXX stats */ 2617223637Sbz return; 2618223637Sbz } 2619171168Smlaier 2620223637Sbz item->ur_msg.id = id; 2621223637Sbz item->ur_msg.creatorid = creatorid; 2622171168Smlaier 2623223637Sbz if (TAILQ_EMPTY(&sc->sc_upd_req_list)) 2624223637Sbz nlen += sizeof(struct pfsync_subheader); 2625223637Sbz 2626130613Smlaier#ifdef __FreeBSD__ 2627229777Sglebius if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2628130613Smlaier#else 2629223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2630130613Smlaier#endif 2631223637Sbz s = splnet(); 2632223637Sbz pfsync_sendout(); 2633223637Sbz splx(s); 2634223637Sbz 2635223637Sbz nlen = sizeof(struct pfsync_subheader) + 2636223637Sbz sizeof(struct pfsync_upd_req); 2637130613Smlaier } 2638223637Sbz 2639223637Sbz TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); 2640223637Sbz sc->sc_len += nlen; 2641223637Sbz 2642223637Sbz schednetisr(NETISR_PFSYNC); 2643223637Sbz} 2644223637Sbz 2645223637Sbzvoid 2646223637Sbzpfsync_update_state_req(struct pf_state *st) 2647223637Sbz{ 2648130613Smlaier#ifdef __FreeBSD__ 2649223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2650223637Sbz#else 2651223637Sbz struct pfsync_softc *sc = pfsyncif; 2652130613Smlaier#endif 2653223637Sbz 2654226544Sbz PF_LOCK_ASSERT(); 2655226544Sbz 2656223637Sbz if (sc == NULL) 2657223637Sbz panic("pfsync_update_state_req: nonexistant instance"); 2658223637Sbz 2659223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2660223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2661223637Sbz pfsync_q_del(st); 2662223637Sbz return; 2663223637Sbz } 2664223637Sbz 2665223637Sbz switch (st->sync_state) { 2666223637Sbz case PFSYNC_S_UPD_C: 2667223637Sbz case PFSYNC_S_IACK: 2668223637Sbz pfsync_q_del(st); 2669223637Sbz case PFSYNC_S_NONE: 2670223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD); 2671223637Sbz schednetisr(NETISR_PFSYNC); 2672223637Sbz return; 2673223637Sbz 2674223637Sbz case PFSYNC_S_INS: 2675223637Sbz case PFSYNC_S_UPD: 2676223637Sbz case PFSYNC_S_DEL: 2677223637Sbz /* we're already handling it */ 2678223637Sbz return; 2679223637Sbz 2680223637Sbz default: 2681223637Sbz panic("pfsync_update_state_req: unexpected sync state %d", 2682223637Sbz st->sync_state); 2683223637Sbz } 2684130613Smlaier} 2685130613Smlaier 2686130613Smlaiervoid 2687223637Sbzpfsync_delete_state(struct pf_state *st) 2688130613Smlaier{ 2689130613Smlaier#ifdef __FreeBSD__ 2690223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2691223637Sbz#else 2692223637Sbz struct pfsync_softc *sc = pfsyncif; 2693130613Smlaier#endif 2694223637Sbz 2695130613Smlaier#ifdef __FreeBSD__ 2696226535Sbz PF_LOCK_ASSERT(); 2697130613Smlaier#else 2698223637Sbz splassert(IPL_SOFTNET); 2699130613Smlaier#endif 2700223637Sbz 2701223637Sbz if (sc == NULL) 2702223637Sbz return; 2703223637Sbz 2704223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2705223637Sbz pfsync_deferred(st, 1); 2706223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2707223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2708223637Sbz pfsync_q_del(st); 2709223637Sbz return; 2710223637Sbz } 2711223637Sbz 2712223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2713171168Smlaier#ifdef __FreeBSD__ 2714223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2715223637Sbz V_pfsyncif); 2716171168Smlaier#else 2717223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2718171168Smlaier#endif 2719223637Sbz 2720223637Sbz switch (st->sync_state) { 2721223637Sbz case PFSYNC_S_INS: 2722223637Sbz /* we never got to tell the world so just forget about it */ 2723223637Sbz pfsync_q_del(st); 2724223637Sbz return; 2725223637Sbz 2726223637Sbz case PFSYNC_S_UPD_C: 2727223637Sbz case PFSYNC_S_UPD: 2728223637Sbz case PFSYNC_S_IACK: 2729223637Sbz pfsync_q_del(st); 2730223637Sbz /* FALLTHROUGH to putting it on the del list */ 2731223637Sbz 2732223637Sbz case PFSYNC_S_NONE: 2733223637Sbz pfsync_q_ins(st, PFSYNC_S_DEL); 2734223637Sbz return; 2735223637Sbz 2736223637Sbz default: 2737223637Sbz panic("pfsync_delete_state: unexpected sync state %d", 2738223637Sbz st->sync_state); 2739130613Smlaier } 2740223637Sbz} 2741223637Sbz 2742223637Sbzvoid 2743223637Sbzpfsync_clear_states(u_int32_t creatorid, const char *ifname) 2744223637Sbz{ 2745223637Sbz struct { 2746223637Sbz struct pfsync_subheader subh; 2747223637Sbz struct pfsync_clr clr; 2748223637Sbz } __packed r; 2749223637Sbz 2750130613Smlaier#ifdef __FreeBSD__ 2751223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2752223637Sbz#else 2753223637Sbz struct pfsync_softc *sc = pfsyncif; 2754130613Smlaier#endif 2755223637Sbz 2756223637Sbz#ifdef __FreeBSD__ 2757226535Sbz PF_LOCK_ASSERT(); 2758223637Sbz#else 2759223637Sbz splassert(IPL_SOFTNET); 2760223637Sbz#endif 2761223637Sbz 2762223637Sbz if (sc == NULL) 2763223637Sbz return; 2764223637Sbz 2765223637Sbz bzero(&r, sizeof(r)); 2766223637Sbz 2767223637Sbz r.subh.action = PFSYNC_ACT_CLR; 2768223637Sbz r.subh.count = htons(1); 2769223637Sbz 2770223637Sbz strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 2771223637Sbz r.clr.creatorid = creatorid; 2772223637Sbz 2773223637Sbz pfsync_send_plus(&r, sizeof(r)); 2774130613Smlaier} 2775130613Smlaier 2776223637Sbzvoid 2777223637Sbzpfsync_q_ins(struct pf_state *st, int q) 2778126258Smlaier{ 2779171168Smlaier#ifdef __FreeBSD__ 2780223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2781171168Smlaier#else 2782223637Sbz struct pfsync_softc *sc = pfsyncif; 2783138666Smlaier#endif 2784223637Sbz size_t nlen = pfsync_qs[q].len; 2785223637Sbz int s; 2786223637Sbz 2787226544Sbz PF_LOCK_ASSERT(); 2788226544Sbz 2789223637Sbz#ifdef __FreeBSD__ 2790223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 2791223637Sbz ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2792223637Sbz#else 2793223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE); 2794171168Smlaier#endif 2795126258Smlaier 2796223637Sbz#if 1 || defined(PFSYNC_DEBUG) 2797223637Sbz if (sc->sc_len < PFSYNC_MINPKT) 2798127145Smlaier#ifdef __FreeBSD__ 2799223637Sbz panic("pfsync pkt len is too low %zu", sc->sc_len); 2800223637Sbz#else 2801223637Sbz panic("pfsync pkt len is too low %d", sc->sc_len); 2802171168Smlaier#endif 2803223637Sbz#endif 2804223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2805223637Sbz nlen += sizeof(struct pfsync_subheader); 2806130613Smlaier 2807165632Sjhb#ifdef __FreeBSD__ 2808223637Sbz if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2809165632Sjhb#else 2810223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2811126258Smlaier#endif 2812223637Sbz s = splnet(); 2813223637Sbz pfsync_sendout(); 2814223637Sbz splx(s); 2815126258Smlaier 2816223637Sbz nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 2817130613Smlaier } 2818126258Smlaier 2819223637Sbz sc->sc_len += nlen; 2820223637Sbz TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); 2821223637Sbz st->sync_state = q; 2822171168Smlaier} 2823171168Smlaier 2824223637Sbzvoid 2825223637Sbzpfsync_q_del(struct pf_state *st) 2826171168Smlaier{ 2827159603Smlaier#ifdef __FreeBSD__ 2828223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2829171168Smlaier#else 2830223637Sbz struct pfsync_softc *sc = pfsyncif; 2831171168Smlaier#endif 2832223637Sbz int q = st->sync_state; 2833171168Smlaier 2834171168Smlaier#ifdef __FreeBSD__ 2835229964Sglebius KASSERT(st->sync_state != PFSYNC_S_NONE, 2836223637Sbz ("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__)); 2837223637Sbz#else 2838223637Sbz KASSERT(st->sync_state != PFSYNC_S_NONE); 2839171168Smlaier#endif 2840171168Smlaier 2841223637Sbz sc->sc_len -= pfsync_qs[q].len; 2842223637Sbz TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); 2843223637Sbz st->sync_state = PFSYNC_S_NONE; 2844171168Smlaier 2845223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2846223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2847223637Sbz} 2848223637Sbz 2849223637Sbz#ifdef notyet 2850223637Sbzvoid 2851223637Sbzpfsync_update_tdb(struct tdb *t, int output) 2852223637Sbz{ 2853171168Smlaier#ifdef __FreeBSD__ 2854223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2855171168Smlaier#else 2856223637Sbz struct pfsync_softc *sc = pfsyncif; 2857171168Smlaier#endif 2858223637Sbz size_t nlen = sizeof(struct pfsync_tdb); 2859223637Sbz int s; 2860171168Smlaier 2861223637Sbz if (sc == NULL) 2862223637Sbz return; 2863223637Sbz 2864223637Sbz if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) { 2865223637Sbz if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2866223637Sbz nlen += sizeof(struct pfsync_subheader); 2867223637Sbz 2868223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2869223637Sbz s = splnet(); 2870226544Sbz PF_LOCK(); 2871223637Sbz pfsync_sendout(); 2872226544Sbz PF_UNLOCK(); 2873223637Sbz splx(s); 2874223637Sbz 2875223637Sbz nlen = sizeof(struct pfsync_subheader) + 2876223637Sbz sizeof(struct pfsync_tdb); 2877223637Sbz } 2878223637Sbz 2879223637Sbz sc->sc_len += nlen; 2880223637Sbz TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry); 2881223637Sbz SET(t->tdb_flags, TDBF_PFSYNC); 2882223637Sbz t->tdb_updates = 0; 2883223637Sbz } else { 2884223637Sbz if (++t->tdb_updates >= sc->sc_maxupdates) 2885223637Sbz schednetisr(NETISR_PFSYNC); 2886223637Sbz } 2887223637Sbz 2888223637Sbz if (output) 2889223637Sbz SET(t->tdb_flags, TDBF_PFSYNC_RPL); 2890223637Sbz else 2891223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC_RPL); 2892171168Smlaier} 2893223637Sbz 2894223637Sbzvoid 2895223637Sbzpfsync_delete_tdb(struct tdb *t) 2896223637Sbz{ 2897223637Sbz#ifdef __FreeBSD__ 2898223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2899223637Sbz#else 2900223637Sbz struct pfsync_softc *sc = pfsyncif; 2901171168Smlaier#endif 2902171168Smlaier 2903223637Sbz if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC)) 2904223637Sbz return; 2905223637Sbz 2906223637Sbz sc->sc_len -= sizeof(struct pfsync_tdb); 2907223637Sbz TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry); 2908223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2909223637Sbz 2910223637Sbz if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2911223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2912223637Sbz} 2913223637Sbz 2914171168Smlaierint 2915223637Sbzpfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset) 2916171168Smlaier{ 2917223637Sbz struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset); 2918171168Smlaier 2919223637Sbz bzero(ut, sizeof(*ut)); 2920223637Sbz ut->spi = t->tdb_spi; 2921223637Sbz bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst)); 2922223637Sbz /* 2923223637Sbz * When a failover happens, the master's rpl is probably above 2924223637Sbz * what we see here (we may be up to a second late), so 2925223637Sbz * increase it a bit for outbound tdbs to manage most such 2926223637Sbz * situations. 2927223637Sbz * 2928223637Sbz * For now, just add an offset that is likely to be larger 2929223637Sbz * than the number of packets we can see in one second. The RFC 2930223637Sbz * just says the next packet must have a higher seq value. 2931223637Sbz * 2932223637Sbz * XXX What is a good algorithm for this? We could use 2933223637Sbz * a rate-determined increase, but to know it, we would have 2934223637Sbz * to extend struct tdb. 2935223637Sbz * XXX pt->rpl can wrap over MAXINT, but if so the real tdb 2936223637Sbz * will soon be replaced anyway. For now, just don't handle 2937223637Sbz * this edge case. 2938223637Sbz */ 2939223637Sbz#define RPL_INCR 16384 2940223637Sbz ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ? 2941223637Sbz RPL_INCR : 0)); 2942223637Sbz ut->cur_bytes = htobe64(t->tdb_cur_bytes); 2943223637Sbz ut->sproto = t->tdb_sproto; 2944223637Sbz 2945223637Sbz return (sizeof(*ut)); 2946223637Sbz} 2947223637Sbz#endif 2948223637Sbz 2949223637Sbzvoid 2950223637Sbzpfsync_bulk_start(void) 2951223637Sbz{ 2952171168Smlaier#ifdef __FreeBSD__ 2953223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2954223637Sbz#else 2955223637Sbz struct pfsync_softc *sc = pfsyncif; 2956171168Smlaier#endif 2957223637Sbz 2958171168Smlaier#ifdef __FreeBSD__ 2959226663Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 2960159603Smlaier#else 2961226663Sglebius if (pf_status.debug >= PF_DEBUG_MISC) 2962159603Smlaier#endif 2963226663Sglebius printf("pfsync: received bulk update request\n"); 2964223637Sbz 2965223637Sbz#ifdef __FreeBSD__ 2966229963Sglebius PF_LOCK_ASSERT(); 2967226663Sglebius if (TAILQ_EMPTY(&V_state_list)) 2968223637Sbz#else 2969226663Sglebius if (TAILQ_EMPTY(&state_list)) 2970223637Sbz#endif 2971226663Sglebius pfsync_bulk_status(PFSYNC_BUS_END); 2972226663Sglebius else { 2973226663Sglebius sc->sc_ureq_received = time_uptime; 2974226663Sglebius if (sc->sc_bulk_next == NULL) 2975226663Sglebius#ifdef __FreeBSD__ 2976226663Sglebius sc->sc_bulk_next = TAILQ_FIRST(&V_state_list); 2977226663Sglebius#else 2978226663Sglebius sc->sc_bulk_next = TAILQ_FIRST(&state_list); 2979226663Sglebius#endif 2980229773Sglebius sc->sc_bulk_last = sc->sc_bulk_next; 2981223637Sbz 2982229773Sglebius pfsync_bulk_status(PFSYNC_BUS_START); 2983229773Sglebius callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, sc); 2984226663Sglebius } 2985223637Sbz} 2986223637Sbz 2987223637Sbzvoid 2988223637Sbzpfsync_bulk_update(void *arg) 2989223637Sbz{ 2990223637Sbz struct pfsync_softc *sc = arg; 2991223637Sbz struct pf_state *st = sc->sc_bulk_next; 2992223637Sbz int i = 0; 2993223637Sbz int s; 2994223637Sbz 2995226544Sbz PF_LOCK_ASSERT(); 2996226544Sbz 2997223637Sbz s = splsoftnet(); 2998223637Sbz#ifdef __FreeBSD__ 2999223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3000223637Sbz#endif 3001226663Sglebius for (;;) { 3002223637Sbz if (st->sync_state == PFSYNC_S_NONE && 3003223637Sbz st->timeout < PFTM_MAX && 3004223637Sbz st->pfsync_time <= sc->sc_ureq_received) { 3005223637Sbz pfsync_update_state_req(st); 3006223637Sbz i++; 3007130613Smlaier } 3008223637Sbz 3009223637Sbz st = TAILQ_NEXT(st, entry_list); 3010223637Sbz if (st == NULL) 3011130613Smlaier#ifdef __FreeBSD__ 3012223637Sbz st = TAILQ_FIRST(&V_state_list); 3013130613Smlaier#else 3014223637Sbz st = TAILQ_FIRST(&state_list); 3015130613Smlaier#endif 3016223637Sbz 3017226663Sglebius if (st == sc->sc_bulk_last) { 3018226663Sglebius /* we're done */ 3019226663Sglebius sc->sc_bulk_next = NULL; 3020226663Sglebius sc->sc_bulk_last = NULL; 3021226663Sglebius pfsync_bulk_status(PFSYNC_BUS_END); 3022226663Sglebius break; 3023226663Sglebius } 3024226663Sglebius 3025226663Sglebius#ifdef __FreeBSD__ 3026226663Sglebius if (i > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) < 3027226663Sglebius#else 3028226663Sglebius if (i > 1 && (sc->sc_if.if_mtu - sc->sc_len) < 3029226663Sglebius#endif 3030226663Sglebius sizeof(struct pfsync_state)) { 3031226663Sglebius /* we've filled a packet */ 3032223637Sbz sc->sc_bulk_next = st; 3033130613Smlaier#ifdef __FreeBSD__ 3034223637Sbz callout_reset(&sc->sc_bulk_tmo, 1, 3035226661Sglebius pfsync_bulk_update, sc); 3036130613Smlaier#else 3037223637Sbz timeout_add(&sc->sc_bulk_tmo, 1); 3038130613Smlaier#endif 3039226663Sglebius break; 3040223637Sbz } 3041226663Sglebius } 3042130613Smlaier 3043130613Smlaier#ifdef __FreeBSD__ 3044223637Sbz CURVNET_RESTORE(); 3045223637Sbz#endif 3046223637Sbz splx(s); 3047223637Sbz} 3048223637Sbz 3049223637Sbzvoid 3050223637Sbzpfsync_bulk_status(u_int8_t status) 3051223637Sbz{ 3052223637Sbz struct { 3053223637Sbz struct pfsync_subheader subh; 3054223637Sbz struct pfsync_bus bus; 3055223637Sbz } __packed r; 3056223637Sbz 3057223637Sbz#ifdef __FreeBSD__ 3058223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3059130613Smlaier#else 3060223637Sbz struct pfsync_softc *sc = pfsyncif; 3061130613Smlaier#endif 3062130613Smlaier 3063226544Sbz PF_LOCK_ASSERT(); 3064226544Sbz 3065223637Sbz bzero(&r, sizeof(r)); 3066171168Smlaier 3067223637Sbz r.subh.action = PFSYNC_ACT_BUS; 3068223637Sbz r.subh.count = htons(1); 3069223637Sbz 3070130613Smlaier#ifdef __FreeBSD__ 3071223637Sbz r.bus.creatorid = V_pf_status.hostid; 3072147261Smlaier#else 3073223637Sbz r.bus.creatorid = pf_status.hostid; 3074130613Smlaier#endif 3075223637Sbz r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 3076223637Sbz r.bus.status = status; 3077130613Smlaier 3078223637Sbz pfsync_send_plus(&r, sizeof(r)); 3079126258Smlaier} 3080126261Smlaier 3081171168Smlaiervoid 3082223637Sbzpfsync_bulk_fail(void *arg) 3083171168Smlaier{ 3084223637Sbz struct pfsync_softc *sc = arg; 3085171168Smlaier 3086223637Sbz#ifdef __FreeBSD__ 3087223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3088223637Sbz#endif 3089171168Smlaier 3090223637Sbz if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 3091223637Sbz /* Try again */ 3092223637Sbz#ifdef __FreeBSD__ 3093223637Sbz callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 3094223637Sbz pfsync_bulk_fail, V_pfsyncif); 3095223637Sbz#else 3096223637Sbz timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 3097223637Sbz#endif 3098226544Sbz PF_LOCK(); 3099223637Sbz pfsync_request_update(0, 0); 3100226544Sbz PF_UNLOCK(); 3101223637Sbz } else { 3102223637Sbz /* Pretend like the transfer was ok */ 3103223637Sbz sc->sc_ureq_sent = 0; 3104223637Sbz sc->sc_bulk_tries = 0; 3105223637Sbz#ifdef __FreeBSD__ 3106228736Sglebius if (!sc->pfsync_sync_ok && carp_demote_adj_p) 3107228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, 3108228736Sglebius "pfsync bulk fail"); 3109228736Sglebius sc->pfsync_sync_ok = 1; 3110223637Sbz#else 3111228736Sglebius#if NCARP > 0 3112223637Sbz if (!pfsync_sync_ok) 3113223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 3114223637Sbz#endif 3115223637Sbz pfsync_sync_ok = 1; 3116223637Sbz#endif 3117223637Sbz#ifdef __FreeBSD__ 3118223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 3119223637Sbz#else 3120223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 3121223637Sbz#endif 3122223637Sbz printf("pfsync: failed to receive bulk update\n"); 3123223637Sbz } 3124171168Smlaier 3125223637Sbz#ifdef __FreeBSD__ 3126223637Sbz CURVNET_RESTORE(); 3127223637Sbz#endif 3128223637Sbz} 3129171168Smlaier 3130223637Sbzvoid 3131223637Sbzpfsync_send_plus(void *plus, size_t pluslen) 3132223637Sbz{ 3133223637Sbz#ifdef __FreeBSD__ 3134223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3135223637Sbz#else 3136223637Sbz struct pfsync_softc *sc = pfsyncif; 3137223637Sbz#endif 3138223637Sbz int s; 3139223637Sbz 3140226544Sbz PF_LOCK_ASSERT(); 3141226544Sbz 3142223637Sbz#ifdef __FreeBSD__ 3143223637Sbz if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) { 3144223637Sbz#else 3145223637Sbz if (sc->sc_len + pluslen > sc->sc_if.if_mtu) { 3146223637Sbz#endif 3147223637Sbz s = splnet(); 3148223637Sbz pfsync_sendout(); 3149223637Sbz splx(s); 3150171168Smlaier } 3151223637Sbz 3152223637Sbz sc->sc_plus = plus; 3153223637Sbz sc->sc_len += (sc->sc_pluslen = pluslen); 3154223637Sbz 3155223637Sbz s = splnet(); 3156223637Sbz pfsync_sendout(); 3157171168Smlaier splx(s); 3158171168Smlaier} 3159171168Smlaier 3160171168Smlaierint 3161223637Sbzpfsync_up(void) 3162171168Smlaier{ 3163223637Sbz#ifdef __FreeBSD__ 3164223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3165223637Sbz#else 3166171168Smlaier struct pfsync_softc *sc = pfsyncif; 3167223637Sbz#endif 3168171168Smlaier 3169147261Smlaier#ifdef __FreeBSD__ 3170223637Sbz if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING)) 3171171168Smlaier#else 3172223637Sbz if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) 3173171168Smlaier#endif 3174223637Sbz return (0); 3175223637Sbz 3176223637Sbz return (1); 3177223637Sbz} 3178223637Sbz 3179223637Sbzint 3180223637Sbzpfsync_state_in_use(struct pf_state *st) 3181223637Sbz{ 3182171168Smlaier#ifdef __FreeBSD__ 3183223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3184171168Smlaier#else 3185223637Sbz struct pfsync_softc *sc = pfsyncif; 3186171168Smlaier#endif 3187223637Sbz 3188223637Sbz if (sc == NULL) 3189171168Smlaier return (0); 3190171168Smlaier 3191226663Sglebius if (st->sync_state != PFSYNC_S_NONE || 3192226663Sglebius st == sc->sc_bulk_next || 3193226663Sglebius st == sc->sc_bulk_last) 3194223637Sbz return (1); 3195223637Sbz 3196226663Sglebius return (0); 3197223637Sbz} 3198223637Sbz 3199223637Sbzu_int pfsync_ints; 3200223637Sbzu_int pfsync_tmos; 3201223637Sbz 3202223637Sbzvoid 3203223637Sbzpfsync_timeout(void *arg) 3204223637Sbz{ 3205223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE) 3206223637Sbz struct pfsync_softc *sc = arg; 3207223637Sbz#endif 3208223637Sbz int s; 3209223637Sbz 3210171168Smlaier#ifdef __FreeBSD__ 3211223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3212171168Smlaier#endif 3213223637Sbz 3214223637Sbz pfsync_tmos++; 3215223637Sbz 3216171168Smlaier s = splnet(); 3217223637Sbz#ifdef __FreeBSD__ 3218223637Sbz PF_LOCK(); 3219223637Sbz#endif 3220223637Sbz pfsync_sendout(); 3221223637Sbz#ifdef __FreeBSD__ 3222223637Sbz PF_UNLOCK(); 3223223637Sbz#endif 3224223637Sbz splx(s); 3225171168Smlaier 3226223637Sbz#ifdef __FreeBSD__ 3227223637Sbz CURVNET_RESTORE(); 3228223637Sbz#endif 3229223637Sbz} 3230171168Smlaier 3231223637Sbz/* this is a softnet/netisr handler */ 3232223637Sbzvoid 3233223637Sbz#ifdef __FreeBSD__ 3234223637Sbzpfsyncintr(void *arg) 3235226660Sglebius{ 3236226660Sglebius struct pfsync_softc *sc = arg; 3237226831Sglebius struct mbuf *m, *n; 3238226660Sglebius 3239226660Sglebius CURVNET_SET(sc->sc_ifp->if_vnet); 3240226660Sglebius pfsync_ints++; 3241226660Sglebius 3242229976Sglebius PF_LOCK(); 3243229976Sglebius if (sc->sc_len > PFSYNC_MINPKT) 3244229976Sglebius pfsync_sendout1(0); 3245229976Sglebius _IF_DEQUEUE_ALL(&sc->sc_ifp->if_snd, m); 3246229976Sglebius PF_UNLOCK(); 3247226660Sglebius 3248226831Sglebius for (; m != NULL; m = n) { 3249226831Sglebius 3250226831Sglebius n = m->m_nextpkt; 3251226831Sglebius m->m_nextpkt = NULL; 3252226660Sglebius if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) 3253226660Sglebius == 0) 3254226660Sglebius V_pfsyncstats.pfsyncs_opackets++; 3255226660Sglebius else 3256226660Sglebius V_pfsyncstats.pfsyncs_oerrors++; 3257226660Sglebius } 3258226660Sglebius CURVNET_RESTORE(); 3259226660Sglebius} 3260223637Sbz#else 3261223637Sbzpfsyncintr(void) 3262223637Sbz{ 3263223637Sbz int s; 3264171168Smlaier 3265223637Sbz pfsync_ints++; 3266171168Smlaier 3267223637Sbz s = splnet(); 3268223637Sbz pfsync_sendout(); 3269223637Sbz splx(s); 3270226660Sglebius} 3271223637Sbz#endif 3272171168Smlaier 3273223637Sbzint 3274223637Sbzpfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 3275223637Sbz size_t newlen) 3276223637Sbz{ 3277223637Sbz 3278223637Sbz#ifdef notyet 3279223637Sbz /* All sysctl names at this level are terminal. */ 3280223637Sbz if (namelen != 1) 3281223637Sbz return (ENOTDIR); 3282223637Sbz 3283223637Sbz switch (name[0]) { 3284223637Sbz case PFSYNCCTL_STATS: 3285223637Sbz if (newp != NULL) 3286223637Sbz return (EPERM); 3287223637Sbz return (sysctl_struct(oldp, oldlenp, newp, newlen, 3288223637Sbz &V_pfsyncstats, sizeof(V_pfsyncstats))); 3289223637Sbz } 3290223637Sbz#endif 3291223637Sbz return (ENOPROTOOPT); 3292223637Sbz} 3293223637Sbz 3294171168Smlaier#ifdef __FreeBSD__ 3295229850Sglebiusstatic int 3296229850Sglebiuspfsync_multicast_setup(struct pfsync_softc *sc) 3297167710Sbms{ 3298229850Sglebius struct ip_moptions *imo = &sc->sc_imo; 3299229850Sglebius int error; 3300167710Sbms 3301229850Sglebius if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 3302229850Sglebius sc->sc_sync_if = NULL; 3303229850Sglebius return (EADDRNOTAVAIL); 3304229850Sglebius } 3305167710Sbms 3306229850Sglebius imo->imo_membership = (struct in_multi **)malloc( 3307229850Sglebius (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, 3308229850Sglebius M_WAITOK | M_ZERO); 3309229850Sglebius imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 3310229850Sglebius imo->imo_multicast_vif = -1; 3311223637Sbz 3312229850Sglebius if ((error = in_joingroup(sc->sc_sync_if, &sc->sc_sync_peer, NULL, 3313229850Sglebius &imo->imo_membership[0])) != 0) { 3314229850Sglebius free(imo->imo_membership, M_PFSYNC); 3315229850Sglebius return (error); 3316167710Sbms } 3317229850Sglebius imo->imo_num_memberships++; 3318229850Sglebius imo->imo_multicast_ifp = sc->sc_sync_if; 3319229850Sglebius imo->imo_multicast_ttl = PFSYNC_DFLTTL; 3320229850Sglebius imo->imo_multicast_loop = 0; 3321167710Sbms 3322229850Sglebius return (0); 3323167710Sbms} 3324167710Sbms 3325229850Sglebiusstatic void 3326229850Sglebiuspfsync_multicast_cleanup(struct pfsync_softc *sc) 3327229850Sglebius{ 3328229850Sglebius struct ip_moptions *imo = &sc->sc_imo; 3329229850Sglebius 3330229850Sglebius in_leavegroup(imo->imo_membership[0], NULL); 3331229850Sglebius free(imo->imo_membership, M_PFSYNC); 3332229850Sglebius imo->imo_membership = NULL; 3333229850Sglebius imo->imo_multicast_ifp = NULL; 3334229850Sglebius} 3335229850Sglebius 3336229850Sglebius#ifdef INET 3337229850Sglebiusextern struct domain inetdomain; 3338229850Sglebiusstatic struct protosw in_pfsync_protosw = { 3339229964Sglebius .pr_type = SOCK_RAW, 3340229964Sglebius .pr_domain = &inetdomain, 3341229964Sglebius .pr_protocol = IPPROTO_PFSYNC, 3342229964Sglebius .pr_flags = PR_ATOMIC|PR_ADDR, 3343229964Sglebius .pr_input = pfsync_input, 3344229964Sglebius .pr_output = (pr_output_t *)rip_output, 3345229964Sglebius .pr_ctloutput = rip_ctloutput, 3346229964Sglebius .pr_usrreqs = &rip_usrreqs 3347229850Sglebius}; 3348229850Sglebius#endif 3349229850Sglebius 3350223637Sbzstatic int 3351229850Sglebiuspfsync_init() 3352147261Smlaier{ 3353229850Sglebius VNET_ITERATOR_DECL(vnet_iter); 3354223637Sbz int error = 0; 3355126261Smlaier 3356229850Sglebius VNET_LIST_RLOCK(); 3357229850Sglebius VNET_FOREACH(vnet_iter) { 3358229850Sglebius CURVNET_SET(vnet_iter); 3359229850Sglebius V_pfsync_cloner = pfsync_cloner; 3360229850Sglebius V_pfsync_cloner_data = pfsync_cloner_data; 3361229850Sglebius V_pfsync_cloner.ifc_data = &V_pfsync_cloner_data; 3362229850Sglebius if_clone_attach(&V_pfsync_cloner); 3363229850Sglebius error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif, 3364229850Sglebius SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie); 3365229850Sglebius CURVNET_RESTORE(); 3366229850Sglebius if (error) 3367229850Sglebius goto fail_locked; 3368229850Sglebius } 3369229850Sglebius VNET_LIST_RUNLOCK(); 3370229850Sglebius#ifdef INET 3371229850Sglebius error = pf_proto_register(PF_INET, &in_pfsync_protosw); 3372223637Sbz if (error) 3373229850Sglebius goto fail; 3374229850Sglebius error = ipproto_register(IPPROTO_PFSYNC); 3375229850Sglebius if (error) { 3376229850Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3377229850Sglebius goto fail; 3378229850Sglebius } 3379229850Sglebius#endif 3380228732Sglebius PF_LOCK(); 3381223637Sbz pfsync_state_import_ptr = pfsync_state_import; 3382223637Sbz pfsync_up_ptr = pfsync_up; 3383223637Sbz pfsync_insert_state_ptr = pfsync_insert_state; 3384223637Sbz pfsync_update_state_ptr = pfsync_update_state; 3385223637Sbz pfsync_delete_state_ptr = pfsync_delete_state; 3386223637Sbz pfsync_clear_states_ptr = pfsync_clear_states; 3387223637Sbz pfsync_state_in_use_ptr = pfsync_state_in_use; 3388223637Sbz pfsync_defer_ptr = pfsync_defer; 3389228732Sglebius PF_UNLOCK(); 3390223637Sbz 3391223637Sbz return (0); 3392229850Sglebius 3393229850Sglebiusfail: 3394229850Sglebius VNET_LIST_RLOCK(); 3395229850Sglebiusfail_locked: 3396229850Sglebius VNET_FOREACH(vnet_iter) { 3397229850Sglebius CURVNET_SET(vnet_iter); 3398229850Sglebius if (V_pfsync_swi_cookie) { 3399229850Sglebius swi_remove(V_pfsync_swi_cookie); 3400229850Sglebius if_clone_detach(&V_pfsync_cloner); 3401229850Sglebius } 3402229850Sglebius CURVNET_RESTORE(); 3403229850Sglebius } 3404229850Sglebius VNET_LIST_RUNLOCK(); 3405229850Sglebius 3406229850Sglebius return (error); 3407147261Smlaier} 3408147261Smlaier 3409229850Sglebiusstatic void 3410229850Sglebiuspfsync_uninit() 3411223637Sbz{ 3412229850Sglebius VNET_ITERATOR_DECL(vnet_iter); 3413223637Sbz 3414228732Sglebius PF_LOCK(); 3415223637Sbz pfsync_state_import_ptr = NULL; 3416223637Sbz pfsync_up_ptr = NULL; 3417223637Sbz pfsync_insert_state_ptr = NULL; 3418223637Sbz pfsync_update_state_ptr = NULL; 3419223637Sbz pfsync_delete_state_ptr = NULL; 3420223637Sbz pfsync_clear_states_ptr = NULL; 3421223637Sbz pfsync_state_in_use_ptr = NULL; 3422223637Sbz pfsync_defer_ptr = NULL; 3423228732Sglebius PF_UNLOCK(); 3424223637Sbz 3425229850Sglebius ipproto_unregister(IPPROTO_PFSYNC); 3426229850Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3427229850Sglebius VNET_LIST_RLOCK(); 3428229850Sglebius VNET_FOREACH(vnet_iter) { 3429229850Sglebius CURVNET_SET(vnet_iter); 3430229850Sglebius swi_remove(V_pfsync_swi_cookie); 3431229850Sglebius if_clone_detach(&V_pfsync_cloner); 3432229850Sglebius CURVNET_RESTORE(); 3433229850Sglebius } 3434229850Sglebius VNET_LIST_RUNLOCK(); 3435223637Sbz} 3436223637Sbz 3437223637Sbzstatic int 3438126261Smlaierpfsync_modevent(module_t mod, int type, void *data) 3439126261Smlaier{ 3440126261Smlaier int error = 0; 3441126261Smlaier 3442126261Smlaier switch (type) { 3443126261Smlaier case MOD_LOAD: 3444229850Sglebius error = pfsync_init(); 3445126261Smlaier break; 3446229850Sglebius case MOD_QUIESCE: 3447229850Sglebius /* 3448229850Sglebius * Module should not be unloaded due to race conditions. 3449229850Sglebius */ 3450229850Sglebius error = EPERM; 3451229850Sglebius break; 3452126261Smlaier case MOD_UNLOAD: 3453229850Sglebius pfsync_uninit(); 3454126261Smlaier break; 3455126261Smlaier default: 3456126261Smlaier error = EINVAL; 3457126261Smlaier break; 3458126261Smlaier } 3459126261Smlaier 3460229850Sglebius return (error); 3461126261Smlaier} 3462126261Smlaier 3463126261Smlaierstatic moduledata_t pfsync_mod = { 3464126261Smlaier "pfsync", 3465126261Smlaier pfsync_modevent, 3466126261Smlaier 0 3467126261Smlaier}; 3468126261Smlaier 3469126261Smlaier#define PFSYNC_MODVER 1 3470126261Smlaier 3471229853SglebiusDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 3472126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER); 3473223637SbzMODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 3474126261Smlaier#endif /* __FreeBSD__ */ 3475