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 45229770Sglebius/* 46229770Sglebius * Revisions picked from OpenBSD after revision 1.110 import: 47229770Sglebius * 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates 48229770Sglebius * 1.120, 1.175 - use monotonic time_uptime 49229770Sglebius * 1.122 - reduce number of updates for non-TCP sessions 50230868Sglebius * 1.128 - cleanups 51233275Sglebius * 1.146 - bzero() mbuf before sparsely filling it with data 52230868Sglebius * 1.170 - SIOCSIFMTU checks 53229770Sglebius */ 54229770Sglebius 55127145Smlaier#ifdef __FreeBSD__ 56126261Smlaier#include "opt_inet.h" 57126261Smlaier#include "opt_inet6.h" 58126261Smlaier#include "opt_pf.h" 59153110Sru 60171168Smlaier#include <sys/cdefs.h> 61171168Smlaier__FBSDID("$FreeBSD$"); 62171168Smlaier 63229770Sglebius#define NBPFILTER 1 64153110Sru 65171168Smlaier#ifdef DEV_CARP 66171168Smlaier#define NCARP DEV_CARP 67171168Smlaier#else 68171168Smlaier#define NCARP 0 69153110Sru#endif 70171168Smlaier#endif /* __FreeBSD__ */ 71153110Sru 72126258Smlaier#include <sys/param.h> 73223637Sbz#include <sys/kernel.h> 74164033Srwatson#ifdef __FreeBSD__ 75223637Sbz#include <sys/bus.h> 76223637Sbz#include <sys/interrupt.h> 77164033Srwatson#include <sys/priv.h> 78164033Srwatson#endif 79130613Smlaier#include <sys/proc.h> 80126258Smlaier#include <sys/systm.h> 81126258Smlaier#include <sys/time.h> 82126258Smlaier#include <sys/mbuf.h> 83126258Smlaier#include <sys/socket.h> 84127145Smlaier#ifdef __FreeBSD__ 85145836Smlaier#include <sys/endian.h> 86126261Smlaier#include <sys/malloc.h> 87129907Smlaier#include <sys/module.h> 88126261Smlaier#include <sys/sockio.h> 89171168Smlaier#include <sys/taskqueue.h> 90130613Smlaier#include <sys/lock.h> 91130613Smlaier#include <sys/mutex.h> 92230868Sglebius#include <sys/protosw.h> 93126261Smlaier#else 94126258Smlaier#include <sys/ioctl.h> 95126258Smlaier#include <sys/timeout.h> 96126261Smlaier#endif 97223637Sbz#include <sys/sysctl.h> 98223637Sbz#ifndef __FreeBSD__ 99223637Sbz#include <sys/pool.h> 100223637Sbz#endif 101126258Smlaier 102126258Smlaier#include <net/if.h> 103171168Smlaier#ifdef __FreeBSD__ 104130933Sbrooks#include <net/if_clone.h> 105130933Sbrooks#endif 106126258Smlaier#include <net/if_types.h> 107126258Smlaier#include <net/route.h> 108126258Smlaier#include <net/bpf.h> 109223637Sbz#include <net/netisr.h> 110223637Sbz#ifdef __FreeBSD__ 111223637Sbz#include <net/vnet.h> 112223637Sbz#endif 113223637Sbz 114171168Smlaier#include <netinet/in.h> 115171168Smlaier#include <netinet/if_ether.h> 116145836Smlaier#include <netinet/tcp.h> 117145836Smlaier#include <netinet/tcp_seq.h> 118126258Smlaier 119126258Smlaier#ifdef INET 120130613Smlaier#include <netinet/in_systm.h> 121126258Smlaier#include <netinet/in_var.h> 122130613Smlaier#include <netinet/ip.h> 123130613Smlaier#include <netinet/ip_var.h> 124126258Smlaier#endif 125126258Smlaier 126126258Smlaier#ifdef INET6 127126258Smlaier#include <netinet6/nd6.h> 128126258Smlaier#endif /* INET6 */ 129126258Smlaier 130171168Smlaier#ifndef __FreeBSD__ 131145836Smlaier#include "carp.h" 132145836Smlaier#endif 133145836Smlaier#if NCARP > 0 134171168Smlaier#include <netinet/ip_carp.h> 135145836Smlaier#endif 136145836Smlaier 137126258Smlaier#include <net/pfvar.h> 138126258Smlaier#include <net/if_pfsync.h> 139126258Smlaier 140171168Smlaier#ifndef __FreeBSD__ 141171168Smlaier#include "bpfilter.h" 142171168Smlaier#include "pfsync.h" 143126261Smlaier#endif 144126261Smlaier 145223637Sbz#define PFSYNC_MINPKT ( \ 146223637Sbz sizeof(struct ip) + \ 147223637Sbz sizeof(struct pfsync_header) + \ 148223637Sbz sizeof(struct pfsync_subheader) + \ 149223637Sbz sizeof(struct pfsync_eof)) 150126258Smlaier 151223637Sbzstruct pfsync_pkt { 152223637Sbz struct ip *ip; 153223637Sbz struct in_addr src; 154223637Sbz u_int8_t flags; 155223637Sbz}; 156223637Sbz 157223637Sbzint pfsync_input_hmac(struct mbuf *, int); 158223637Sbz 159223637Sbzint pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *, 160223637Sbz struct pfsync_state_peer *); 161223637Sbz 162223637Sbzint pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int); 163223637Sbzint pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int); 164223637Sbzint pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int); 165223637Sbzint pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int); 166223637Sbzint pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int); 167223637Sbzint pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int); 168223637Sbzint pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int); 169223637Sbzint pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int); 170223637Sbzint pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int); 171223637Sbzint pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int); 172223637Sbzint pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int); 173223637Sbz 174223637Sbzint pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int); 175223637Sbz 176223637Sbzint (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = { 177223637Sbz pfsync_in_clr, /* PFSYNC_ACT_CLR */ 178223637Sbz pfsync_in_ins, /* PFSYNC_ACT_INS */ 179223637Sbz pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ 180223637Sbz pfsync_in_upd, /* PFSYNC_ACT_UPD */ 181223637Sbz pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ 182223637Sbz pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ 183223637Sbz pfsync_in_del, /* PFSYNC_ACT_DEL */ 184223637Sbz pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ 185223637Sbz pfsync_in_error, /* PFSYNC_ACT_INS_F */ 186223637Sbz pfsync_in_error, /* PFSYNC_ACT_DEL_F */ 187223637Sbz pfsync_in_bus, /* PFSYNC_ACT_BUS */ 188223637Sbz pfsync_in_tdb, /* PFSYNC_ACT_TDB */ 189223637Sbz pfsync_in_eof /* PFSYNC_ACT_EOF */ 190223637Sbz}; 191223637Sbz 192223637Sbzstruct pfsync_q { 193223637Sbz int (*write)(struct pf_state *, struct mbuf *, int); 194223637Sbz size_t len; 195223637Sbz u_int8_t action; 196223637Sbz}; 197223637Sbz 198223637Sbz/* we have one of these for every PFSYNC_S_ */ 199223637Sbzint pfsync_out_state(struct pf_state *, struct mbuf *, int); 200223637Sbzint pfsync_out_iack(struct pf_state *, struct mbuf *, int); 201223637Sbzint pfsync_out_upd_c(struct pf_state *, struct mbuf *, int); 202223637Sbzint pfsync_out_del(struct pf_state *, struct mbuf *, int); 203223637Sbz 204223637Sbzstruct pfsync_q pfsync_qs[] = { 205223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS }, 206223637Sbz { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, 207223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD }, 208223637Sbz { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, 209223637Sbz { pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } 210223637Sbz}; 211223637Sbz 212223637Sbzvoid pfsync_q_ins(struct pf_state *, int); 213223637Sbzvoid pfsync_q_del(struct pf_state *); 214223637Sbz 215223637Sbzstruct pfsync_upd_req_item { 216223637Sbz TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; 217223637Sbz struct pfsync_upd_req ur_msg; 218223637Sbz}; 219223637SbzTAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item); 220223637Sbz 221223637Sbzstruct pfsync_deferral { 222223637Sbz TAILQ_ENTRY(pfsync_deferral) pd_entry; 223223637Sbz struct pf_state *pd_st; 224223637Sbz struct mbuf *pd_m; 225223637Sbz#ifdef __FreeBSD__ 226223637Sbz struct callout pd_tmo; 227126258Smlaier#else 228223637Sbz struct timeout pd_tmo; 229126258Smlaier#endif 230223637Sbz}; 231223637SbzTAILQ_HEAD(pfsync_deferrals, pfsync_deferral); 232126258Smlaier 233223637Sbz#define PFSYNC_PLSIZE MAX(sizeof(struct pfsync_upd_req_item), \ 234223637Sbz sizeof(struct pfsync_deferral)) 235223637Sbz 236223637Sbz#ifdef notyet 237223637Sbzint pfsync_out_tdb(struct tdb *, struct mbuf *, int); 238223637Sbz#endif 239223637Sbz 240223637Sbzstruct pfsync_softc { 241223637Sbz#ifdef __FreeBSD__ 242223637Sbz struct ifnet *sc_ifp; 243223637Sbz#else 244223637Sbz struct ifnet sc_if; 245223637Sbz#endif 246223637Sbz struct ifnet *sc_sync_if; 247223637Sbz 248223637Sbz#ifdef __FreeBSD__ 249223637Sbz uma_zone_t sc_pool; 250223637Sbz#else 251223637Sbz struct pool sc_pool; 252223637Sbz#endif 253223637Sbz 254223637Sbz struct ip_moptions sc_imo; 255223637Sbz 256223637Sbz struct in_addr sc_sync_peer; 257223637Sbz u_int8_t sc_maxupdates; 258223637Sbz#ifdef __FreeBSD__ 259223637Sbz int pfsync_sync_ok; 260223637Sbz#endif 261223637Sbz 262223637Sbz struct ip sc_template; 263223637Sbz 264223637Sbz struct pf_state_queue sc_qs[PFSYNC_S_COUNT]; 265223637Sbz size_t sc_len; 266223637Sbz 267223637Sbz struct pfsync_upd_reqs sc_upd_req_list; 268223637Sbz 269223637Sbz struct pfsync_deferrals sc_deferrals; 270223637Sbz u_int sc_deferred; 271223637Sbz 272223637Sbz void *sc_plus; 273223637Sbz size_t sc_pluslen; 274223637Sbz 275223637Sbz u_int32_t sc_ureq_sent; 276223637Sbz int sc_bulk_tries; 277223637Sbz#ifdef __FreeBSD__ 278223637Sbz struct callout sc_bulkfail_tmo; 279223637Sbz#else 280223637Sbz struct timeout sc_bulkfail_tmo; 281223637Sbz#endif 282223637Sbz 283223637Sbz u_int32_t sc_ureq_received; 284223637Sbz struct pf_state *sc_bulk_next; 285223637Sbz struct pf_state *sc_bulk_last; 286223637Sbz#ifdef __FreeBSD__ 287223637Sbz struct callout sc_bulk_tmo; 288223637Sbz#else 289223637Sbz struct timeout sc_bulk_tmo; 290223637Sbz#endif 291223637Sbz 292223637Sbz TAILQ_HEAD(, tdb) sc_tdb_q; 293223637Sbz 294223637Sbz#ifdef __FreeBSD__ 295223637Sbz struct callout sc_tmo; 296223637Sbz#else 297223637Sbz struct timeout sc_tmo; 298223637Sbz#endif 299223637Sbz}; 300223637Sbz 301223637Sbz#ifdef __FreeBSD__ 302230868Sglebiusstatic MALLOC_DEFINE(M_PFSYNC, "pfsync", "pfsync data"); 303223637Sbzstatic VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 304223637Sbz#define V_pfsyncif VNET(pfsyncif) 305230868Sglebiusstatic VNET_DEFINE(void *, pfsync_swi_cookie) = NULL; 306230868Sglebius#define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) 307223637Sbzstatic VNET_DEFINE(struct pfsyncstats, pfsyncstats); 308223637Sbz#define V_pfsyncstats VNET(pfsyncstats) 309223637Sbz 310230868Sglebiusstatic void pfsyncintr(void *); 311230868Sglebiusstatic int pfsync_multicast_setup(struct pfsync_softc *); 312230868Sglebiusstatic void pfsync_multicast_cleanup(struct pfsync_softc *); 313230868Sglebiusstatic int pfsync_init(void); 314230868Sglebiusstatic void pfsync_uninit(void); 315230868Sglebiusstatic void pfsync_sendout1(int); 316230868Sglebius 317230868Sglebius#define schednetisr(NETISR_PFSYNC) swi_sched(V_pfsync_swi_cookie, 0) 318230868Sglebius 319223637SbzSYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 320223637SbzSYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 321223637Sbz &VNET_NAME(pfsyncstats), pfsyncstats, 322223637Sbz "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 323223637Sbz#else 324171168Smlaierstruct pfsync_softc *pfsyncif = NULL; 325171168Smlaierstruct pfsyncstats pfsyncstats; 326223637Sbz#define V_pfsyncstats pfsyncstats 327223637Sbz#endif 328223637Sbz 329171168Smlaiervoid pfsyncattach(int); 330171168Smlaier#ifdef __FreeBSD__ 331171168Smlaierint pfsync_clone_create(struct if_clone *, int, caddr_t); 332171168Smlaiervoid pfsync_clone_destroy(struct ifnet *); 333126261Smlaier#else 334171168Smlaierint pfsync_clone_create(struct if_clone *, int); 335171168Smlaierint pfsync_clone_destroy(struct ifnet *); 336126261Smlaier#endif 337171168Smlaierint pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 338171168Smlaier struct pf_state_peer *); 339171168Smlaiervoid pfsync_update_net_tdb(struct pfsync_tdb *); 340126258Smlaierint pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 341223637Sbz#ifdef __FreeBSD__ 342191148Skmacy struct route *); 343223637Sbz#else 344223637Sbz struct rtentry *); 345223637Sbz#endif 346126258Smlaierint pfsyncioctl(struct ifnet *, u_long, caddr_t); 347126258Smlaiervoid pfsyncstart(struct ifnet *); 348126258Smlaier 349223637Sbzstruct mbuf *pfsync_if_dequeue(struct ifnet *); 350223637Sbz 351223637Sbzvoid pfsync_deferred(struct pf_state *, int); 352223637Sbzvoid pfsync_undefer(struct pfsync_deferral *, int); 353223637Sbzvoid pfsync_defer_tmo(void *); 354223637Sbz 355223637Sbzvoid pfsync_request_update(u_int32_t, u_int64_t); 356223637Sbzvoid pfsync_update_state_req(struct pf_state *); 357223637Sbz 358223637Sbzvoid pfsync_drop(struct pfsync_softc *); 359223637Sbzvoid pfsync_sendout(void); 360223637Sbzvoid pfsync_send_plus(void *, size_t); 361130613Smlaiervoid pfsync_timeout(void *); 362171168Smlaiervoid pfsync_tdb_timeout(void *); 363223637Sbz 364223637Sbzvoid pfsync_bulk_start(void); 365223637Sbzvoid pfsync_bulk_status(u_int8_t); 366130613Smlaiervoid pfsync_bulk_update(void *); 367223637Sbzvoid pfsync_bulk_fail(void *); 368171168Smlaier 369167710Sbms#ifdef __FreeBSD__ 370171168Smlaier/* XXX: ugly */ 371171168Smlaier#define betoh64 (unsigned long long)be64toh 372171168Smlaier#define timeout_del callout_stop 373167710Sbms#endif 374126258Smlaier 375223637Sbz#define PFSYNC_MAX_BULKTRIES 12 376223637Sbz#ifndef __FreeBSD__ 377145836Smlaierint pfsync_sync_ok; 378126261Smlaier#endif 379126258Smlaier 380127145Smlaier#ifdef __FreeBSD__ 381230868SglebiusVNET_DEFINE(struct ifc_simple_data, pfsync_cloner_data); 382230868SglebiusVNET_DEFINE(struct if_clone, pfsync_cloner); 383230868Sglebius#define V_pfsync_cloner_data VNET(pfsync_cloner_data) 384230868Sglebius#define V_pfsync_cloner VNET(pfsync_cloner) 385130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1); 386171168Smlaier#else 387171168Smlaierstruct if_clone pfsync_cloner = 388171168Smlaier IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy); 389171168Smlaier#endif 390126261Smlaier 391171168Smlaiervoid 392171168Smlaierpfsyncattach(int npfsync) 393126261Smlaier{ 394171168Smlaier if_clone_attach(&pfsync_cloner); 395126261Smlaier} 396171168Smlaierint 397160195Ssam#ifdef __FreeBSD__ 398171168Smlaierpfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 399160195Ssam#else 400126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit) 401160195Ssam#endif 402126261Smlaier{ 403223637Sbz struct pfsync_softc *sc; 404130613Smlaier struct ifnet *ifp; 405223637Sbz int q; 406126261Smlaier 407171168Smlaier if (unit != 0) 408171168Smlaier return (EINVAL); 409171168Smlaier 410230868Sglebius#ifdef __FreeBSD__ 411230868Sglebius sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); 412230868Sglebius sc->pfsync_sync_ok = 1; 413230868Sglebius#else 414171168Smlaier pfsync_sync_ok = 1; 415230868Sglebius sc = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT | M_ZERO); 416223637Sbz#endif 417223637Sbz 418223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) 419223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 420223637Sbz 421171168Smlaier#ifdef __FreeBSD__ 422230868Sglebius sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, NULL, NULL, NULL, 423230868Sglebius NULL, UMA_ALIGN_PTR, 0); 424223637Sbz#else 425223637Sbz pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL); 426223637Sbz#endif 427223637Sbz TAILQ_INIT(&sc->sc_upd_req_list); 428223637Sbz TAILQ_INIT(&sc->sc_deferrals); 429223637Sbz sc->sc_deferred = 0; 430171168Smlaier 431223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 432223637Sbz 433223637Sbz sc->sc_len = PFSYNC_MINPKT; 434223637Sbz sc->sc_maxupdates = 128; 435223637Sbz 436230868Sglebius#ifndef __FreeBSD__ 437223637Sbz sc->sc_imo.imo_membership = (struct in_multi **)malloc( 438223637Sbz (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, 439223637Sbz M_WAITOK | M_ZERO); 440223637Sbz sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 441223637Sbz#endif 442223637Sbz 443223637Sbz#ifdef __FreeBSD__ 444223637Sbz ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 445147256Sbrooks if (ifp == NULL) { 446223637Sbz uma_zdestroy(sc->sc_pool); 447230868Sglebius free(sc, M_PFSYNC); 448147256Sbrooks return (ENOSPC); 449147256Sbrooks } 450171168Smlaier if_initname(ifp, ifc->ifc_name, unit); 451223637Sbz#else 452223637Sbz ifp = &sc->sc_if; 453171168Smlaier snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); 454171168Smlaier#endif 455223637Sbz ifp->if_softc = sc; 456130613Smlaier ifp->if_ioctl = pfsyncioctl; 457130613Smlaier ifp->if_output = pfsyncoutput; 458130613Smlaier ifp->if_start = pfsyncstart; 459171168Smlaier ifp->if_type = IFT_PFSYNC; 460130613Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 461223637Sbz ifp->if_hdrlen = sizeof(struct pfsync_header); 462230868Sglebius ifp->if_mtu = ETHERMTU; 463171168Smlaier#ifdef __FreeBSD__ 464223637Sbz callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); 465226801Sglebius callout_init_mtx(&sc->sc_bulk_tmo, &pf_task_mtx, 0); 466223637Sbz callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE); 467171168Smlaier#else 468223637Sbz timeout_set(&sc->sc_tmo, pfsync_timeout, sc); 469223637Sbz timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc); 470223637Sbz timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc); 471171168Smlaier#endif 472223637Sbz 473141584Smlaier if_attach(ifp); 474171168Smlaier#ifndef __FreeBSD__ 475171168Smlaier if_alloc_sadl(ifp); 476171168Smlaier#endif 477126261Smlaier 478171168Smlaier#if NCARP > 0 479171168Smlaier if_addgroup(ifp, "carp"); 480171168Smlaier#endif 481171168Smlaier 482126261Smlaier#if NBPFILTER > 0 483171168Smlaier#ifdef __FreeBSD__ 484141584Smlaier bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 485171168Smlaier#else 486223637Sbz bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 487126261Smlaier#endif 488171168Smlaier#endif 489126261Smlaier 490223637Sbz#ifdef __FreeBSD__ 491223637Sbz V_pfsyncif = sc; 492223637Sbz#else 493223637Sbz pfsyncif = sc; 494223637Sbz#endif 495223637Sbz 496126261Smlaier return (0); 497126261Smlaier} 498171168Smlaier 499171168Smlaier#ifdef __FreeBSD__ 500126261Smlaiervoid 501171168Smlaier#else 502171168Smlaierint 503171168Smlaier#endif 504171168Smlaierpfsync_clone_destroy(struct ifnet *ifp) 505126258Smlaier{ 506223637Sbz struct pfsync_softc *sc = ifp->if_softc; 507223637Sbz 508171168Smlaier#ifdef __FreeBSD__ 509229770Sglebius PF_LOCK(); 510171168Smlaier#endif 511229770Sglebius timeout_del(&sc->sc_bulkfail_tmo); 512229770Sglebius timeout_del(&sc->sc_bulk_tmo); 513223637Sbz timeout_del(&sc->sc_tmo); 514229770Sglebius#ifdef __FreeBSD__ 515229770Sglebius PF_UNLOCK(); 516229770Sglebius#endif 517223637Sbz#if NCARP > 0 518223637Sbz#ifdef notyet 519223637Sbz#ifdef __FreeBSD__ 520223637Sbz if (!sc->pfsync_sync_ok) 521223637Sbz#else 522223637Sbz if (!pfsync_sync_ok) 523171168Smlaier#endif 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); 544230868Sglebius if (sc->sc_imo.imo_membership) 545230868Sglebius pfsync_multicast_cleanup(sc); 546230868Sglebius free(sc, M_PFSYNC); 547223637Sbz#else 548223637Sbz free(sc->sc_imo.imo_membership, M_IPMOPTS); 549230868Sglebius 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)); 639229770Sglebius 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 691230868Sglebius#ifdef __FreeBSD__ 692226801Sglebius PF_LOCK_ASSERT(); 693226801Sglebius 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 739226801Sglebius 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)); 790229770Sglebius st->creation = time_uptime - ntohl(sp->creation); 791223637Sbz st->expire = time_second; 792223637Sbz if (sp->expire) { 793223637Sbz /* XXX No adaptive scaling. */ 794223637Sbz st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire); 795223637Sbz } 796223637Sbz 797130613Smlaier st->expire = ntohl(sp->expire) + time_second; 798130613Smlaier st->direction = sp->direction; 799130613Smlaier st->log = sp->log; 800130613Smlaier st->timeout = sp->timeout; 801200930Sdelphij st->state_flags = sp->state_flags; 802130613Smlaier 803130613Smlaier bcopy(sp->id, &st->id, sizeof(st->id)); 804130613Smlaier st->creatorid = sp->creatorid; 805223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 806223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 807130613Smlaier 808223637Sbz st->rule.ptr = r; 809223637Sbz st->nat_rule.ptr = NULL; 810223637Sbz st->anchor.ptr = NULL; 811223637Sbz st->rt_kif = NULL; 812223637Sbz 813229770Sglebius st->pfsync_time = time_uptime; 814223637Sbz st->sync_state = PFSYNC_S_NONE; 815223637Sbz 816223637Sbz /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 817223637Sbz r->states_cur++; 818223637Sbz r->states_tot++; 819223637Sbz 820223637Sbz if (!ISSET(flags, PFSYNC_SI_IOCTL)) 821223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 822223637Sbz 823223637Sbz if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { 824145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 825223637Sbz r->states_cur--; 826223637Sbz goto cleanup_state; 827223637Sbz } 828223637Sbz 829223637Sbz if (!ISSET(flags, PFSYNC_SI_IOCTL)) { 830223637Sbz CLR(st->state_flags, PFSTATE_NOSYNC); 831223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) { 832223637Sbz pfsync_q_ins(st, PFSYNC_S_IACK); 833223637Sbz schednetisr(NETISR_PFSYNC); 834223637Sbz } 835223637Sbz } 836223637Sbz CLR(st->state_flags, PFSTATE_ACK); 837223637Sbz 838223637Sbz return (0); 839223637Sbz 840223637Sbzcleanup: 841223637Sbz error = ENOMEM; 842223637Sbz if (skw == sks) 843223637Sbz sks = NULL; 844223637Sbz#ifdef __FreeBSD__ 845223637Sbz if (skw != NULL) 846223637Sbz pool_put(&V_pf_state_key_pl, skw); 847223637Sbz if (sks != NULL) 848223637Sbz pool_put(&V_pf_state_key_pl, sks); 849223637Sbz#else 850223637Sbz if (skw != NULL) 851223637Sbz pool_put(&pf_state_key_pl, skw); 852223637Sbz if (sks != NULL) 853223637Sbz pool_put(&pf_state_key_pl, sks); 854223637Sbz#endif 855223637Sbz 856223637Sbzcleanup_state: /* pf_state_insert frees the state keys */ 857223637Sbz if (st) { 858223637Sbz#ifdef __FreeBSD__ 859171168Smlaier if (st->dst.scrub) 860223637Sbz pool_put(&V_pf_state_scrub_pl, st->dst.scrub); 861223637Sbz if (st->src.scrub) 862223637Sbz pool_put(&V_pf_state_scrub_pl, st->src.scrub); 863223637Sbz pool_put(&V_pf_state_pl, st); 864223637Sbz#else 865223637Sbz if (st->dst.scrub) 866171168Smlaier pool_put(&pf_state_scrub_pl, st->dst.scrub); 867171168Smlaier if (st->src.scrub) 868171168Smlaier pool_put(&pf_state_scrub_pl, st->src.scrub); 869130613Smlaier pool_put(&pf_state_pl, st); 870223637Sbz#endif 871130613Smlaier } 872223637Sbz return (error); 873130613Smlaier} 874130613Smlaier 875130613Smlaiervoid 876130613Smlaier#ifdef __FreeBSD__ 877130613Smlaierpfsync_input(struct mbuf *m, __unused int off) 878130613Smlaier#else 879130613Smlaierpfsync_input(struct mbuf *m, ...) 880130613Smlaier#endif 881130613Smlaier{ 882223637Sbz#ifdef __FreeBSD__ 883223637Sbz struct pfsync_softc *sc = V_pfsyncif; 884223637Sbz#else 885223637Sbz struct pfsync_softc *sc = pfsyncif; 886223637Sbz#endif 887223637Sbz struct pfsync_pkt pkt; 888130613Smlaier struct ip *ip = mtod(m, struct ip *); 889130613Smlaier struct pfsync_header *ph; 890223637Sbz struct pfsync_subheader subh; 891130613Smlaier 892223637Sbz int offset; 893223637Sbz int rv; 894130613Smlaier 895223637Sbz V_pfsyncstats.pfsyncs_ipackets++; 896223637Sbz 897130613Smlaier /* verify that we have a sync interface configured */ 898223637Sbz#ifdef __FreeBSD__ 899223637Sbz if (!sc || !sc->sc_sync_if || !V_pf_status.running) 900223637Sbz#else 901223637Sbz if (!sc || !sc->sc_sync_if || !pf_status.running) 902223637Sbz#endif 903130613Smlaier goto done; 904130613Smlaier 905130613Smlaier /* verify that the packet came in on the right interface */ 906223637Sbz if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 907223637Sbz V_pfsyncstats.pfsyncs_badif++; 908130613Smlaier goto done; 909130613Smlaier } 910130613Smlaier 911223637Sbz#ifdef __FreeBSD__ 912223637Sbz sc->sc_ifp->if_ipackets++; 913223637Sbz sc->sc_ifp->if_ibytes += m->m_pkthdr.len; 914223637Sbz#else 915223637Sbz sc->sc_if.if_ipackets++; 916223637Sbz sc->sc_if.if_ibytes += m->m_pkthdr.len; 917223637Sbz#endif 918223637Sbz /* verify that the IP TTL is 255. */ 919130613Smlaier if (ip->ip_ttl != PFSYNC_DFLTTL) { 920223637Sbz V_pfsyncstats.pfsyncs_badttl++; 921130613Smlaier goto done; 922130613Smlaier } 923130613Smlaier 924223637Sbz offset = ip->ip_hl << 2; 925223637Sbz if (m->m_pkthdr.len < offset + sizeof(*ph)) { 926223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 927130613Smlaier goto done; 928130613Smlaier } 929130613Smlaier 930223637Sbz if (offset + sizeof(*ph) > m->m_len) { 931223637Sbz if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 932223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 933223637Sbz return; 934130613Smlaier } 935130613Smlaier ip = mtod(m, struct ip *); 936130613Smlaier } 937223637Sbz ph = (struct pfsync_header *)((char *)ip + offset); 938130613Smlaier 939130613Smlaier /* verify the version */ 940130613Smlaier if (ph->version != PFSYNC_VERSION) { 941223637Sbz V_pfsyncstats.pfsyncs_badver++; 942130613Smlaier goto done; 943130613Smlaier } 944130613Smlaier 945223637Sbz#if 0 946223637Sbz if (pfsync_input_hmac(m, offset) != 0) { 947223637Sbz /* XXX stats */ 948130613Smlaier goto done; 949130613Smlaier } 950223637Sbz#endif 951130613Smlaier 952130613Smlaier /* Cheaper to grab this now than having to mess with mbufs later */ 953223637Sbz pkt.ip = ip; 954223637Sbz pkt.src = ip->ip_src; 955223637Sbz pkt.flags = 0; 956130613Smlaier 957223637Sbz#ifdef __FreeBSD__ 958223637Sbz if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 959223637Sbz#else 960223637Sbz if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 961223637Sbz#endif 962223637Sbz pkt.flags |= PFSYNC_SI_CKSUM; 963171168Smlaier 964223637Sbz offset += sizeof(*ph); 965223637Sbz for (;;) { 966223637Sbz m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 967223637Sbz offset += sizeof(subh); 968223637Sbz 969223637Sbz if (subh.action >= PFSYNC_ACT_MAX) { 970223637Sbz V_pfsyncstats.pfsyncs_badact++; 971223637Sbz goto done; 972130613Smlaier } 973130613Smlaier 974223637Sbz rv = (*pfsync_acts[subh.action])(&pkt, m, offset, 975223637Sbz ntohs(subh.count)); 976223637Sbz if (rv == -1) 977223637Sbz return; 978223637Sbz 979223637Sbz offset += rv; 980223637Sbz } 981223637Sbz 982223637Sbzdone: 983223637Sbz m_freem(m); 984223637Sbz} 985223637Sbz 986223637Sbzint 987223637Sbzpfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 988223637Sbz{ 989223637Sbz struct pfsync_clr *clr; 990223637Sbz struct mbuf *mp; 991223637Sbz int len = sizeof(*clr) * count; 992223637Sbz int i, offp; 993223637Sbz 994223637Sbz struct pf_state *st, *nexts; 995223637Sbz struct pf_state_key *sk, *nextsk; 996223637Sbz struct pf_state_item *si; 997223637Sbz u_int32_t creatorid; 998223637Sbz int s; 999223637Sbz 1000223637Sbz mp = m_pulldown(m, offset, len, &offp); 1001223637Sbz if (mp == NULL) { 1002223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1003223637Sbz return (-1); 1004223637Sbz } 1005223637Sbz clr = (struct pfsync_clr *)(mp->m_data + offp); 1006223637Sbz 1007223637Sbz s = splsoftnet(); 1008130613Smlaier#ifdef __FreeBSD__ 1009223637Sbz PF_LOCK(); 1010130613Smlaier#endif 1011223637Sbz for (i = 0; i < count; i++) { 1012223637Sbz creatorid = clr[i].creatorid; 1013223637Sbz 1014223637Sbz if (clr[i].ifname[0] == '\0') { 1015223637Sbz#ifdef __FreeBSD__ 1016223637Sbz for (st = RB_MIN(pf_state_tree_id, &V_tree_id); 1017223637Sbz st; st = nexts) { 1018223637Sbz nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st); 1019223637Sbz#else 1020145836Smlaier for (st = RB_MIN(pf_state_tree_id, &tree_id); 1021145836Smlaier st; st = nexts) { 1022171168Smlaier nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 1023223637Sbz#endif 1024145836Smlaier if (st->creatorid == creatorid) { 1025223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1026171168Smlaier pf_unlink_state(st); 1027145836Smlaier } 1028130613Smlaier } 1029130613Smlaier } else { 1030223637Sbz if (pfi_kif_get(clr[i].ifname) == NULL) 1031223637Sbz continue; 1032223637Sbz 1033223637Sbz /* XXX correct? */ 1034130613Smlaier#ifdef __FreeBSD__ 1035223637Sbz for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl); 1036223637Sbz#else 1037223637Sbz for (sk = RB_MIN(pf_state_tree, &pf_statetbl); 1038130613Smlaier#endif 1039223637Sbz sk; sk = nextsk) { 1040223637Sbz nextsk = RB_NEXT(pf_state_tree, 1041223637Sbz#ifdef __FreeBSD__ 1042223637Sbz &V_pf_statetbl, sk); 1043223637Sbz#else 1044223637Sbz &pf_statetbl, sk); 1045223637Sbz#endif 1046223637Sbz TAILQ_FOREACH(si, &sk->states, entry) { 1047223637Sbz if (si->s->creatorid == creatorid) { 1048223637Sbz SET(si->s->state_flags, 1049223637Sbz PFSTATE_NOSYNC); 1050223637Sbz pf_unlink_state(si->s); 1051223637Sbz } 1052145836Smlaier } 1053130613Smlaier } 1054130613Smlaier } 1055223637Sbz } 1056130613Smlaier#ifdef __FreeBSD__ 1057223637Sbz PF_UNLOCK(); 1058130613Smlaier#endif 1059223637Sbz splx(s); 1060130613Smlaier 1061223637Sbz return (len); 1062223637Sbz} 1063223637Sbz 1064223637Sbzint 1065223637Sbzpfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1066223637Sbz{ 1067223637Sbz struct mbuf *mp; 1068223637Sbz struct pfsync_state *sa, *sp; 1069223637Sbz int len = sizeof(*sp) * count; 1070223637Sbz int i, offp; 1071223637Sbz 1072223637Sbz int s; 1073223637Sbz 1074223637Sbz mp = m_pulldown(m, offset, len, &offp); 1075223637Sbz if (mp == NULL) { 1076223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1077223637Sbz return (-1); 1078130613Smlaier } 1079223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1080130613Smlaier 1081223637Sbz s = splsoftnet(); 1082130613Smlaier#ifdef __FreeBSD__ 1083223637Sbz PF_LOCK(); 1084130613Smlaier#endif 1085223637Sbz for (i = 0; i < count; i++) { 1086223637Sbz sp = &sa[i]; 1087130613Smlaier 1088223637Sbz /* check for invalid values */ 1089223637Sbz if (sp->timeout >= PFTM_MAX || 1090223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 1091223637Sbz sp->dst.state > PF_TCPS_PROXY_DST || 1092223637Sbz sp->direction > PF_OUT || 1093223637Sbz (sp->af != AF_INET && sp->af != AF_INET6)) { 1094130613Smlaier#ifdef __FreeBSD__ 1095223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1096223637Sbz#else 1097223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1098130613Smlaier#endif 1099223637Sbz printf("pfsync_input: PFSYNC5_ACT_INS: " 1100223637Sbz "invalid value\n"); 1101130613Smlaier } 1102223637Sbz V_pfsyncstats.pfsyncs_badval++; 1103223637Sbz continue; 1104130613Smlaier } 1105223637Sbz 1106223637Sbz if (pfsync_state_import(sp, pkt->flags) == ENOMEM) { 1107223637Sbz /* drop out, but process the rest of the actions */ 1108223637Sbz break; 1109223637Sbz } 1110223637Sbz } 1111130613Smlaier#ifdef __FreeBSD__ 1112223637Sbz PF_UNLOCK(); 1113130613Smlaier#endif 1114223637Sbz splx(s); 1115130613Smlaier 1116223637Sbz return (len); 1117223637Sbz} 1118223637Sbz 1119223637Sbzint 1120223637Sbzpfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1121223637Sbz{ 1122223637Sbz struct pfsync_ins_ack *ia, *iaa; 1123223637Sbz struct pf_state_cmp id_key; 1124223637Sbz struct pf_state *st; 1125223637Sbz 1126223637Sbz struct mbuf *mp; 1127223637Sbz int len = count * sizeof(*ia); 1128223637Sbz int offp, i; 1129223637Sbz int s; 1130223637Sbz 1131223637Sbz mp = m_pulldown(m, offset, len, &offp); 1132223637Sbz if (mp == NULL) { 1133223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1134223637Sbz return (-1); 1135223637Sbz } 1136223637Sbz iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 1137223637Sbz 1138223637Sbz s = splsoftnet(); 1139130613Smlaier#ifdef __FreeBSD__ 1140223637Sbz PF_LOCK(); 1141130613Smlaier#endif 1142223637Sbz for (i = 0; i < count; i++) { 1143223637Sbz ia = &iaa[i]; 1144145836Smlaier 1145223637Sbz bcopy(&ia->id, &id_key.id, sizeof(id_key.id)); 1146223637Sbz id_key.creatorid = ia->creatorid; 1147130613Smlaier 1148223637Sbz st = pf_find_state_byid(&id_key); 1149223637Sbz if (st == NULL) 1150223637Sbz continue; 1151130613Smlaier 1152223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1153223637Sbz pfsync_deferred(st, 0); 1154223637Sbz } 1155130613Smlaier#ifdef __FreeBSD__ 1156223637Sbz PF_UNLOCK(); 1157130613Smlaier#endif 1158223637Sbz splx(s); 1159130613Smlaier /* 1160223637Sbz * XXX this is not yet implemented, but we know the size of the 1161223637Sbz * message so we can skip it. 1162130613Smlaier */ 1163130613Smlaier 1164223637Sbz return (count * sizeof(struct pfsync_ins_ack)); 1165223637Sbz} 1166223637Sbz 1167223637Sbzint 1168223637Sbzpfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, 1169223637Sbz struct pfsync_state_peer *dst) 1170223637Sbz{ 1171223637Sbz int sfail = 0; 1172223637Sbz 1173223637Sbz /* 1174223637Sbz * The state should never go backwards except 1175223637Sbz * for syn-proxy states. Neither should the 1176223637Sbz * sequence window slide backwards. 1177223637Sbz */ 1178223637Sbz if (st->src.state > src->state && 1179223637Sbz (st->src.state < PF_TCPS_PROXY_SRC || 1180223637Sbz src->state >= PF_TCPS_PROXY_SRC)) 1181223637Sbz sfail = 1; 1182223637Sbz else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo))) 1183223637Sbz sfail = 3; 1184223637Sbz else if (st->dst.state > dst->state) { 1185223637Sbz /* There might still be useful 1186223637Sbz * information about the src state here, 1187223637Sbz * so import that part of the update, 1188223637Sbz * then "fail" so we send the updated 1189223637Sbz * state back to the peer who is missing 1190223637Sbz * our what we know. */ 1191223637Sbz pf_state_peer_ntoh(src, &st->src); 1192223637Sbz /* XXX do anything with timeouts? */ 1193223637Sbz sfail = 7; 1194223637Sbz } else if (st->dst.state >= TCPS_SYN_SENT && 1195223637Sbz SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo))) 1196223637Sbz sfail = 4; 1197223637Sbz 1198223637Sbz return (sfail); 1199223637Sbz} 1200223637Sbz 1201223637Sbzint 1202223637Sbzpfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1203223637Sbz{ 1204223637Sbz struct pfsync_state *sa, *sp; 1205223637Sbz struct pf_state_cmp id_key; 1206223637Sbz struct pf_state_key *sk; 1207223637Sbz struct pf_state *st; 1208223637Sbz int sfail; 1209223637Sbz 1210223637Sbz struct mbuf *mp; 1211223637Sbz int len = count * sizeof(*sp); 1212223637Sbz int offp, i; 1213223637Sbz int s; 1214223637Sbz 1215223637Sbz mp = m_pulldown(m, offset, len, &offp); 1216223637Sbz if (mp == NULL) { 1217223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1218223637Sbz return (-1); 1219223637Sbz } 1220223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1221223637Sbz 1222223637Sbz s = splsoftnet(); 1223130613Smlaier#ifdef __FreeBSD__ 1224223637Sbz PF_LOCK(); 1225130613Smlaier#endif 1226223637Sbz for (i = 0; i < count; i++) { 1227223637Sbz sp = &sa[i]; 1228130613Smlaier 1229223637Sbz /* check for invalid values */ 1230223637Sbz if (sp->timeout >= PFTM_MAX || 1231223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 1232223637Sbz sp->dst.state > PF_TCPS_PROXY_DST) { 1233223637Sbz#ifdef __FreeBSD__ 1234223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1235223637Sbz#else 1236223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1237223637Sbz#endif 1238223637Sbz printf("pfsync_input: PFSYNC_ACT_UPD: " 1239223637Sbz "invalid value\n"); 1240130613Smlaier } 1241223637Sbz V_pfsyncstats.pfsyncs_badval++; 1242223637Sbz continue; 1243130613Smlaier } 1244223637Sbz 1245223637Sbz bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1246223637Sbz id_key.creatorid = sp->creatorid; 1247223637Sbz 1248223637Sbz st = pf_find_state_byid(&id_key); 1249223637Sbz if (st == NULL) { 1250223637Sbz /* insert the update */ 1251223637Sbz if (pfsync_state_import(sp, 0)) 1252223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1253223637Sbz continue; 1254223637Sbz } 1255223637Sbz 1256223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1257223637Sbz pfsync_deferred(st, 1); 1258223637Sbz 1259223637Sbz sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1260223637Sbz sfail = 0; 1261223637Sbz if (sk->proto == IPPROTO_TCP) 1262223637Sbz sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst); 1263223637Sbz else { 1264223637Sbz /* 1265223637Sbz * Non-TCP protocol state machine always go 1266223637Sbz * forwards 1267223637Sbz */ 1268223637Sbz if (st->src.state > sp->src.state) 1269223637Sbz sfail = 5; 1270223637Sbz else if (st->dst.state > sp->dst.state) 1271223637Sbz sfail = 6; 1272223637Sbz } 1273223637Sbz 1274223637Sbz if (sfail) { 1275130613Smlaier#ifdef __FreeBSD__ 1276223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1277223637Sbz#else 1278223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1279130613Smlaier#endif 1280223637Sbz printf("pfsync: %s stale update (%d)" 1281223637Sbz " id: %016llx creatorid: %08x\n", 1282223637Sbz (sfail < 7 ? "ignoring" : "partial"), 1283223637Sbz sfail, betoh64(st->id), 1284223637Sbz ntohl(st->creatorid)); 1285223637Sbz } 1286223637Sbz V_pfsyncstats.pfsyncs_stale++; 1287130613Smlaier 1288223637Sbz pfsync_update_state(st); 1289223637Sbz schednetisr(NETISR_PFSYNC); 1290223637Sbz continue; 1291130613Smlaier } 1292223637Sbz pfsync_alloc_scrub_memory(&sp->dst, &st->dst); 1293223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 1294223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 1295223637Sbz st->expire = ntohl(sp->expire) + time_second; 1296223637Sbz st->timeout = sp->timeout; 1297229770Sglebius st->pfsync_time = time_uptime; 1298223637Sbz } 1299223637Sbz#ifdef __FreeBSD__ 1300223637Sbz PF_UNLOCK(); 1301223637Sbz#endif 1302223637Sbz splx(s); 1303130613Smlaier 1304223637Sbz return (len); 1305223637Sbz} 1306223637Sbz 1307223637Sbzint 1308223637Sbzpfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1309223637Sbz{ 1310223637Sbz struct pfsync_upd_c *ua, *up; 1311223637Sbz struct pf_state_key *sk; 1312223637Sbz struct pf_state_cmp id_key; 1313223637Sbz struct pf_state *st; 1314223637Sbz 1315223637Sbz int len = count * sizeof(*up); 1316223637Sbz int sfail; 1317223637Sbz 1318223637Sbz struct mbuf *mp; 1319223637Sbz int offp, i; 1320223637Sbz int s; 1321223637Sbz 1322223637Sbz mp = m_pulldown(m, offset, len, &offp); 1323223637Sbz if (mp == NULL) { 1324223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1325223637Sbz return (-1); 1326223637Sbz } 1327223637Sbz ua = (struct pfsync_upd_c *)(mp->m_data + offp); 1328223637Sbz 1329223637Sbz s = splsoftnet(); 1330130613Smlaier#ifdef __FreeBSD__ 1331223637Sbz PF_LOCK(); 1332130613Smlaier#endif 1333223637Sbz for (i = 0; i < count; i++) { 1334223637Sbz up = &ua[i]; 1335223637Sbz 1336223637Sbz /* check for invalid values */ 1337223637Sbz if (up->timeout >= PFTM_MAX || 1338223637Sbz up->src.state > PF_TCPS_PROXY_DST || 1339223637Sbz up->dst.state > PF_TCPS_PROXY_DST) { 1340223637Sbz#ifdef __FreeBSD__ 1341223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1342223637Sbz#else 1343223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1344223637Sbz#endif 1345223637Sbz printf("pfsync_input: " 1346223637Sbz "PFSYNC_ACT_UPD_C: " 1347223637Sbz "invalid value\n"); 1348130613Smlaier } 1349223637Sbz V_pfsyncstats.pfsyncs_badval++; 1350223637Sbz continue; 1351223637Sbz } 1352130613Smlaier 1353223637Sbz bcopy(&up->id, &id_key.id, sizeof(id_key.id)); 1354223637Sbz id_key.creatorid = up->creatorid; 1355130613Smlaier 1356223637Sbz st = pf_find_state_byid(&id_key); 1357223637Sbz if (st == NULL) { 1358223637Sbz /* We don't have this state. Ask for it. */ 1359223637Sbz pfsync_request_update(id_key.creatorid, id_key.id); 1360223637Sbz continue; 1361223637Sbz } 1362223637Sbz 1363223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1364223637Sbz pfsync_deferred(st, 1); 1365223637Sbz 1366223637Sbz sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1367223637Sbz sfail = 0; 1368223637Sbz if (sk->proto == IPPROTO_TCP) 1369223637Sbz sfail = pfsync_upd_tcp(st, &up->src, &up->dst); 1370223637Sbz else { 1371223637Sbz /* 1372223637Sbz * Non-TCP protocol state machine always go forwards 1373223637Sbz */ 1374223637Sbz if (st->src.state > up->src.state) 1375223637Sbz sfail = 5; 1376223637Sbz else if (st->dst.state > up->dst.state) 1377223637Sbz sfail = 6; 1378223637Sbz } 1379223637Sbz 1380223637Sbz if (sfail) { 1381171168Smlaier#ifdef __FreeBSD__ 1382223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1383223637Sbz#else 1384223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1385171168Smlaier#endif 1386223637Sbz printf("pfsync: ignoring stale update " 1387223637Sbz "(%d) id: %016llx " 1388223637Sbz "creatorid: %08x\n", sfail, 1389223637Sbz betoh64(st->id), 1390223637Sbz ntohl(st->creatorid)); 1391130613Smlaier } 1392223637Sbz V_pfsyncstats.pfsyncs_stale++; 1393145836Smlaier 1394223637Sbz pfsync_update_state(st); 1395223637Sbz schednetisr(NETISR_PFSYNC); 1396223637Sbz continue; 1397130613Smlaier } 1398223637Sbz pfsync_alloc_scrub_memory(&up->dst, &st->dst); 1399223637Sbz pf_state_peer_ntoh(&up->src, &st->src); 1400223637Sbz pf_state_peer_ntoh(&up->dst, &st->dst); 1401223637Sbz st->expire = ntohl(up->expire) + time_second; 1402223637Sbz st->timeout = up->timeout; 1403229770Sglebius st->pfsync_time = time_uptime; 1404223637Sbz } 1405130613Smlaier#ifdef __FreeBSD__ 1406223637Sbz PF_UNLOCK(); 1407130613Smlaier#endif 1408223637Sbz splx(s); 1409223637Sbz 1410223637Sbz return (len); 1411223637Sbz} 1412223637Sbz 1413223637Sbzint 1414223637Sbzpfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1415223637Sbz{ 1416223637Sbz struct pfsync_upd_req *ur, *ura; 1417223637Sbz struct mbuf *mp; 1418223637Sbz int len = count * sizeof(*ur); 1419223637Sbz int i, offp; 1420223637Sbz 1421223637Sbz struct pf_state_cmp id_key; 1422223637Sbz struct pf_state *st; 1423223637Sbz 1424223637Sbz mp = m_pulldown(m, offset, len, &offp); 1425223637Sbz if (mp == NULL) { 1426223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1427223637Sbz return (-1); 1428130613Smlaier } 1429223637Sbz ura = (struct pfsync_upd_req *)(mp->m_data + offp); 1430130613Smlaier 1431230868Sglebius#ifdef __FreeBSD__ 1432230868Sglebius PF_LOCK(); 1433230868Sglebius#endif 1434223637Sbz for (i = 0; i < count; i++) { 1435223637Sbz ur = &ura[i]; 1436130613Smlaier 1437223637Sbz bcopy(&ur->id, &id_key.id, sizeof(id_key.id)); 1438223637Sbz id_key.creatorid = ur->creatorid; 1439223637Sbz 1440223637Sbz if (id_key.id == 0 && id_key.creatorid == 0) 1441223637Sbz pfsync_bulk_start(); 1442223637Sbz else { 1443223637Sbz st = pf_find_state_byid(&id_key); 1444130613Smlaier if (st == NULL) { 1445223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1446130613Smlaier continue; 1447130613Smlaier } 1448223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) 1449223637Sbz continue; 1450223637Sbz 1451223637Sbz pfsync_update_state_req(st); 1452130613Smlaier } 1453223637Sbz } 1454230868Sglebius#ifdef __FreeBSD__ 1455230868Sglebius PF_UNLOCK(); 1456230868Sglebius#endif 1457223637Sbz 1458223637Sbz return (len); 1459223637Sbz} 1460223637Sbz 1461223637Sbzint 1462223637Sbzpfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1463223637Sbz{ 1464223637Sbz struct mbuf *mp; 1465223637Sbz struct pfsync_state *sa, *sp; 1466223637Sbz struct pf_state_cmp id_key; 1467223637Sbz struct pf_state *st; 1468223637Sbz int len = count * sizeof(*sp); 1469223637Sbz int offp, i; 1470223637Sbz int s; 1471223637Sbz 1472223637Sbz mp = m_pulldown(m, offset, len, &offp); 1473223637Sbz if (mp == NULL) { 1474223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1475223637Sbz return (-1); 1476223637Sbz } 1477223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1478223637Sbz 1479223637Sbz s = splsoftnet(); 1480130613Smlaier#ifdef __FreeBSD__ 1481223637Sbz PF_LOCK(); 1482130613Smlaier#endif 1483223637Sbz for (i = 0; i < count; i++) { 1484223637Sbz sp = &sa[i]; 1485223637Sbz 1486223637Sbz bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1487223637Sbz id_key.creatorid = sp->creatorid; 1488223637Sbz 1489223637Sbz st = pf_find_state_byid(&id_key); 1490223637Sbz if (st == NULL) { 1491223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1492223637Sbz continue; 1493130613Smlaier } 1494223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1495223637Sbz pf_unlink_state(st); 1496223637Sbz } 1497223637Sbz#ifdef __FreeBSD__ 1498223637Sbz PF_UNLOCK(); 1499223637Sbz#endif 1500223637Sbz splx(s); 1501130613Smlaier 1502223637Sbz return (len); 1503223637Sbz} 1504223637Sbz 1505223637Sbzint 1506223637Sbzpfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1507223637Sbz{ 1508223637Sbz struct mbuf *mp; 1509223637Sbz struct pfsync_del_c *sa, *sp; 1510223637Sbz struct pf_state_cmp id_key; 1511223637Sbz struct pf_state *st; 1512223637Sbz int len = count * sizeof(*sp); 1513223637Sbz int offp, i; 1514223637Sbz int s; 1515223637Sbz 1516223637Sbz mp = m_pulldown(m, offset, len, &offp); 1517223637Sbz if (mp == NULL) { 1518223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1519223637Sbz return (-1); 1520223637Sbz } 1521223637Sbz sa = (struct pfsync_del_c *)(mp->m_data + offp); 1522223637Sbz 1523223637Sbz s = splsoftnet(); 1524130613Smlaier#ifdef __FreeBSD__ 1525223637Sbz PF_LOCK(); 1526130613Smlaier#endif 1527223637Sbz for (i = 0; i < count; i++) { 1528223637Sbz sp = &sa[i]; 1529130613Smlaier 1530223637Sbz bcopy(&sp->id, &id_key.id, sizeof(id_key.id)); 1531223637Sbz id_key.creatorid = sp->creatorid; 1532223637Sbz 1533223637Sbz st = pf_find_state_byid(&id_key); 1534223637Sbz if (st == NULL) { 1535223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1536223637Sbz continue; 1537223637Sbz } 1538223637Sbz 1539223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1540223637Sbz pf_unlink_state(st); 1541223637Sbz } 1542130613Smlaier#ifdef __FreeBSD__ 1543226801Sglebius PF_UNLOCK(); 1544223637Sbz#endif 1545223637Sbz splx(s); 1546223637Sbz 1547223637Sbz return (len); 1548223637Sbz} 1549223637Sbz 1550223637Sbzint 1551223637Sbzpfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1552223637Sbz{ 1553223637Sbz#ifdef __FreeBSD__ 1554223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1555130613Smlaier#else 1556223637Sbz struct pfsync_softc *sc = pfsyncif; 1557130613Smlaier#endif 1558223637Sbz struct pfsync_bus *bus; 1559223637Sbz struct mbuf *mp; 1560223637Sbz int len = count * sizeof(*bus); 1561223637Sbz int offp; 1562223637Sbz 1563223637Sbz /* If we're not waiting for a bulk update, who cares. */ 1564223637Sbz if (sc->sc_ureq_sent == 0) 1565223637Sbz return (len); 1566223637Sbz 1567223637Sbz mp = m_pulldown(m, offset, len, &offp); 1568223637Sbz if (mp == NULL) { 1569223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1570223637Sbz return (-1); 1571223637Sbz } 1572223637Sbz bus = (struct pfsync_bus *)(mp->m_data + offp); 1573223637Sbz 1574223637Sbz switch (bus->status) { 1575223637Sbz case PFSYNC_BUS_START: 1576130613Smlaier#ifdef __FreeBSD__ 1577229770Sglebius callout_reset(&sc->sc_bulkfail_tmo, 4 * hz + 1578229770Sglebius V_pf_pool_limits[PF_LIMIT_STATES].limit / 1579230868Sglebius ((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) / 1580229770Sglebius sizeof(struct pfsync_state)), 1581229770Sglebius pfsync_bulk_fail, V_pfsyncif); 1582223637Sbz#else 1583229770Sglebius timeout_add(&sc->sc_bulkfail_tmo, 4 * hz + 1584223637Sbz pf_pool_limits[PF_LIMIT_STATES].limit / 1585229770Sglebius ((sc->sc_if.if_mtu - PFSYNC_MINPKT) / 1586229770Sglebius sizeof(struct pfsync_state))); 1587223637Sbz#endif 1588223637Sbz#ifdef __FreeBSD__ 1589223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1590223637Sbz#else 1591223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1592223637Sbz#endif 1593223637Sbz printf("pfsync: received bulk update start\n"); 1594130613Smlaier break; 1595130613Smlaier 1596223637Sbz case PFSYNC_BUS_END: 1597223637Sbz if (time_uptime - ntohl(bus->endtime) >= 1598223637Sbz sc->sc_ureq_sent) { 1599223637Sbz /* that's it, we're happy */ 1600223637Sbz sc->sc_ureq_sent = 0; 1601223637Sbz sc->sc_bulk_tries = 0; 1602223637Sbz timeout_del(&sc->sc_bulkfail_tmo); 1603223637Sbz#if NCARP > 0 1604223637Sbz#ifdef notyet 1605130613Smlaier#ifdef __FreeBSD__ 1606223637Sbz if (!sc->pfsync_sync_ok) 1607130613Smlaier#else 1608223637Sbz if (!pfsync_sync_ok) 1609130613Smlaier#endif 1610223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 1611223637Sbz#endif 1612223637Sbz#endif 1613130613Smlaier#ifdef __FreeBSD__ 1614223637Sbz sc->pfsync_sync_ok = 1; 1615223637Sbz#else 1616223637Sbz pfsync_sync_ok = 1; 1617171168Smlaier#endif 1618223637Sbz#ifdef __FreeBSD__ 1619223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1620130613Smlaier#else 1621223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1622130613Smlaier#endif 1623223637Sbz printf("pfsync: received valid " 1624223637Sbz "bulk update end\n"); 1625223637Sbz } else { 1626223637Sbz#ifdef __FreeBSD__ 1627223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1628223637Sbz#else 1629223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1630145836Smlaier#endif 1631223637Sbz printf("pfsync: received invalid " 1632223637Sbz "bulk update end: bad timestamp\n"); 1633130613Smlaier } 1634130613Smlaier break; 1635223637Sbz } 1636223637Sbz 1637223637Sbz return (len); 1638223637Sbz} 1639223637Sbz 1640223637Sbzint 1641223637Sbzpfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1642223637Sbz{ 1643223637Sbz int len = count * sizeof(struct pfsync_tdb); 1644223637Sbz 1645223637Sbz#if defined(IPSEC) 1646223637Sbz struct pfsync_tdb *tp; 1647223637Sbz struct mbuf *mp; 1648223637Sbz int offp; 1649223637Sbz int i; 1650223637Sbz int s; 1651223637Sbz 1652223637Sbz mp = m_pulldown(m, offset, len, &offp); 1653223637Sbz if (mp == NULL) { 1654223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1655223637Sbz return (-1); 1656223637Sbz } 1657223637Sbz tp = (struct pfsync_tdb *)(mp->m_data + offp); 1658223637Sbz 1659223637Sbz s = splsoftnet(); 1660171168Smlaier#ifdef __FreeBSD__ 1661223637Sbz PF_LOCK(); 1662171168Smlaier#endif 1663223637Sbz for (i = 0; i < count; i++) 1664223637Sbz pfsync_update_net_tdb(&tp[i]); 1665171168Smlaier#ifdef __FreeBSD__ 1666223637Sbz PF_UNLOCK(); 1667171168Smlaier#endif 1668223637Sbz splx(s); 1669171168Smlaier#endif 1670223637Sbz 1671223637Sbz return (len); 1672223637Sbz} 1673223637Sbz 1674223637Sbz#if defined(IPSEC) 1675223637Sbz/* Update an in-kernel tdb. Silently fail if no tdb is found. */ 1676223637Sbzvoid 1677223637Sbzpfsync_update_net_tdb(struct pfsync_tdb *pt) 1678223637Sbz{ 1679223637Sbz struct tdb *tdb; 1680223637Sbz int s; 1681223637Sbz 1682223637Sbz /* check for invalid values */ 1683223637Sbz if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 1684223637Sbz (pt->dst.sa.sa_family != AF_INET && 1685223637Sbz pt->dst.sa.sa_family != AF_INET6)) 1686223637Sbz goto bad; 1687223637Sbz 1688223637Sbz s = spltdb(); 1689223637Sbz tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 1690223637Sbz if (tdb) { 1691223637Sbz pt->rpl = ntohl(pt->rpl); 1692223637Sbz pt->cur_bytes = betoh64(pt->cur_bytes); 1693223637Sbz 1694223637Sbz /* Neither replay nor byte counter should ever decrease. */ 1695223637Sbz if (pt->rpl < tdb->tdb_rpl || 1696223637Sbz pt->cur_bytes < tdb->tdb_cur_bytes) { 1697223637Sbz splx(s); 1698223637Sbz goto bad; 1699223637Sbz } 1700223637Sbz 1701223637Sbz tdb->tdb_rpl = pt->rpl; 1702223637Sbz tdb->tdb_cur_bytes = pt->cur_bytes; 1703130613Smlaier } 1704223637Sbz splx(s); 1705223637Sbz return; 1706130613Smlaier 1707223637Sbzbad: 1708223637Sbz#ifdef __FreeBSD__ 1709223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1710223637Sbz#else 1711223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1712223637Sbz#endif 1713223637Sbz printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 1714223637Sbz "invalid value\n"); 1715223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1716223637Sbz return; 1717130613Smlaier} 1718223637Sbz#endif 1719130613Smlaier 1720223637Sbz 1721130613Smlaierint 1722223637Sbzpfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1723223637Sbz{ 1724223637Sbz /* check if we are at the right place in the packet */ 1725223637Sbz if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof)) 1726223637Sbz V_pfsyncstats.pfsyncs_badact++; 1727223637Sbz 1728223637Sbz /* we're done. free and let the caller return */ 1729223637Sbz m_freem(m); 1730223637Sbz return (-1); 1731223637Sbz} 1732223637Sbz 1733223637Sbzint 1734223637Sbzpfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1735223637Sbz{ 1736223637Sbz V_pfsyncstats.pfsyncs_badact++; 1737223637Sbz 1738223637Sbz m_freem(m); 1739223637Sbz return (-1); 1740223637Sbz} 1741223637Sbz 1742223637Sbzint 1743126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 1744223637Sbz#ifdef __FreeBSD__ 1745223637Sbz struct route *rt) 1746223637Sbz#else 1747223637Sbz struct rtentry *rt) 1748223637Sbz#endif 1749126258Smlaier{ 1750126258Smlaier m_freem(m); 1751126258Smlaier return (0); 1752126258Smlaier} 1753126258Smlaier 1754126258Smlaier/* ARGSUSED */ 1755126258Smlaierint 1756126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1757126258Smlaier{ 1758130613Smlaier#ifndef __FreeBSD__ 1759130613Smlaier struct proc *p = curproc; 1760130613Smlaier#endif 1761126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1762126258Smlaier struct ifreq *ifr = (struct ifreq *)data; 1763130613Smlaier struct ip_moptions *imo = &sc->sc_imo; 1764130613Smlaier struct pfsyncreq pfsyncr; 1765130613Smlaier struct ifnet *sifp; 1766223637Sbz struct ip *ip; 1767130613Smlaier int s, error; 1768126258Smlaier 1769126258Smlaier switch (cmd) { 1770223637Sbz#if 0 1771126258Smlaier case SIOCSIFADDR: 1772126258Smlaier case SIOCAIFADDR: 1773126258Smlaier case SIOCSIFDSTADDR: 1774223637Sbz#endif 1775126258Smlaier case SIOCSIFFLAGS: 1776148891Smlaier#ifdef __FreeBSD__ 1777126258Smlaier if (ifp->if_flags & IFF_UP) 1778148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1779126258Smlaier else 1780148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1781148891Smlaier#else 1782148891Smlaier if (ifp->if_flags & IFF_UP) 1783148891Smlaier ifp->if_flags |= IFF_RUNNING; 1784148891Smlaier else 1785148891Smlaier ifp->if_flags &= ~IFF_RUNNING; 1786148891Smlaier#endif 1787126258Smlaier break; 1788126258Smlaier case SIOCSIFMTU: 1789230868Sglebius if (!sc->sc_sync_if || 1790230868Sglebius ifr->ifr_mtu <= PFSYNC_MINPKT || 1791230868Sglebius ifr->ifr_mtu > sc->sc_sync_if->if_mtu) 1792126258Smlaier return (EINVAL); 1793223637Sbz if (ifr->ifr_mtu < ifp->if_mtu) { 1794223637Sbz s = splnet(); 1795130613Smlaier#ifdef __FreeBSD__ 1796223637Sbz PF_LOCK(); 1797130613Smlaier#endif 1798223637Sbz pfsync_sendout(); 1799130613Smlaier#ifdef __FreeBSD__ 1800223637Sbz PF_UNLOCK(); 1801130613Smlaier#endif 1802223637Sbz splx(s); 1803223637Sbz } 1804223637Sbz ifp->if_mtu = ifr->ifr_mtu; 1805126258Smlaier break; 1806130613Smlaier case SIOCGETPFSYNC: 1807130613Smlaier bzero(&pfsyncr, sizeof(pfsyncr)); 1808223637Sbz if (sc->sc_sync_if) { 1809145836Smlaier strlcpy(pfsyncr.pfsyncr_syncdev, 1810223637Sbz sc->sc_sync_if->if_xname, IFNAMSIZ); 1811223637Sbz } 1812145836Smlaier pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1813130613Smlaier pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1814223637Sbz return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); 1815223637Sbz 1816130613Smlaier case SIOCSETPFSYNC: 1817130613Smlaier#ifdef __FreeBSD__ 1818164033Srwatson if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1819130613Smlaier#else 1820130613Smlaier if ((error = suser(p, p->p_acflag)) != 0) 1821130613Smlaier#endif 1822130613Smlaier return (error); 1823130613Smlaier if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1824130613Smlaier return (error); 1825130613Smlaier 1826171168Smlaier#ifdef __FreeBSD__ 1827171168Smlaier PF_LOCK(); 1828171168Smlaier#endif 1829145836Smlaier if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1830159603Smlaier#ifdef __FreeBSD__ 1831159603Smlaier sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1832159603Smlaier#else 1833145836Smlaier sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1834159603Smlaier#endif 1835145836Smlaier else 1836145836Smlaier sc->sc_sync_peer.s_addr = 1837145836Smlaier pfsyncr.pfsyncr_syncpeer.s_addr; 1838145836Smlaier 1839130613Smlaier if (pfsyncr.pfsyncr_maxupdates > 255) 1840171168Smlaier#ifdef __FreeBSD__ 1841171168Smlaier { 1842171168Smlaier PF_UNLOCK(); 1843171168Smlaier#endif 1844130613Smlaier return (EINVAL); 1845130613Smlaier#ifdef __FreeBSD__ 1846171168Smlaier } 1847130613Smlaier#endif 1848130613Smlaier sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1849130613Smlaier 1850145836Smlaier if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1851223637Sbz sc->sc_sync_if = NULL; 1852171168Smlaier#ifdef __FreeBSD__ 1853171168Smlaier PF_UNLOCK(); 1854230868Sglebius if (imo->imo_membership) 1855230868Sglebius pfsync_multicast_cleanup(sc); 1856230868Sglebius#else 1857145836Smlaier if (imo->imo_num_memberships > 0) { 1858223637Sbz in_delmulti(imo->imo_membership[ 1859223637Sbz --imo->imo_num_memberships]); 1860145836Smlaier imo->imo_multicast_ifp = NULL; 1861145836Smlaier } 1862230868Sglebius#endif 1863130613Smlaier break; 1864130613Smlaier } 1865145836Smlaier 1866130613Smlaier#ifdef __FreeBSD__ 1867171168Smlaier PF_UNLOCK(); 1868130613Smlaier#endif 1869171168Smlaier if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) 1870130613Smlaier return (EINVAL); 1871223637Sbz 1872171168Smlaier#ifdef __FreeBSD__ 1873171168Smlaier PF_LOCK(); 1874171168Smlaier#endif 1875130613Smlaier s = splnet(); 1876141584Smlaier#ifdef __FreeBSD__ 1877171168Smlaier if (sifp->if_mtu < sc->sc_ifp->if_mtu || 1878141584Smlaier#else 1879130613Smlaier if (sifp->if_mtu < sc->sc_if.if_mtu || 1880141584Smlaier#endif 1881223637Sbz (sc->sc_sync_if != NULL && 1882223637Sbz sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1883130613Smlaier sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1884223637Sbz pfsync_sendout(); 1885223637Sbz sc->sc_sync_if = sifp; 1886130613Smlaier 1887171168Smlaier#ifdef __FreeBSD__ 1888230868Sglebius if (imo->imo_membership) { 1889171168Smlaier PF_UNLOCK(); 1890230868Sglebius pfsync_multicast_cleanup(sc); 1891230868Sglebius PF_LOCK(); 1892230868Sglebius } 1893230868Sglebius#else 1894230868Sglebius if (imo->imo_num_memberships > 0) { 1895130613Smlaier in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1896130613Smlaier imo->imo_multicast_ifp = NULL; 1897130613Smlaier } 1898230868Sglebius#endif 1899130613Smlaier 1900230868Sglebius#ifdef __FreeBSD__ 1901223637Sbz if (sc->sc_sync_if && 1902159603Smlaier sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1903230868Sglebius PF_UNLOCK(); 1904230868Sglebius error = pfsync_multicast_setup(sc); 1905230868Sglebius if (error) 1906230868Sglebius return (error); 1907230868Sglebius PF_LOCK(); 1908230868Sglebius } 1909159603Smlaier#else 1910230868Sglebius if (sc->sc_sync_if && 1911145836Smlaier sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1912130613Smlaier struct in_addr addr; 1913130613Smlaier 1914223637Sbz if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 1915223637Sbz sc->sc_sync_if = NULL; 1916145836Smlaier splx(s); 1917145836Smlaier return (EADDRNOTAVAIL); 1918145836Smlaier } 1919171168Smlaier 1920130613Smlaier addr.s_addr = INADDR_PFSYNC_GROUP; 1921145836Smlaier 1922130613Smlaier if ((imo->imo_membership[0] = 1923223637Sbz in_addmulti(&addr, sc->sc_sync_if)) == NULL) { 1924223637Sbz sc->sc_sync_if = NULL; 1925130613Smlaier splx(s); 1926130613Smlaier return (ENOBUFS); 1927130613Smlaier } 1928130613Smlaier imo->imo_num_memberships++; 1929223637Sbz imo->imo_multicast_ifp = sc->sc_sync_if; 1930130613Smlaier imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1931130613Smlaier imo->imo_multicast_loop = 0; 1932145836Smlaier } 1933230868Sglebius#endif /* !__FreeBSD__ */ 1934130613Smlaier 1935223637Sbz ip = &sc->sc_template; 1936223637Sbz bzero(ip, sizeof(*ip)); 1937223637Sbz ip->ip_v = IPVERSION; 1938223637Sbz ip->ip_hl = sizeof(sc->sc_template) >> 2; 1939223637Sbz ip->ip_tos = IPTOS_LOWDELAY; 1940223637Sbz /* len and id are set later */ 1941226801Sglebius#ifdef __FreeBSD__ 1942226801Sglebius ip->ip_off = IP_DF; 1943226801Sglebius#else 1944223637Sbz ip->ip_off = htons(IP_DF); 1945226801Sglebius#endif 1946223637Sbz ip->ip_ttl = PFSYNC_DFLTTL; 1947223637Sbz ip->ip_p = IPPROTO_PFSYNC; 1948223637Sbz ip->ip_src.s_addr = INADDR_ANY; 1949223637Sbz ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; 1950223637Sbz 1951223637Sbz if (sc->sc_sync_if) { 1952130613Smlaier /* Request a full state table update. */ 1953130613Smlaier sc->sc_ureq_sent = time_uptime; 1954145836Smlaier#if NCARP > 0 1955223637Sbz#ifdef notyet 1956223637Sbz#ifdef __FreeBSD__ 1957223637Sbz if (sc->pfsync_sync_ok) 1958223637Sbz#else 1959145836Smlaier if (pfsync_sync_ok) 1960130613Smlaier#endif 1961171168Smlaier carp_group_demote_adj(&sc->sc_if, 1); 1962171168Smlaier#endif 1963171168Smlaier#endif 1964223637Sbz#ifdef __FreeBSD__ 1965223637Sbz sc->pfsync_sync_ok = 0; 1966223637Sbz#else 1967130613Smlaier pfsync_sync_ok = 0; 1968223637Sbz#endif 1969223637Sbz#ifdef __FreeBSD__ 1970223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1971223637Sbz#else 1972130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1973223637Sbz#endif 1974130613Smlaier printf("pfsync: requesting bulk update\n"); 1975130613Smlaier#ifdef __FreeBSD__ 1976226801Sglebius callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 1977226801Sglebius pfsync_bulk_fail, V_pfsyncif); 1978130613Smlaier#else 1979223637Sbz timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 1980130613Smlaier#endif 1981223637Sbz pfsync_request_update(0, 0); 1982130613Smlaier } 1983130613Smlaier#ifdef __FreeBSD__ 1984130613Smlaier PF_UNLOCK(); 1985130613Smlaier#endif 1986130613Smlaier splx(s); 1987130613Smlaier 1988130613Smlaier break; 1989130613Smlaier 1990126258Smlaier default: 1991126258Smlaier return (ENOTTY); 1992126258Smlaier } 1993126258Smlaier 1994126258Smlaier return (0); 1995126258Smlaier} 1996126258Smlaier 1997223637Sbzint 1998223637Sbzpfsync_out_state(struct pf_state *st, struct mbuf *m, int offset) 1999130613Smlaier{ 2000223637Sbz struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset); 2001130613Smlaier 2002223637Sbz pfsync_state_export(sp, st); 2003223637Sbz 2004223637Sbz return (sizeof(*sp)); 2005223637Sbz} 2006223637Sbz 2007223637Sbzint 2008223637Sbzpfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset) 2009223637Sbz{ 2010223637Sbz struct pfsync_ins_ack *iack = 2011223637Sbz (struct pfsync_ins_ack *)(m->m_data + offset); 2012223637Sbz 2013223637Sbz iack->id = st->id; 2014223637Sbz iack->creatorid = st->creatorid; 2015223637Sbz 2016223637Sbz return (sizeof(*iack)); 2017223637Sbz} 2018223637Sbz 2019223637Sbzint 2020223637Sbzpfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset) 2021223637Sbz{ 2022223637Sbz struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset); 2023223637Sbz 2024233275Sglebius bzero(up, sizeof(*up)); 2025223637Sbz up->id = st->id; 2026223637Sbz pf_state_peer_hton(&st->src, &up->src); 2027223637Sbz pf_state_peer_hton(&st->dst, &up->dst); 2028223637Sbz up->creatorid = st->creatorid; 2029223637Sbz 2030223637Sbz up->expire = pf_state_expires(st); 2031223637Sbz if (up->expire <= time_second) 2032223637Sbz up->expire = htonl(0); 2033130613Smlaier else 2034223637Sbz up->expire = htonl(up->expire - time_second); 2035223637Sbz up->timeout = st->timeout; 2036130613Smlaier 2037223637Sbz return (sizeof(*up)); 2038223637Sbz} 2039223637Sbz 2040223637Sbzint 2041223637Sbzpfsync_out_del(struct pf_state *st, struct mbuf *m, int offset) 2042223637Sbz{ 2043223637Sbz struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset); 2044223637Sbz 2045223637Sbz dp->id = st->id; 2046223637Sbz dp->creatorid = st->creatorid; 2047223637Sbz 2048223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 2049223637Sbz 2050223637Sbz return (sizeof(*dp)); 2051223637Sbz} 2052223637Sbz 2053223637Sbzvoid 2054223637Sbzpfsync_drop(struct pfsync_softc *sc) 2055223637Sbz{ 2056223637Sbz struct pf_state *st; 2057223637Sbz struct pfsync_upd_req_item *ur; 2058223637Sbz#ifdef notyet 2059223637Sbz struct tdb *t; 2060223637Sbz#endif 2061223637Sbz int q; 2062223637Sbz 2063223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 2064223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2065223637Sbz continue; 2066223637Sbz 2067223637Sbz TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2068223637Sbz#ifdef PFSYNC_DEBUG 2069141584Smlaier#ifdef __FreeBSD__ 2070223637Sbz KASSERT(st->sync_state == q, 2071230868Sglebius ("%s: st->sync_state == q", 2072223637Sbz __FUNCTION__)); 2073141584Smlaier#else 2074223637Sbz KASSERT(st->sync_state == q); 2075171168Smlaier#endif 2076223637Sbz#endif 2077223637Sbz st->sync_state = PFSYNC_S_NONE; 2078223637Sbz } 2079223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 2080223637Sbz } 2081223637Sbz 2082223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2083223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2084223637Sbz pool_put(&sc->sc_pool, ur); 2085223637Sbz } 2086223637Sbz 2087223637Sbz sc->sc_plus = NULL; 2088223637Sbz 2089223637Sbz#ifdef notyet 2090223637Sbz if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2091223637Sbz TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) 2092223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2093223637Sbz 2094223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 2095223637Sbz } 2096223637Sbz#endif 2097223637Sbz 2098223637Sbz sc->sc_len = PFSYNC_MINPKT; 2099126258Smlaier} 2100126258Smlaier 2101230868Sglebius#ifdef __FreeBSD__ 2102230868Sglebiusvoid pfsync_sendout() 2103230868Sglebius{ 2104230868Sglebius pfsync_sendout1(1); 2105230868Sglebius} 2106230868Sglebius 2107230868Sglebiusstatic void 2108230868Sglebiuspfsync_sendout1(int schedswi) 2109230868Sglebius{ 2110230868Sglebius struct pfsync_softc *sc = V_pfsyncif; 2111230868Sglebius#else 2112223637Sbzvoid 2113223637Sbzpfsync_sendout(void) 2114126258Smlaier{ 2115223637Sbz struct pfsync_softc *sc = pfsyncif; 2116223637Sbz#endif 2117223637Sbz#if NBPFILTER > 0 2118223637Sbz#ifdef __FreeBSD__ 2119223637Sbz struct ifnet *ifp = sc->sc_ifp; 2120223637Sbz#else 2121223637Sbz struct ifnet *ifp = &sc->sc_if; 2122223637Sbz#endif 2123224936Spluknet#endif 2124126258Smlaier struct mbuf *m; 2125223637Sbz struct ip *ip; 2126223637Sbz struct pfsync_header *ph; 2127223637Sbz struct pfsync_subheader *subh; 2128223637Sbz struct pf_state *st; 2129223637Sbz struct pfsync_upd_req_item *ur; 2130223637Sbz#ifdef notyet 2131223637Sbz struct tdb *t; 2132223637Sbz#endif 2133223637Sbz#ifdef __FreeBSD__ 2134223637Sbz size_t pktlen; 2135223637Sbz#endif 2136223637Sbz int offset; 2137223637Sbz int q, count = 0; 2138126258Smlaier 2139223637Sbz#ifdef __FreeBSD__ 2140226801Sglebius PF_LOCK_ASSERT(); 2141223637Sbz#else 2142223637Sbz splassert(IPL_NET); 2143223637Sbz#endif 2144223637Sbz 2145223637Sbz if (sc == NULL || sc->sc_len == PFSYNC_MINPKT) 2146223637Sbz return; 2147223637Sbz 2148223637Sbz#if NBPFILTER > 0 2149223637Sbz if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { 2150223637Sbz#else 2151223637Sbz if (sc->sc_sync_if == NULL) { 2152223637Sbz#endif 2153223637Sbz pfsync_drop(sc); 2154223637Sbz return; 2155223637Sbz } 2156223637Sbz 2157126258Smlaier MGETHDR(m, M_DONTWAIT, MT_DATA); 2158126258Smlaier if (m == NULL) { 2159141584Smlaier#ifdef __FreeBSD__ 2160171168Smlaier sc->sc_ifp->if_oerrors++; 2161141584Smlaier#else 2162126258Smlaier sc->sc_if.if_oerrors++; 2163141584Smlaier#endif 2164223637Sbz V_pfsyncstats.pfsyncs_onomem++; 2165223637Sbz pfsync_drop(sc); 2166223637Sbz return; 2167126258Smlaier } 2168126258Smlaier 2169223637Sbz#ifdef __FreeBSD__ 2170223637Sbz pktlen = max_linkhdr + sc->sc_len; 2171223637Sbz if (pktlen > MHLEN) { 2172223637Sbz /* Find the right pool to allocate from. */ 2173223637Sbz /* XXX: This is ugly. */ 2174230868Sglebius m_cljget(m, M_DONTWAIT, pktlen <= MCLBYTES ? MCLBYTES : 2175223637Sbz#if MJUMPAGESIZE != MCLBYTES 2176223637Sbz pktlen <= MJUMPAGESIZE ? MJUMPAGESIZE : 2177171168Smlaier#endif 2178223637Sbz pktlen <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); 2179223637Sbz#else 2180223637Sbz if (max_linkhdr + sc->sc_len > MHLEN) { 2181223637Sbz MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len); 2182223637Sbz#endif 2183223637Sbz if (!ISSET(m->m_flags, M_EXT)) { 2184126258Smlaier m_free(m); 2185141584Smlaier#ifdef __FreeBSD__ 2186171168Smlaier sc->sc_ifp->if_oerrors++; 2187141584Smlaier#else 2188126258Smlaier sc->sc_if.if_oerrors++; 2189141584Smlaier#endif 2190223637Sbz V_pfsyncstats.pfsyncs_onomem++; 2191223637Sbz pfsync_drop(sc); 2192223637Sbz return; 2193126258Smlaier } 2194223637Sbz } 2195223637Sbz m->m_data += max_linkhdr; 2196223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 2197130613Smlaier 2198223637Sbz /* build the ip header */ 2199223637Sbz ip = (struct ip *)m->m_data; 2200223637Sbz bcopy(&sc->sc_template, ip, sizeof(*ip)); 2201223637Sbz offset = sizeof(*ip); 2202126258Smlaier 2203226801Sglebius#ifdef __FreeBSD__ 2204226801Sglebius ip->ip_len = m->m_pkthdr.len; 2205226801Sglebius#else 2206223637Sbz ip->ip_len = htons(m->m_pkthdr.len); 2207226801Sglebius#endif 2208223637Sbz ip->ip_id = htons(ip_randomid()); 2209126258Smlaier 2210223637Sbz /* build the pfsync header */ 2211223637Sbz ph = (struct pfsync_header *)(m->m_data + offset); 2212223637Sbz bzero(ph, sizeof(*ph)); 2213223637Sbz offset += sizeof(*ph); 2214126258Smlaier 2215223637Sbz ph->version = PFSYNC_VERSION; 2216223637Sbz ph->len = htons(sc->sc_len - sizeof(*ip)); 2217130613Smlaier#ifdef __FreeBSD__ 2218223637Sbz bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2219171168Smlaier#else 2220223637Sbz bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2221130613Smlaier#endif 2222171168Smlaier 2223223637Sbz /* walk the queues */ 2224223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 2225223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2226223637Sbz continue; 2227223637Sbz 2228223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2229223637Sbz offset += sizeof(*subh); 2230223637Sbz 2231223637Sbz count = 0; 2232223637Sbz TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2233223637Sbz#ifdef PFSYNC_DEBUG 2234159603Smlaier#ifdef __FreeBSD__ 2235223637Sbz KASSERT(st->sync_state == q, 2236223637Sbz ("%s: st->sync_state == q", 2237223637Sbz __FUNCTION__)); 2238159603Smlaier#else 2239223637Sbz KASSERT(st->sync_state == q); 2240159603Smlaier#endif 2241223637Sbz#endif 2242130613Smlaier 2243223637Sbz offset += pfsync_qs[q].write(st, m, offset); 2244223637Sbz st->sync_state = PFSYNC_S_NONE; 2245223637Sbz count++; 2246126258Smlaier } 2247223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 2248130613Smlaier 2249223637Sbz bzero(subh, sizeof(*subh)); 2250223637Sbz subh->action = pfsync_qs[q].action; 2251223637Sbz subh->count = htons(count); 2252126258Smlaier } 2253126258Smlaier 2254223637Sbz if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { 2255223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2256223637Sbz offset += sizeof(*subh); 2257126258Smlaier 2258223637Sbz count = 0; 2259223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2260223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2261130613Smlaier 2262223637Sbz bcopy(&ur->ur_msg, m->m_data + offset, 2263223637Sbz sizeof(ur->ur_msg)); 2264223637Sbz offset += sizeof(ur->ur_msg); 2265130613Smlaier 2266223637Sbz pool_put(&sc->sc_pool, ur); 2267130613Smlaier 2268223637Sbz count++; 2269223637Sbz } 2270130613Smlaier 2271223637Sbz bzero(subh, sizeof(*subh)); 2272223637Sbz subh->action = PFSYNC_ACT_UPD_REQ; 2273223637Sbz subh->count = htons(count); 2274223637Sbz } 2275130613Smlaier 2276223637Sbz /* has someone built a custom region for us to add? */ 2277223637Sbz if (sc->sc_plus != NULL) { 2278223637Sbz bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); 2279223637Sbz offset += sc->sc_pluslen; 2280130613Smlaier 2281223637Sbz sc->sc_plus = NULL; 2282130613Smlaier } 2283130613Smlaier 2284223637Sbz#ifdef notyet 2285223637Sbz if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2286223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2287223637Sbz offset += sizeof(*subh); 2288126258Smlaier 2289223637Sbz count = 0; 2290223637Sbz TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) { 2291223637Sbz offset += pfsync_out_tdb(t, m, offset); 2292223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2293126258Smlaier 2294223637Sbz count++; 2295130613Smlaier } 2296223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 2297223637Sbz 2298223637Sbz bzero(subh, sizeof(*subh)); 2299223637Sbz subh->action = PFSYNC_ACT_TDB; 2300223637Sbz subh->count = htons(count); 2301130613Smlaier } 2302223637Sbz#endif 2303130613Smlaier 2304223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2305223637Sbz offset += sizeof(*subh); 2306130613Smlaier 2307223637Sbz bzero(subh, sizeof(*subh)); 2308223637Sbz subh->action = PFSYNC_ACT_EOF; 2309223637Sbz subh->count = htons(1); 2310130613Smlaier 2311223637Sbz /* XXX write checksum in EOF here */ 2312130613Smlaier 2313223637Sbz /* we're done, let's put it on the wire */ 2314223637Sbz#if NBPFILTER > 0 2315223637Sbz if (ifp->if_bpf) { 2316223637Sbz m->m_data += sizeof(*ip); 2317223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); 2318223637Sbz#ifdef __FreeBSD__ 2319223637Sbz BPF_MTAP(ifp, m); 2320223637Sbz#else 2321223637Sbz bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 2322223637Sbz#endif 2323223637Sbz m->m_data -= sizeof(*ip); 2324223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 2325130613Smlaier } 2326130613Smlaier 2327223637Sbz if (sc->sc_sync_if == NULL) { 2328223637Sbz sc->sc_len = PFSYNC_MINPKT; 2329223637Sbz m_freem(m); 2330223637Sbz return; 2331223637Sbz } 2332223637Sbz#endif 2333126258Smlaier 2334223637Sbz#ifdef __FreeBSD__ 2335223637Sbz sc->sc_ifp->if_opackets++; 2336223637Sbz sc->sc_ifp->if_obytes += m->m_pkthdr.len; 2337226801Sglebius sc->sc_len = PFSYNC_MINPKT; 2338226801Sglebius 2339230868Sglebius if (!_IF_QFULL(&sc->sc_ifp->if_snd)) 2340230868Sglebius _IF_ENQUEUE(&sc->sc_ifp->if_snd, m); 2341230868Sglebius else { 2342230868Sglebius m_freem(m); 2343230868Sglebius sc->sc_ifp->if_snd.ifq_drops++; 2344230868Sglebius } 2345230868Sglebius if (schedswi) 2346230868Sglebius swi_sched(V_pfsync_swi_cookie, 0); 2347223637Sbz#else 2348223637Sbz sc->sc_if.if_opackets++; 2349223637Sbz sc->sc_if.if_obytes += m->m_pkthdr.len; 2350223637Sbz 2351223637Sbz if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0) 2352226801Sglebius pfsyncstats.pfsyncs_opackets++; 2353223637Sbz else 2354226801Sglebius pfsyncstats.pfsyncs_oerrors++; 2355223637Sbz 2356223637Sbz /* start again */ 2357223637Sbz sc->sc_len = PFSYNC_MINPKT; 2358226801Sglebius#endif 2359126258Smlaier} 2360126258Smlaier 2361223637Sbzvoid 2362223637Sbzpfsync_insert_state(struct pf_state *st) 2363126258Smlaier{ 2364223637Sbz#ifdef __FreeBSD__ 2365223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2366223637Sbz#else 2367171168Smlaier struct pfsync_softc *sc = pfsyncif; 2368223637Sbz#endif 2369130613Smlaier 2370130613Smlaier#ifdef __FreeBSD__ 2371226801Sglebius PF_LOCK_ASSERT(); 2372171168Smlaier#else 2373223637Sbz splassert(IPL_SOFTNET); 2374126261Smlaier#endif 2375130613Smlaier 2376223637Sbz if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) || 2377223637Sbz st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 2378223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 2379223637Sbz return; 2380130613Smlaier } 2381130613Smlaier 2382223637Sbz if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC)) 2383223637Sbz return; 2384130613Smlaier 2385223637Sbz#ifdef PFSYNC_DEBUG 2386223637Sbz#ifdef __FreeBSD__ 2387223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 2388223637Sbz ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2389223637Sbz#else 2390223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE); 2391223637Sbz#endif 2392223637Sbz#endif 2393223637Sbz 2394223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2395223637Sbz#ifdef __FreeBSD__ 2396223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2397223637Sbz V_pfsyncif); 2398223637Sbz#else 2399223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2400223637Sbz#endif 2401223637Sbz 2402223637Sbz pfsync_q_ins(st, PFSYNC_S_INS); 2403223637Sbz 2404223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2405223637Sbz schednetisr(NETISR_PFSYNC); 2406223637Sbz else 2407223637Sbz st->sync_updates = 0; 2408130613Smlaier} 2409130613Smlaier 2410223637Sbzint defer = 10; 2411223637Sbz 2412130613Smlaierint 2413223637Sbzpfsync_defer(struct pf_state *st, struct mbuf *m) 2414130613Smlaier{ 2415223637Sbz#ifdef __FreeBSD__ 2416223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2417223637Sbz#else 2418171168Smlaier struct pfsync_softc *sc = pfsyncif; 2419223637Sbz#endif 2420223637Sbz struct pfsync_deferral *pd; 2421126258Smlaier 2422223637Sbz#ifdef __FreeBSD__ 2423226801Sglebius PF_LOCK_ASSERT(); 2424223637Sbz#else 2425223637Sbz splassert(IPL_SOFTNET); 2426223637Sbz#endif 2427223637Sbz 2428223637Sbz if (sc->sc_deferred >= 128) 2429223637Sbz pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 2430223637Sbz 2431223637Sbz pd = pool_get(&sc->sc_pool, M_NOWAIT); 2432223637Sbz if (pd == NULL) 2433171168Smlaier return (0); 2434223637Sbz sc->sc_deferred++; 2435171168Smlaier 2436130613Smlaier#ifdef __FreeBSD__ 2437223637Sbz m->m_flags |= M_SKIP_FIREWALL; 2438171168Smlaier#else 2439223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2440171168Smlaier#endif 2441223637Sbz SET(st->state_flags, PFSTATE_ACK); 2442223637Sbz 2443223637Sbz pd->pd_st = st; 2444223637Sbz pd->pd_m = m; 2445223637Sbz 2446223637Sbz TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); 2447171168Smlaier#ifdef __FreeBSD__ 2448223637Sbz callout_init(&pd->pd_tmo, CALLOUT_MPSAFE); 2449223637Sbz callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo, 2450223637Sbz pd); 2451223637Sbz#else 2452223637Sbz timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd); 2453223637Sbz timeout_add(&pd->pd_tmo, defer); 2454130613Smlaier#endif 2455126258Smlaier 2456223637Sbz return (1); 2457126258Smlaier} 2458126258Smlaier 2459126258Smlaiervoid 2460223637Sbzpfsync_undefer(struct pfsync_deferral *pd, int drop) 2461126258Smlaier{ 2462223637Sbz#ifdef __FreeBSD__ 2463223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2464223637Sbz#else 2465223637Sbz struct pfsync_softc *sc = pfsyncif; 2466223637Sbz#endif 2467126258Smlaier int s; 2468126258Smlaier 2469130613Smlaier#ifdef __FreeBSD__ 2470226801Sglebius PF_LOCK_ASSERT(); 2471223637Sbz#else 2472223637Sbz splassert(IPL_SOFTNET); 2473130613Smlaier#endif 2474223637Sbz 2475223637Sbz TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 2476223637Sbz sc->sc_deferred--; 2477223637Sbz 2478223637Sbz CLR(pd->pd_st->state_flags, PFSTATE_ACK); 2479223637Sbz timeout_del(&pd->pd_tmo); /* bah */ 2480223637Sbz if (drop) 2481223637Sbz m_freem(pd->pd_m); 2482223637Sbz else { 2483223637Sbz s = splnet(); 2484130613Smlaier#ifdef __FreeBSD__ 2485223637Sbz /* XXX: use pf_defered?! */ 2486223637Sbz PF_UNLOCK(); 2487130613Smlaier#endif 2488223637Sbz ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0, 2489223637Sbz (void *)NULL, (void *)NULL); 2490223637Sbz#ifdef __FreeBSD__ 2491223637Sbz PF_LOCK(); 2492223637Sbz#endif 2493223637Sbz splx(s); 2494223637Sbz } 2495223637Sbz 2496223637Sbz pool_put(&sc->sc_pool, pd); 2497126258Smlaier} 2498126258Smlaier 2499171168Smlaiervoid 2500223637Sbzpfsync_defer_tmo(void *arg) 2501171168Smlaier{ 2502223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE) 2503223637Sbz struct pfsync_deferral *pd = arg; 2504223637Sbz#endif 2505171168Smlaier int s; 2506171168Smlaier 2507223637Sbz s = splsoftnet(); 2508171168Smlaier#ifdef __FreeBSD__ 2509223637Sbz CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */ 2510171168Smlaier PF_LOCK(); 2511171168Smlaier#endif 2512223637Sbz pfsync_undefer(arg, 0); 2513171168Smlaier#ifdef __FreeBSD__ 2514171168Smlaier PF_UNLOCK(); 2515223637Sbz CURVNET_RESTORE(); 2516171168Smlaier#endif 2517171168Smlaier splx(s); 2518171168Smlaier} 2519223637Sbz 2520223637Sbzvoid 2521223637Sbzpfsync_deferred(struct pf_state *st, int drop) 2522223637Sbz{ 2523223637Sbz#ifdef __FreeBSD__ 2524223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2525223637Sbz#else 2526223637Sbz struct pfsync_softc *sc = pfsyncif; 2527171168Smlaier#endif 2528223637Sbz struct pfsync_deferral *pd; 2529171168Smlaier 2530223637Sbz TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { 2531223637Sbz if (pd->pd_st == st) { 2532223637Sbz pfsync_undefer(pd, drop); 2533223637Sbz return; 2534223637Sbz } 2535223637Sbz } 2536223637Sbz 2537223637Sbz panic("pfsync_send_deferred: unable to find deferred state"); 2538223637Sbz} 2539223637Sbz 2540223637Sbzu_int pfsync_upds = 0; 2541223637Sbz 2542130613Smlaiervoid 2543223637Sbzpfsync_update_state(struct pf_state *st) 2544130613Smlaier{ 2545223637Sbz#ifdef __FreeBSD__ 2546223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2547223637Sbz#else 2548223637Sbz struct pfsync_softc *sc = pfsyncif; 2549223637Sbz#endif 2550223637Sbz int sync = 0; 2551130613Smlaier 2552130613Smlaier#ifdef __FreeBSD__ 2553226801Sglebius PF_LOCK_ASSERT(); 2554223637Sbz#else 2555223637Sbz splassert(IPL_SOFTNET); 2556130613Smlaier#endif 2557130613Smlaier 2558223637Sbz if (sc == NULL) 2559223637Sbz return; 2560223637Sbz 2561223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2562223637Sbz pfsync_deferred(st, 0); 2563223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2564223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2565223637Sbz pfsync_q_del(st); 2566223637Sbz return; 2567130613Smlaier } 2568223637Sbz 2569223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2570223637Sbz#ifdef __FreeBSD__ 2571223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2572223637Sbz V_pfsyncif); 2573223637Sbz#else 2574223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2575223637Sbz#endif 2576223637Sbz 2577223637Sbz switch (st->sync_state) { 2578223637Sbz case PFSYNC_S_UPD_C: 2579223637Sbz case PFSYNC_S_UPD: 2580223637Sbz case PFSYNC_S_INS: 2581223637Sbz /* we're already handling it */ 2582223637Sbz 2583229770Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) { 2584229770Sglebius st->sync_updates++; 2585229770Sglebius if (st->sync_updates >= sc->sc_maxupdates) 2586229770Sglebius sync = 1; 2587229770Sglebius } 2588223637Sbz break; 2589223637Sbz 2590223637Sbz case PFSYNC_S_IACK: 2591223637Sbz pfsync_q_del(st); 2592223637Sbz case PFSYNC_S_NONE: 2593223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD_C); 2594223637Sbz st->sync_updates = 0; 2595223637Sbz break; 2596223637Sbz 2597223637Sbz default: 2598223637Sbz panic("pfsync_update_state: unexpected sync state %d", 2599223637Sbz st->sync_state); 2600223637Sbz } 2601223637Sbz 2602229770Sglebius if (sync || (time_uptime - st->pfsync_time) < 2) { 2603223637Sbz pfsync_upds++; 2604223637Sbz schednetisr(NETISR_PFSYNC); 2605223637Sbz } 2606130613Smlaier} 2607130613Smlaier 2608130613Smlaiervoid 2609223637Sbzpfsync_request_update(u_int32_t creatorid, u_int64_t id) 2610130613Smlaier{ 2611130613Smlaier#ifdef __FreeBSD__ 2612223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2613223637Sbz#else 2614223637Sbz struct pfsync_softc *sc = pfsyncif; 2615130613Smlaier#endif 2616223637Sbz struct pfsync_upd_req_item *item; 2617223637Sbz size_t nlen = sizeof(struct pfsync_upd_req); 2618223637Sbz int s; 2619130613Smlaier 2620226801Sglebius PF_LOCK_ASSERT(); 2621226801Sglebius 2622130613Smlaier /* 2623223637Sbz * this code does nothing to prevent multiple update requests for the 2624223637Sbz * same state being generated. 2625130613Smlaier */ 2626130613Smlaier 2627223637Sbz item = pool_get(&sc->sc_pool, PR_NOWAIT); 2628223637Sbz if (item == NULL) { 2629223637Sbz /* XXX stats */ 2630223637Sbz return; 2631223637Sbz } 2632171168Smlaier 2633223637Sbz item->ur_msg.id = id; 2634223637Sbz item->ur_msg.creatorid = creatorid; 2635171168Smlaier 2636223637Sbz if (TAILQ_EMPTY(&sc->sc_upd_req_list)) 2637223637Sbz nlen += sizeof(struct pfsync_subheader); 2638223637Sbz 2639130613Smlaier#ifdef __FreeBSD__ 2640230868Sglebius if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2641130613Smlaier#else 2642223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2643130613Smlaier#endif 2644223637Sbz s = splnet(); 2645223637Sbz pfsync_sendout(); 2646223637Sbz splx(s); 2647223637Sbz 2648223637Sbz nlen = sizeof(struct pfsync_subheader) + 2649223637Sbz sizeof(struct pfsync_upd_req); 2650130613Smlaier } 2651223637Sbz 2652223637Sbz TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); 2653223637Sbz sc->sc_len += nlen; 2654223637Sbz 2655223637Sbz schednetisr(NETISR_PFSYNC); 2656223637Sbz} 2657223637Sbz 2658223637Sbzvoid 2659223637Sbzpfsync_update_state_req(struct pf_state *st) 2660223637Sbz{ 2661130613Smlaier#ifdef __FreeBSD__ 2662223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2663223637Sbz#else 2664223637Sbz struct pfsync_softc *sc = pfsyncif; 2665130613Smlaier#endif 2666223637Sbz 2667226801Sglebius PF_LOCK_ASSERT(); 2668226801Sglebius 2669223637Sbz if (sc == NULL) 2670223637Sbz panic("pfsync_update_state_req: nonexistant instance"); 2671223637Sbz 2672223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2673223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2674223637Sbz pfsync_q_del(st); 2675223637Sbz return; 2676223637Sbz } 2677223637Sbz 2678223637Sbz switch (st->sync_state) { 2679223637Sbz case PFSYNC_S_UPD_C: 2680223637Sbz case PFSYNC_S_IACK: 2681223637Sbz pfsync_q_del(st); 2682223637Sbz case PFSYNC_S_NONE: 2683223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD); 2684223637Sbz schednetisr(NETISR_PFSYNC); 2685223637Sbz return; 2686223637Sbz 2687223637Sbz case PFSYNC_S_INS: 2688223637Sbz case PFSYNC_S_UPD: 2689223637Sbz case PFSYNC_S_DEL: 2690223637Sbz /* we're already handling it */ 2691223637Sbz return; 2692223637Sbz 2693223637Sbz default: 2694223637Sbz panic("pfsync_update_state_req: unexpected sync state %d", 2695223637Sbz st->sync_state); 2696223637Sbz } 2697130613Smlaier} 2698130613Smlaier 2699130613Smlaiervoid 2700223637Sbzpfsync_delete_state(struct pf_state *st) 2701130613Smlaier{ 2702130613Smlaier#ifdef __FreeBSD__ 2703223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2704223637Sbz#else 2705223637Sbz struct pfsync_softc *sc = pfsyncif; 2706130613Smlaier#endif 2707223637Sbz 2708130613Smlaier#ifdef __FreeBSD__ 2709226801Sglebius PF_LOCK_ASSERT(); 2710130613Smlaier#else 2711223637Sbz splassert(IPL_SOFTNET); 2712130613Smlaier#endif 2713223637Sbz 2714223637Sbz if (sc == NULL) 2715223637Sbz return; 2716223637Sbz 2717223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2718223637Sbz pfsync_deferred(st, 1); 2719223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2720223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2721223637Sbz pfsync_q_del(st); 2722223637Sbz return; 2723223637Sbz } 2724223637Sbz 2725223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2726171168Smlaier#ifdef __FreeBSD__ 2727223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2728223637Sbz V_pfsyncif); 2729171168Smlaier#else 2730223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2731171168Smlaier#endif 2732223637Sbz 2733223637Sbz switch (st->sync_state) { 2734223637Sbz case PFSYNC_S_INS: 2735223637Sbz /* we never got to tell the world so just forget about it */ 2736223637Sbz pfsync_q_del(st); 2737223637Sbz return; 2738223637Sbz 2739223637Sbz case PFSYNC_S_UPD_C: 2740223637Sbz case PFSYNC_S_UPD: 2741223637Sbz case PFSYNC_S_IACK: 2742223637Sbz pfsync_q_del(st); 2743223637Sbz /* FALLTHROUGH to putting it on the del list */ 2744223637Sbz 2745223637Sbz case PFSYNC_S_NONE: 2746223637Sbz pfsync_q_ins(st, PFSYNC_S_DEL); 2747223637Sbz return; 2748223637Sbz 2749223637Sbz default: 2750223637Sbz panic("pfsync_delete_state: unexpected sync state %d", 2751223637Sbz st->sync_state); 2752130613Smlaier } 2753223637Sbz} 2754223637Sbz 2755223637Sbzvoid 2756223637Sbzpfsync_clear_states(u_int32_t creatorid, const char *ifname) 2757223637Sbz{ 2758223637Sbz struct { 2759223637Sbz struct pfsync_subheader subh; 2760223637Sbz struct pfsync_clr clr; 2761223637Sbz } __packed r; 2762223637Sbz 2763130613Smlaier#ifdef __FreeBSD__ 2764223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2765223637Sbz#else 2766223637Sbz struct pfsync_softc *sc = pfsyncif; 2767130613Smlaier#endif 2768223637Sbz 2769223637Sbz#ifdef __FreeBSD__ 2770226801Sglebius PF_LOCK_ASSERT(); 2771223637Sbz#else 2772223637Sbz splassert(IPL_SOFTNET); 2773223637Sbz#endif 2774223637Sbz 2775223637Sbz if (sc == NULL) 2776223637Sbz return; 2777223637Sbz 2778223637Sbz bzero(&r, sizeof(r)); 2779223637Sbz 2780223637Sbz r.subh.action = PFSYNC_ACT_CLR; 2781223637Sbz r.subh.count = htons(1); 2782223637Sbz 2783223637Sbz strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 2784223637Sbz r.clr.creatorid = creatorid; 2785223637Sbz 2786223637Sbz pfsync_send_plus(&r, sizeof(r)); 2787130613Smlaier} 2788130613Smlaier 2789223637Sbzvoid 2790223637Sbzpfsync_q_ins(struct pf_state *st, int q) 2791126258Smlaier{ 2792171168Smlaier#ifdef __FreeBSD__ 2793223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2794171168Smlaier#else 2795223637Sbz struct pfsync_softc *sc = pfsyncif; 2796138666Smlaier#endif 2797223637Sbz size_t nlen = pfsync_qs[q].len; 2798223637Sbz int s; 2799223637Sbz 2800226801Sglebius PF_LOCK_ASSERT(); 2801226801Sglebius 2802223637Sbz#ifdef __FreeBSD__ 2803223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 2804223637Sbz ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2805223637Sbz#else 2806223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE); 2807171168Smlaier#endif 2808126258Smlaier 2809223637Sbz#if 1 || defined(PFSYNC_DEBUG) 2810223637Sbz if (sc->sc_len < PFSYNC_MINPKT) 2811127145Smlaier#ifdef __FreeBSD__ 2812223637Sbz panic("pfsync pkt len is too low %zu", sc->sc_len); 2813223637Sbz#else 2814223637Sbz panic("pfsync pkt len is too low %d", sc->sc_len); 2815171168Smlaier#endif 2816223637Sbz#endif 2817223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2818223637Sbz nlen += sizeof(struct pfsync_subheader); 2819130613Smlaier 2820165632Sjhb#ifdef __FreeBSD__ 2821223637Sbz if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2822165632Sjhb#else 2823223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2824126258Smlaier#endif 2825223637Sbz s = splnet(); 2826223637Sbz pfsync_sendout(); 2827223637Sbz splx(s); 2828126258Smlaier 2829223637Sbz nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 2830130613Smlaier } 2831126258Smlaier 2832223637Sbz sc->sc_len += nlen; 2833223637Sbz TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); 2834223637Sbz st->sync_state = q; 2835171168Smlaier} 2836171168Smlaier 2837223637Sbzvoid 2838223637Sbzpfsync_q_del(struct pf_state *st) 2839171168Smlaier{ 2840159603Smlaier#ifdef __FreeBSD__ 2841223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2842171168Smlaier#else 2843223637Sbz struct pfsync_softc *sc = pfsyncif; 2844171168Smlaier#endif 2845223637Sbz int q = st->sync_state; 2846171168Smlaier 2847171168Smlaier#ifdef __FreeBSD__ 2848230868Sglebius KASSERT(st->sync_state != PFSYNC_S_NONE, 2849223637Sbz ("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__)); 2850223637Sbz#else 2851223637Sbz KASSERT(st->sync_state != PFSYNC_S_NONE); 2852171168Smlaier#endif 2853171168Smlaier 2854223637Sbz sc->sc_len -= pfsync_qs[q].len; 2855223637Sbz TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); 2856223637Sbz st->sync_state = PFSYNC_S_NONE; 2857171168Smlaier 2858223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2859223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2860223637Sbz} 2861223637Sbz 2862223637Sbz#ifdef notyet 2863223637Sbzvoid 2864223637Sbzpfsync_update_tdb(struct tdb *t, int output) 2865223637Sbz{ 2866171168Smlaier#ifdef __FreeBSD__ 2867223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2868171168Smlaier#else 2869223637Sbz struct pfsync_softc *sc = pfsyncif; 2870171168Smlaier#endif 2871223637Sbz size_t nlen = sizeof(struct pfsync_tdb); 2872223637Sbz int s; 2873171168Smlaier 2874223637Sbz if (sc == NULL) 2875223637Sbz return; 2876223637Sbz 2877223637Sbz if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) { 2878223637Sbz if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2879223637Sbz nlen += sizeof(struct pfsync_subheader); 2880223637Sbz 2881223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2882223637Sbz s = splnet(); 2883226801Sglebius PF_LOCK(); 2884223637Sbz pfsync_sendout(); 2885226801Sglebius PF_UNLOCK(); 2886223637Sbz splx(s); 2887223637Sbz 2888223637Sbz nlen = sizeof(struct pfsync_subheader) + 2889223637Sbz sizeof(struct pfsync_tdb); 2890223637Sbz } 2891223637Sbz 2892223637Sbz sc->sc_len += nlen; 2893223637Sbz TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry); 2894223637Sbz SET(t->tdb_flags, TDBF_PFSYNC); 2895223637Sbz t->tdb_updates = 0; 2896223637Sbz } else { 2897223637Sbz if (++t->tdb_updates >= sc->sc_maxupdates) 2898223637Sbz schednetisr(NETISR_PFSYNC); 2899223637Sbz } 2900223637Sbz 2901223637Sbz if (output) 2902223637Sbz SET(t->tdb_flags, TDBF_PFSYNC_RPL); 2903223637Sbz else 2904223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC_RPL); 2905171168Smlaier} 2906223637Sbz 2907223637Sbzvoid 2908223637Sbzpfsync_delete_tdb(struct tdb *t) 2909223637Sbz{ 2910223637Sbz#ifdef __FreeBSD__ 2911223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2912223637Sbz#else 2913223637Sbz struct pfsync_softc *sc = pfsyncif; 2914171168Smlaier#endif 2915171168Smlaier 2916223637Sbz if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC)) 2917223637Sbz return; 2918223637Sbz 2919223637Sbz sc->sc_len -= sizeof(struct pfsync_tdb); 2920223637Sbz TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry); 2921223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2922223637Sbz 2923223637Sbz if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2924223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2925223637Sbz} 2926223637Sbz 2927171168Smlaierint 2928223637Sbzpfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset) 2929171168Smlaier{ 2930223637Sbz struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset); 2931171168Smlaier 2932223637Sbz bzero(ut, sizeof(*ut)); 2933223637Sbz ut->spi = t->tdb_spi; 2934223637Sbz bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst)); 2935223637Sbz /* 2936223637Sbz * When a failover happens, the master's rpl is probably above 2937223637Sbz * what we see here (we may be up to a second late), so 2938223637Sbz * increase it a bit for outbound tdbs to manage most such 2939223637Sbz * situations. 2940223637Sbz * 2941223637Sbz * For now, just add an offset that is likely to be larger 2942223637Sbz * than the number of packets we can see in one second. The RFC 2943223637Sbz * just says the next packet must have a higher seq value. 2944223637Sbz * 2945223637Sbz * XXX What is a good algorithm for this? We could use 2946223637Sbz * a rate-determined increase, but to know it, we would have 2947223637Sbz * to extend struct tdb. 2948223637Sbz * XXX pt->rpl can wrap over MAXINT, but if so the real tdb 2949223637Sbz * will soon be replaced anyway. For now, just don't handle 2950223637Sbz * this edge case. 2951223637Sbz */ 2952223637Sbz#define RPL_INCR 16384 2953223637Sbz ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ? 2954223637Sbz RPL_INCR : 0)); 2955223637Sbz ut->cur_bytes = htobe64(t->tdb_cur_bytes); 2956223637Sbz ut->sproto = t->tdb_sproto; 2957223637Sbz 2958223637Sbz return (sizeof(*ut)); 2959223637Sbz} 2960223637Sbz#endif 2961223637Sbz 2962223637Sbzvoid 2963223637Sbzpfsync_bulk_start(void) 2964223637Sbz{ 2965171168Smlaier#ifdef __FreeBSD__ 2966223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2967223637Sbz#else 2968223637Sbz struct pfsync_softc *sc = pfsyncif; 2969171168Smlaier#endif 2970223637Sbz 2971171168Smlaier#ifdef __FreeBSD__ 2972226801Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 2973159603Smlaier#else 2974226801Sglebius if (pf_status.debug >= PF_DEBUG_MISC) 2975159603Smlaier#endif 2976226801Sglebius printf("pfsync: received bulk update request\n"); 2977223637Sbz 2978223637Sbz#ifdef __FreeBSD__ 2979230868Sglebius PF_LOCK_ASSERT(); 2980226801Sglebius if (TAILQ_EMPTY(&V_state_list)) 2981223637Sbz#else 2982226801Sglebius if (TAILQ_EMPTY(&state_list)) 2983223637Sbz#endif 2984226801Sglebius pfsync_bulk_status(PFSYNC_BUS_END); 2985226801Sglebius else { 2986226801Sglebius sc->sc_ureq_received = time_uptime; 2987226801Sglebius if (sc->sc_bulk_next == NULL) 2988226801Sglebius#ifdef __FreeBSD__ 2989226801Sglebius sc->sc_bulk_next = TAILQ_FIRST(&V_state_list); 2990226801Sglebius#else 2991226801Sglebius sc->sc_bulk_next = TAILQ_FIRST(&state_list); 2992226801Sglebius#endif 2993230868Sglebius sc->sc_bulk_last = sc->sc_bulk_next; 2994223637Sbz 2995230868Sglebius pfsync_bulk_status(PFSYNC_BUS_START); 2996230868Sglebius callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, sc); 2997226801Sglebius } 2998223637Sbz} 2999223637Sbz 3000223637Sbzvoid 3001223637Sbzpfsync_bulk_update(void *arg) 3002223637Sbz{ 3003223637Sbz struct pfsync_softc *sc = arg; 3004223637Sbz struct pf_state *st = sc->sc_bulk_next; 3005223637Sbz int i = 0; 3006223637Sbz int s; 3007223637Sbz 3008226801Sglebius PF_LOCK_ASSERT(); 3009226801Sglebius 3010223637Sbz s = splsoftnet(); 3011223637Sbz#ifdef __FreeBSD__ 3012223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3013223637Sbz#endif 3014226801Sglebius for (;;) { 3015223637Sbz if (st->sync_state == PFSYNC_S_NONE && 3016223637Sbz st->timeout < PFTM_MAX && 3017223637Sbz st->pfsync_time <= sc->sc_ureq_received) { 3018223637Sbz pfsync_update_state_req(st); 3019223637Sbz i++; 3020130613Smlaier } 3021223637Sbz 3022223637Sbz st = TAILQ_NEXT(st, entry_list); 3023223637Sbz if (st == NULL) 3024130613Smlaier#ifdef __FreeBSD__ 3025223637Sbz st = TAILQ_FIRST(&V_state_list); 3026130613Smlaier#else 3027223637Sbz st = TAILQ_FIRST(&state_list); 3028130613Smlaier#endif 3029223637Sbz 3030226801Sglebius if (st == sc->sc_bulk_last) { 3031226801Sglebius /* we're done */ 3032226801Sglebius sc->sc_bulk_next = NULL; 3033226801Sglebius sc->sc_bulk_last = NULL; 3034226801Sglebius pfsync_bulk_status(PFSYNC_BUS_END); 3035226801Sglebius break; 3036226801Sglebius } 3037226801Sglebius 3038226801Sglebius#ifdef __FreeBSD__ 3039226801Sglebius if (i > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) < 3040226801Sglebius#else 3041226801Sglebius if (i > 1 && (sc->sc_if.if_mtu - sc->sc_len) < 3042226801Sglebius#endif 3043226801Sglebius sizeof(struct pfsync_state)) { 3044226801Sglebius /* we've filled a packet */ 3045223637Sbz sc->sc_bulk_next = st; 3046130613Smlaier#ifdef __FreeBSD__ 3047223637Sbz callout_reset(&sc->sc_bulk_tmo, 1, 3048226801Sglebius pfsync_bulk_update, sc); 3049130613Smlaier#else 3050223637Sbz timeout_add(&sc->sc_bulk_tmo, 1); 3051130613Smlaier#endif 3052226801Sglebius break; 3053223637Sbz } 3054226801Sglebius } 3055130613Smlaier 3056130613Smlaier#ifdef __FreeBSD__ 3057223637Sbz CURVNET_RESTORE(); 3058223637Sbz#endif 3059223637Sbz splx(s); 3060223637Sbz} 3061223637Sbz 3062223637Sbzvoid 3063223637Sbzpfsync_bulk_status(u_int8_t status) 3064223637Sbz{ 3065223637Sbz struct { 3066223637Sbz struct pfsync_subheader subh; 3067223637Sbz struct pfsync_bus bus; 3068223637Sbz } __packed r; 3069223637Sbz 3070223637Sbz#ifdef __FreeBSD__ 3071223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3072130613Smlaier#else 3073223637Sbz struct pfsync_softc *sc = pfsyncif; 3074130613Smlaier#endif 3075130613Smlaier 3076226801Sglebius PF_LOCK_ASSERT(); 3077226801Sglebius 3078223637Sbz bzero(&r, sizeof(r)); 3079171168Smlaier 3080223637Sbz r.subh.action = PFSYNC_ACT_BUS; 3081223637Sbz r.subh.count = htons(1); 3082223637Sbz 3083130613Smlaier#ifdef __FreeBSD__ 3084223637Sbz r.bus.creatorid = V_pf_status.hostid; 3085147261Smlaier#else 3086223637Sbz r.bus.creatorid = pf_status.hostid; 3087130613Smlaier#endif 3088223637Sbz r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 3089223637Sbz r.bus.status = status; 3090130613Smlaier 3091223637Sbz pfsync_send_plus(&r, sizeof(r)); 3092126258Smlaier} 3093126261Smlaier 3094171168Smlaiervoid 3095223637Sbzpfsync_bulk_fail(void *arg) 3096171168Smlaier{ 3097223637Sbz struct pfsync_softc *sc = arg; 3098171168Smlaier 3099223637Sbz#ifdef __FreeBSD__ 3100223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3101223637Sbz#endif 3102171168Smlaier 3103223637Sbz if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 3104223637Sbz /* Try again */ 3105223637Sbz#ifdef __FreeBSD__ 3106223637Sbz callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 3107223637Sbz pfsync_bulk_fail, V_pfsyncif); 3108223637Sbz#else 3109223637Sbz timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 3110223637Sbz#endif 3111226801Sglebius PF_LOCK(); 3112223637Sbz pfsync_request_update(0, 0); 3113226801Sglebius PF_UNLOCK(); 3114223637Sbz } else { 3115223637Sbz /* Pretend like the transfer was ok */ 3116223637Sbz sc->sc_ureq_sent = 0; 3117223637Sbz sc->sc_bulk_tries = 0; 3118223637Sbz#if NCARP > 0 3119223637Sbz#ifdef notyet 3120223637Sbz#ifdef __FreeBSD__ 3121223637Sbz if (!sc->pfsync_sync_ok) 3122223637Sbz#else 3123223637Sbz if (!pfsync_sync_ok) 3124223637Sbz#endif 3125223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 3126223637Sbz#endif 3127223637Sbz#endif 3128223637Sbz#ifdef __FreeBSD__ 3129223637Sbz sc->pfsync_sync_ok = 1; 3130223637Sbz#else 3131223637Sbz pfsync_sync_ok = 1; 3132223637Sbz#endif 3133223637Sbz#ifdef __FreeBSD__ 3134223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 3135223637Sbz#else 3136223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 3137223637Sbz#endif 3138223637Sbz printf("pfsync: failed to receive bulk update\n"); 3139223637Sbz } 3140171168Smlaier 3141223637Sbz#ifdef __FreeBSD__ 3142223637Sbz CURVNET_RESTORE(); 3143223637Sbz#endif 3144223637Sbz} 3145171168Smlaier 3146223637Sbzvoid 3147223637Sbzpfsync_send_plus(void *plus, size_t pluslen) 3148223637Sbz{ 3149223637Sbz#ifdef __FreeBSD__ 3150223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3151223637Sbz#else 3152223637Sbz struct pfsync_softc *sc = pfsyncif; 3153223637Sbz#endif 3154223637Sbz int s; 3155223637Sbz 3156226801Sglebius PF_LOCK_ASSERT(); 3157226801Sglebius 3158223637Sbz#ifdef __FreeBSD__ 3159223637Sbz if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) { 3160223637Sbz#else 3161223637Sbz if (sc->sc_len + pluslen > sc->sc_if.if_mtu) { 3162223637Sbz#endif 3163223637Sbz s = splnet(); 3164223637Sbz pfsync_sendout(); 3165223637Sbz splx(s); 3166171168Smlaier } 3167223637Sbz 3168223637Sbz sc->sc_plus = plus; 3169223637Sbz sc->sc_len += (sc->sc_pluslen = pluslen); 3170223637Sbz 3171223637Sbz s = splnet(); 3172223637Sbz pfsync_sendout(); 3173171168Smlaier splx(s); 3174171168Smlaier} 3175171168Smlaier 3176171168Smlaierint 3177223637Sbzpfsync_up(void) 3178171168Smlaier{ 3179223637Sbz#ifdef __FreeBSD__ 3180223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3181223637Sbz#else 3182171168Smlaier struct pfsync_softc *sc = pfsyncif; 3183223637Sbz#endif 3184171168Smlaier 3185147261Smlaier#ifdef __FreeBSD__ 3186223637Sbz if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING)) 3187171168Smlaier#else 3188223637Sbz if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) 3189171168Smlaier#endif 3190223637Sbz return (0); 3191223637Sbz 3192223637Sbz return (1); 3193223637Sbz} 3194223637Sbz 3195223637Sbzint 3196223637Sbzpfsync_state_in_use(struct pf_state *st) 3197223637Sbz{ 3198171168Smlaier#ifdef __FreeBSD__ 3199223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3200171168Smlaier#else 3201223637Sbz struct pfsync_softc *sc = pfsyncif; 3202171168Smlaier#endif 3203223637Sbz 3204223637Sbz if (sc == NULL) 3205171168Smlaier return (0); 3206171168Smlaier 3207226801Sglebius if (st->sync_state != PFSYNC_S_NONE || 3208226801Sglebius st == sc->sc_bulk_next || 3209226801Sglebius st == sc->sc_bulk_last) 3210223637Sbz return (1); 3211223637Sbz 3212226801Sglebius return (0); 3213223637Sbz} 3214223637Sbz 3215223637Sbzu_int pfsync_ints; 3216223637Sbzu_int pfsync_tmos; 3217223637Sbz 3218223637Sbzvoid 3219223637Sbzpfsync_timeout(void *arg) 3220223637Sbz{ 3221223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE) 3222223637Sbz struct pfsync_softc *sc = arg; 3223223637Sbz#endif 3224223637Sbz int s; 3225223637Sbz 3226171168Smlaier#ifdef __FreeBSD__ 3227223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3228171168Smlaier#endif 3229223637Sbz 3230223637Sbz pfsync_tmos++; 3231223637Sbz 3232171168Smlaier s = splnet(); 3233223637Sbz#ifdef __FreeBSD__ 3234223637Sbz PF_LOCK(); 3235223637Sbz#endif 3236223637Sbz pfsync_sendout(); 3237223637Sbz#ifdef __FreeBSD__ 3238223637Sbz PF_UNLOCK(); 3239223637Sbz#endif 3240223637Sbz splx(s); 3241171168Smlaier 3242223637Sbz#ifdef __FreeBSD__ 3243223637Sbz CURVNET_RESTORE(); 3244223637Sbz#endif 3245223637Sbz} 3246171168Smlaier 3247223637Sbz/* this is a softnet/netisr handler */ 3248223637Sbzvoid 3249223637Sbz#ifdef __FreeBSD__ 3250223637Sbzpfsyncintr(void *arg) 3251226801Sglebius{ 3252226801Sglebius struct pfsync_softc *sc = arg; 3253229770Sglebius struct mbuf *m, *n; 3254226801Sglebius 3255226801Sglebius CURVNET_SET(sc->sc_ifp->if_vnet); 3256226801Sglebius pfsync_ints++; 3257226801Sglebius 3258230868Sglebius PF_LOCK(); 3259230868Sglebius if (sc->sc_len > PFSYNC_MINPKT) 3260230868Sglebius pfsync_sendout1(0); 3261230868Sglebius _IF_DEQUEUE_ALL(&sc->sc_ifp->if_snd, m); 3262230868Sglebius PF_UNLOCK(); 3263226801Sglebius 3264229770Sglebius for (; m != NULL; m = n) { 3265229770Sglebius 3266229770Sglebius n = m->m_nextpkt; 3267229770Sglebius m->m_nextpkt = NULL; 3268226801Sglebius if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) 3269226801Sglebius == 0) 3270226801Sglebius V_pfsyncstats.pfsyncs_opackets++; 3271226801Sglebius else 3272226801Sglebius V_pfsyncstats.pfsyncs_oerrors++; 3273226801Sglebius } 3274226801Sglebius CURVNET_RESTORE(); 3275226801Sglebius} 3276223637Sbz#else 3277223637Sbzpfsyncintr(void) 3278223637Sbz{ 3279223637Sbz int s; 3280171168Smlaier 3281223637Sbz pfsync_ints++; 3282171168Smlaier 3283223637Sbz s = splnet(); 3284223637Sbz pfsync_sendout(); 3285223637Sbz splx(s); 3286226801Sglebius} 3287223637Sbz#endif 3288171168Smlaier 3289223637Sbzint 3290223637Sbzpfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 3291223637Sbz size_t newlen) 3292223637Sbz{ 3293223637Sbz 3294223637Sbz#ifdef notyet 3295223637Sbz /* All sysctl names at this level are terminal. */ 3296223637Sbz if (namelen != 1) 3297223637Sbz return (ENOTDIR); 3298223637Sbz 3299223637Sbz switch (name[0]) { 3300223637Sbz case PFSYNCCTL_STATS: 3301223637Sbz if (newp != NULL) 3302223637Sbz return (EPERM); 3303223637Sbz return (sysctl_struct(oldp, oldlenp, newp, newlen, 3304223637Sbz &V_pfsyncstats, sizeof(V_pfsyncstats))); 3305223637Sbz } 3306223637Sbz#endif 3307223637Sbz return (ENOPROTOOPT); 3308223637Sbz} 3309223637Sbz 3310171168Smlaier#ifdef __FreeBSD__ 3311230868Sglebiusstatic int 3312230868Sglebiuspfsync_multicast_setup(struct pfsync_softc *sc) 3313167710Sbms{ 3314230868Sglebius struct ip_moptions *imo = &sc->sc_imo; 3315230868Sglebius int error; 3316167710Sbms 3317230868Sglebius if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 3318230868Sglebius sc->sc_sync_if = NULL; 3319230868Sglebius return (EADDRNOTAVAIL); 3320230868Sglebius } 3321167710Sbms 3322230868Sglebius imo->imo_membership = (struct in_multi **)malloc( 3323230868Sglebius (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, 3324230868Sglebius M_WAITOK | M_ZERO); 3325230868Sglebius imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 3326230868Sglebius imo->imo_multicast_vif = -1; 3327223637Sbz 3328230868Sglebius if ((error = in_joingroup(sc->sc_sync_if, &sc->sc_sync_peer, NULL, 3329230868Sglebius &imo->imo_membership[0])) != 0) { 3330230868Sglebius free(imo->imo_membership, M_PFSYNC); 3331230868Sglebius return (error); 3332167710Sbms } 3333230868Sglebius imo->imo_num_memberships++; 3334230868Sglebius imo->imo_multicast_ifp = sc->sc_sync_if; 3335230868Sglebius imo->imo_multicast_ttl = PFSYNC_DFLTTL; 3336230868Sglebius imo->imo_multicast_loop = 0; 3337167710Sbms 3338230868Sglebius return (0); 3339167710Sbms} 3340167710Sbms 3341230868Sglebiusstatic void 3342230868Sglebiuspfsync_multicast_cleanup(struct pfsync_softc *sc) 3343230868Sglebius{ 3344230868Sglebius struct ip_moptions *imo = &sc->sc_imo; 3345230868Sglebius 3346230868Sglebius in_leavegroup(imo->imo_membership[0], NULL); 3347230868Sglebius free(imo->imo_membership, M_PFSYNC); 3348230868Sglebius imo->imo_membership = NULL; 3349230868Sglebius imo->imo_multicast_ifp = NULL; 3350230868Sglebius} 3351230868Sglebius 3352230868Sglebius#ifdef INET 3353230868Sglebiusextern struct domain inetdomain; 3354230868Sglebiusstatic struct protosw in_pfsync_protosw = { 3355230868Sglebius .pr_type = SOCK_RAW, 3356230868Sglebius .pr_domain = &inetdomain, 3357230868Sglebius .pr_protocol = IPPROTO_PFSYNC, 3358230868Sglebius .pr_flags = PR_ATOMIC|PR_ADDR, 3359230868Sglebius .pr_input = pfsync_input, 3360230868Sglebius .pr_output = (pr_output_t *)rip_output, 3361230868Sglebius .pr_ctloutput = rip_ctloutput, 3362230868Sglebius .pr_usrreqs = &rip_usrreqs 3363230868Sglebius}; 3364230868Sglebius#endif 3365230868Sglebius 3366223637Sbzstatic int 3367230868Sglebiuspfsync_init() 3368147261Smlaier{ 3369230868Sglebius VNET_ITERATOR_DECL(vnet_iter); 3370223637Sbz int error = 0; 3371126261Smlaier 3372230868Sglebius VNET_LIST_RLOCK(); 3373230868Sglebius VNET_FOREACH(vnet_iter) { 3374230868Sglebius CURVNET_SET(vnet_iter); 3375230868Sglebius V_pfsync_cloner = pfsync_cloner; 3376230868Sglebius V_pfsync_cloner_data = pfsync_cloner_data; 3377230868Sglebius V_pfsync_cloner.ifc_data = &V_pfsync_cloner_data; 3378230868Sglebius if_clone_attach(&V_pfsync_cloner); 3379230868Sglebius error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif, 3380230868Sglebius SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie); 3381230868Sglebius CURVNET_RESTORE(); 3382230868Sglebius if (error) 3383230868Sglebius goto fail_locked; 3384230868Sglebius } 3385230868Sglebius VNET_LIST_RUNLOCK(); 3386230868Sglebius#ifdef INET 3387230868Sglebius error = pf_proto_register(PF_INET, &in_pfsync_protosw); 3388223637Sbz if (error) 3389230868Sglebius goto fail; 3390230868Sglebius error = ipproto_register(IPPROTO_PFSYNC); 3391230868Sglebius if (error) { 3392230868Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3393230868Sglebius goto fail; 3394230868Sglebius } 3395230868Sglebius#endif 3396229770Sglebius PF_LOCK(); 3397223637Sbz pfsync_state_import_ptr = pfsync_state_import; 3398223637Sbz pfsync_up_ptr = pfsync_up; 3399223637Sbz pfsync_insert_state_ptr = pfsync_insert_state; 3400223637Sbz pfsync_update_state_ptr = pfsync_update_state; 3401223637Sbz pfsync_delete_state_ptr = pfsync_delete_state; 3402223637Sbz pfsync_clear_states_ptr = pfsync_clear_states; 3403223637Sbz pfsync_state_in_use_ptr = pfsync_state_in_use; 3404223637Sbz pfsync_defer_ptr = pfsync_defer; 3405229770Sglebius PF_UNLOCK(); 3406223637Sbz 3407223637Sbz return (0); 3408230868Sglebius 3409230868Sglebiusfail: 3410230868Sglebius VNET_LIST_RLOCK(); 3411230868Sglebiusfail_locked: 3412230868Sglebius VNET_FOREACH(vnet_iter) { 3413230868Sglebius CURVNET_SET(vnet_iter); 3414230868Sglebius if (V_pfsync_swi_cookie) { 3415230868Sglebius swi_remove(V_pfsync_swi_cookie); 3416230868Sglebius if_clone_detach(&V_pfsync_cloner); 3417230868Sglebius } 3418230868Sglebius CURVNET_RESTORE(); 3419230868Sglebius } 3420230868Sglebius VNET_LIST_RUNLOCK(); 3421230868Sglebius 3422230868Sglebius return (error); 3423147261Smlaier} 3424147261Smlaier 3425230868Sglebiusstatic void 3426230868Sglebiuspfsync_uninit() 3427223637Sbz{ 3428230868Sglebius VNET_ITERATOR_DECL(vnet_iter); 3429223637Sbz 3430229770Sglebius PF_LOCK(); 3431223637Sbz pfsync_state_import_ptr = NULL; 3432223637Sbz pfsync_up_ptr = NULL; 3433223637Sbz pfsync_insert_state_ptr = NULL; 3434223637Sbz pfsync_update_state_ptr = NULL; 3435223637Sbz pfsync_delete_state_ptr = NULL; 3436223637Sbz pfsync_clear_states_ptr = NULL; 3437223637Sbz pfsync_state_in_use_ptr = NULL; 3438223637Sbz pfsync_defer_ptr = NULL; 3439229770Sglebius PF_UNLOCK(); 3440223637Sbz 3441230868Sglebius ipproto_unregister(IPPROTO_PFSYNC); 3442230868Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3443230868Sglebius VNET_LIST_RLOCK(); 3444230868Sglebius VNET_FOREACH(vnet_iter) { 3445230868Sglebius CURVNET_SET(vnet_iter); 3446230868Sglebius swi_remove(V_pfsync_swi_cookie); 3447230868Sglebius if_clone_detach(&V_pfsync_cloner); 3448230868Sglebius CURVNET_RESTORE(); 3449230868Sglebius } 3450230868Sglebius VNET_LIST_RUNLOCK(); 3451223637Sbz} 3452223637Sbz 3453223637Sbzstatic int 3454126261Smlaierpfsync_modevent(module_t mod, int type, void *data) 3455126261Smlaier{ 3456126261Smlaier int error = 0; 3457126261Smlaier 3458126261Smlaier switch (type) { 3459126261Smlaier case MOD_LOAD: 3460230868Sglebius error = pfsync_init(); 3461126261Smlaier break; 3462230868Sglebius case MOD_QUIESCE: 3463230868Sglebius /* 3464230868Sglebius * Module should not be unloaded due to race conditions. 3465230868Sglebius */ 3466230868Sglebius error = EPERM; 3467230868Sglebius break; 3468126261Smlaier case MOD_UNLOAD: 3469230868Sglebius pfsync_uninit(); 3470126261Smlaier break; 3471126261Smlaier default: 3472126261Smlaier error = EINVAL; 3473126261Smlaier break; 3474126261Smlaier } 3475126261Smlaier 3476230868Sglebius return (error); 3477126261Smlaier} 3478126261Smlaier 3479126261Smlaierstatic moduledata_t pfsync_mod = { 3480126261Smlaier "pfsync", 3481126261Smlaier pfsync_modevent, 3482126261Smlaier 0 3483126261Smlaier}; 3484126261Smlaier 3485126261Smlaier#define PFSYNC_MODVER 1 3486126261Smlaier 3487230868SglebiusDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 3488126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER); 3489223637SbzMODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 3490126261Smlaier#endif /* __FreeBSD__ */ 3491