if_pfsync.c revision 223637
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 45127145Smlaier#ifdef __FreeBSD__ 46126261Smlaier#include "opt_inet.h" 47126261Smlaier#include "opt_inet6.h" 48126261Smlaier#include "opt_bpf.h" 49126261Smlaier#include "opt_pf.h" 50153110Sru 51171168Smlaier#include <sys/cdefs.h> 52171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 223637 2011-06-28 11:57:25Z bz $"); 53171168Smlaier 54153110Sru#ifdef DEV_BPF 55127145Smlaier#define NBPFILTER DEV_BPF 56153110Sru#else 57153110Sru#define NBPFILTER 0 58153110Sru#endif 59153110Sru 60153110Sru#ifdef DEV_PFSYNC 61127145Smlaier#define NPFSYNC DEV_PFSYNC 62153110Sru#else 63153110Sru#define NPFSYNC 0 64126261Smlaier#endif 65126258Smlaier 66171168Smlaier#ifdef DEV_CARP 67171168Smlaier#define NCARP DEV_CARP 68171168Smlaier#else 69171168Smlaier#define NCARP 0 70153110Sru#endif 71171168Smlaier#endif /* __FreeBSD__ */ 72153110Sru 73126258Smlaier#include <sys/param.h> 74223637Sbz#include <sys/kernel.h> 75164033Srwatson#ifdef __FreeBSD__ 76223637Sbz#include <sys/bus.h> 77223637Sbz#include <sys/interrupt.h> 78164033Srwatson#include <sys/priv.h> 79164033Srwatson#endif 80130613Smlaier#include <sys/proc.h> 81126258Smlaier#include <sys/systm.h> 82126258Smlaier#include <sys/time.h> 83126258Smlaier#include <sys/mbuf.h> 84126258Smlaier#include <sys/socket.h> 85127145Smlaier#ifdef __FreeBSD__ 86145836Smlaier#include <sys/endian.h> 87126261Smlaier#include <sys/malloc.h> 88129907Smlaier#include <sys/module.h> 89126261Smlaier#include <sys/sockio.h> 90171168Smlaier#include <sys/taskqueue.h> 91130613Smlaier#include <sys/lock.h> 92130613Smlaier#include <sys/mutex.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#ifdef __FreeBSD__ 300223637Sbz eventhandler_tag sc_detachtag; 301223637Sbz#endif 302223637Sbz 303223637Sbz}; 304223637Sbz 305223637Sbz#ifdef __FreeBSD__ 306223637Sbzstatic VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 307223637Sbz#define V_pfsyncif VNET(pfsyncif) 308223637Sbz 309223637Sbzstatic VNET_DEFINE(struct pfsyncstats, pfsyncstats); 310223637Sbz#define V_pfsyncstats VNET(pfsyncstats) 311223637Sbz 312223637SbzSYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 313223637SbzSYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 314223637Sbz &VNET_NAME(pfsyncstats), pfsyncstats, 315223637Sbz "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 316223637Sbz#else 317171168Smlaierstruct pfsync_softc *pfsyncif = NULL; 318171168Smlaierstruct pfsyncstats pfsyncstats; 319223637Sbz#define V_pfsyncstats pfsyncstats 320223637Sbz#endif 321223637Sbz 322127145Smlaier#ifdef __FreeBSD__ 323223637Sbzstatic void pfsyncintr(void *); 324223637Sbzstruct pfsync_swi { 325223637Sbz void * pfsync_swi_cookie; 326223637Sbz}; 327223637Sbzstatic struct pfsync_swi pfsync_swi; 328223637Sbz#define schednetisr(p) swi_sched(pfsync_swi.pfsync_swi_cookie, 0) 329223637Sbz#define NETISR_PFSYNC 330171168Smlaier#endif 331130613Smlaier 332171168Smlaiervoid pfsyncattach(int); 333171168Smlaier#ifdef __FreeBSD__ 334171168Smlaierint pfsync_clone_create(struct if_clone *, int, caddr_t); 335171168Smlaiervoid pfsync_clone_destroy(struct ifnet *); 336126261Smlaier#else 337171168Smlaierint pfsync_clone_create(struct if_clone *, int); 338171168Smlaierint pfsync_clone_destroy(struct ifnet *); 339126261Smlaier#endif 340171168Smlaierint pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 341171168Smlaier struct pf_state_peer *); 342171168Smlaiervoid pfsync_update_net_tdb(struct pfsync_tdb *); 343126258Smlaierint pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 344223637Sbz#ifdef __FreeBSD__ 345191148Skmacy struct route *); 346223637Sbz#else 347223637Sbz struct rtentry *); 348223637Sbz#endif 349126258Smlaierint pfsyncioctl(struct ifnet *, u_long, caddr_t); 350126258Smlaiervoid pfsyncstart(struct ifnet *); 351126258Smlaier 352223637Sbzstruct mbuf *pfsync_if_dequeue(struct ifnet *); 353223637Sbzstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *); 354223637Sbz 355223637Sbzvoid pfsync_deferred(struct pf_state *, int); 356223637Sbzvoid pfsync_undefer(struct pfsync_deferral *, int); 357223637Sbzvoid pfsync_defer_tmo(void *); 358223637Sbz 359223637Sbzvoid pfsync_request_update(u_int32_t, u_int64_t); 360223637Sbzvoid pfsync_update_state_req(struct pf_state *); 361223637Sbz 362223637Sbzvoid pfsync_drop(struct pfsync_softc *); 363223637Sbzvoid pfsync_sendout(void); 364223637Sbzvoid pfsync_send_plus(void *, size_t); 365171168Smlaierint pfsync_tdb_sendout(struct pfsync_softc *); 366171168Smlaierint pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *); 367130613Smlaiervoid pfsync_timeout(void *); 368171168Smlaiervoid pfsync_tdb_timeout(void *); 369130613Smlaiervoid pfsync_send_bus(struct pfsync_softc *, u_int8_t); 370223637Sbz 371223637Sbzvoid pfsync_bulk_start(void); 372223637Sbzvoid pfsync_bulk_status(u_int8_t); 373130613Smlaiervoid pfsync_bulk_update(void *); 374223637Sbzvoid pfsync_bulk_fail(void *); 375171168Smlaier 376167710Sbms#ifdef __FreeBSD__ 377171168Smlaiervoid pfsync_ifdetach(void *, struct ifnet *); 378171168Smlaier 379171168Smlaier/* XXX: ugly */ 380171168Smlaier#define betoh64 (unsigned long long)be64toh 381171168Smlaier#define timeout_del callout_stop 382167710Sbms#endif 383126258Smlaier 384223637Sbz#define PFSYNC_MAX_BULKTRIES 12 385223637Sbz#ifndef __FreeBSD__ 386145836Smlaierint pfsync_sync_ok; 387126261Smlaier#endif 388126258Smlaier 389127145Smlaier#ifdef __FreeBSD__ 390130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1); 391171168Smlaier#else 392171168Smlaierstruct if_clone pfsync_cloner = 393171168Smlaier IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy); 394171168Smlaier#endif 395126261Smlaier 396171168Smlaiervoid 397171168Smlaierpfsyncattach(int npfsync) 398126261Smlaier{ 399171168Smlaier if_clone_attach(&pfsync_cloner); 400126261Smlaier} 401171168Smlaierint 402160195Ssam#ifdef __FreeBSD__ 403171168Smlaierpfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 404160195Ssam#else 405126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit) 406160195Ssam#endif 407126261Smlaier{ 408223637Sbz struct pfsync_softc *sc; 409130613Smlaier struct ifnet *ifp; 410223637Sbz int q; 411126261Smlaier 412171168Smlaier if (unit != 0) 413171168Smlaier return (EINVAL); 414171168Smlaier 415223637Sbz#ifndef __FreeBSD__ 416171168Smlaier pfsync_sync_ok = 1; 417223637Sbz#endif 418223637Sbz 419223637Sbz sc = malloc(sizeof(struct pfsync_softc), M_DEVBUF, M_NOWAIT | M_ZERO); 420223637Sbz if (sc == NULL) 421171168Smlaier return (ENOMEM); 422223637Sbz 423223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) 424223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 425223637Sbz 426171168Smlaier#ifdef __FreeBSD__ 427223637Sbz sc->pfsync_sync_ok = 1; 428223637Sbz sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, 429223637Sbz NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 430223637Sbz if (sc->sc_pool == NULL) { 431223637Sbz free(sc, M_DEVBUF); 432223637Sbz return (ENOMEM); 433171168Smlaier } 434223637Sbz#else 435223637Sbz pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL); 436223637Sbz#endif 437223637Sbz TAILQ_INIT(&sc->sc_upd_req_list); 438223637Sbz TAILQ_INIT(&sc->sc_deferrals); 439223637Sbz sc->sc_deferred = 0; 440171168Smlaier 441223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 442223637Sbz 443223637Sbz sc->sc_len = PFSYNC_MINPKT; 444223637Sbz sc->sc_maxupdates = 128; 445223637Sbz 446223637Sbz#ifdef __FreeBSD__ 447223637Sbz sc->sc_imo.imo_membership = (struct in_multi **)malloc( 448223637Sbz (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF, 449223637Sbz M_NOWAIT | M_ZERO); 450223637Sbz sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 451223637Sbz sc->sc_imo.imo_multicast_vif = -1; 452223637Sbz#else 453223637Sbz sc->sc_imo.imo_membership = (struct in_multi **)malloc( 454223637Sbz (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, 455223637Sbz M_WAITOK | M_ZERO); 456223637Sbz sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 457223637Sbz#endif 458223637Sbz 459223637Sbz#ifdef __FreeBSD__ 460223637Sbz ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 461147256Sbrooks if (ifp == NULL) { 462223637Sbz free(sc->sc_imo.imo_membership, M_DEVBUF); 463223637Sbz uma_zdestroy(sc->sc_pool); 464223637Sbz free(sc, M_DEVBUF); 465147256Sbrooks return (ENOSPC); 466147256Sbrooks } 467171168Smlaier if_initname(ifp, ifc->ifc_name, unit); 468126261Smlaier 469223637Sbz sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event, 470223637Sbz#ifdef __FreeBSD__ 471223637Sbz pfsync_ifdetach, V_pfsyncif, EVENTHANDLER_PRI_ANY); 472223637Sbz#else 473171168Smlaier pfsync_ifdetach, pfsyncif, EVENTHANDLER_PRI_ANY); 474223637Sbz#endif 475223637Sbz if (sc->sc_detachtag == NULL) { 476167710Sbms if_free(ifp); 477223637Sbz free(sc->sc_imo.imo_membership, M_DEVBUF); 478223637Sbz uma_zdestroy(sc->sc_pool); 479223637Sbz free(sc, M_DEVBUF); 480167710Sbms return (ENOSPC); 481167710Sbms } 482171168Smlaier#else 483223637Sbz ifp = &sc->sc_if; 484171168Smlaier snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); 485171168Smlaier#endif 486223637Sbz ifp->if_softc = sc; 487130613Smlaier ifp->if_ioctl = pfsyncioctl; 488130613Smlaier ifp->if_output = pfsyncoutput; 489130613Smlaier ifp->if_start = pfsyncstart; 490171168Smlaier ifp->if_type = IFT_PFSYNC; 491130613Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 492223637Sbz ifp->if_hdrlen = sizeof(struct pfsync_header); 493223637Sbz ifp->if_mtu = 1500; /* XXX */ 494171168Smlaier#ifdef __FreeBSD__ 495223637Sbz callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); 496223637Sbz callout_init(&sc->sc_bulk_tmo, CALLOUT_MPSAFE); 497223637Sbz callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE); 498171168Smlaier#else 499223637Sbz ifp->if_hardmtu = MCLBYTES; /* XXX */ 500223637Sbz timeout_set(&sc->sc_tmo, pfsync_timeout, sc); 501223637Sbz timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc); 502223637Sbz timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc); 503171168Smlaier#endif 504223637Sbz 505141584Smlaier if_attach(ifp); 506171168Smlaier#ifndef __FreeBSD__ 507171168Smlaier if_alloc_sadl(ifp); 508171168Smlaier#endif 509126261Smlaier 510171168Smlaier#if NCARP > 0 511171168Smlaier if_addgroup(ifp, "carp"); 512171168Smlaier#endif 513171168Smlaier 514126261Smlaier#if NBPFILTER > 0 515171168Smlaier#ifdef __FreeBSD__ 516141584Smlaier bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 517171168Smlaier#else 518223637Sbz bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 519126261Smlaier#endif 520171168Smlaier#endif 521126261Smlaier 522223637Sbz#ifdef __FreeBSD__ 523223637Sbz V_pfsyncif = sc; 524223637Sbz#else 525223637Sbz pfsyncif = sc; 526223637Sbz#endif 527223637Sbz 528126261Smlaier return (0); 529126261Smlaier} 530171168Smlaier 531171168Smlaier#ifdef __FreeBSD__ 532126261Smlaiervoid 533171168Smlaier#else 534171168Smlaierint 535171168Smlaier#endif 536171168Smlaierpfsync_clone_destroy(struct ifnet *ifp) 537126258Smlaier{ 538223637Sbz struct pfsync_softc *sc = ifp->if_softc; 539223637Sbz 540171168Smlaier#ifdef __FreeBSD__ 541223637Sbz EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag); 542171168Smlaier#endif 543223637Sbz timeout_del(&sc->sc_bulk_tmo); 544223637Sbz timeout_del(&sc->sc_tmo); 545223637Sbz#if NCARP > 0 546223637Sbz#ifdef notyet 547223637Sbz#ifdef __FreeBSD__ 548223637Sbz if (!sc->pfsync_sync_ok) 549223637Sbz#else 550223637Sbz if (!pfsync_sync_ok) 551171168Smlaier#endif 552223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 553223637Sbz#endif 554223637Sbz#endif 555126258Smlaier#if NBPFILTER > 0 556171168Smlaier bpfdetach(ifp); 557126258Smlaier#endif 558171168Smlaier if_detach(ifp); 559223637Sbz 560223637Sbz pfsync_drop(sc); 561223637Sbz 562223637Sbz while (sc->sc_deferred > 0) 563223637Sbz pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 564223637Sbz 565171168Smlaier#ifdef __FreeBSD__ 566223637Sbz UMA_DESTROY(sc->sc_pool); 567223637Sbz#else 568223637Sbz pool_destroy(&sc->sc_pool); 569223637Sbz#endif 570223637Sbz#ifdef __FreeBSD__ 571171168Smlaier if_free(ifp); 572223637Sbz free(sc->sc_imo.imo_membership, M_DEVBUF); 573223637Sbz#else 574223637Sbz free(sc->sc_imo.imo_membership, M_IPMOPTS); 575171168Smlaier#endif 576223637Sbz free(sc, M_DEVBUF); 577223637Sbz 578223637Sbz#ifdef __FreeBSD__ 579223637Sbz V_pfsyncif = NULL; 580223637Sbz#else 581171168Smlaier pfsyncif = NULL; 582223637Sbz#endif 583223637Sbz 584171168Smlaier#ifndef __FreeBSD__ 585171168Smlaier return (0); 586171168Smlaier#endif 587126258Smlaier} 588126258Smlaier 589223637Sbzstruct mbuf * 590223637Sbzpfsync_if_dequeue(struct ifnet *ifp) 591223637Sbz{ 592223637Sbz struct mbuf *m; 593223637Sbz#ifndef __FreeBSD__ 594223637Sbz int s; 595223637Sbz#endif 596223637Sbz 597223637Sbz#ifdef __FreeBSD__ 598223637Sbz IF_LOCK(&ifp->if_snd); 599223637Sbz _IF_DROP(&ifp->if_snd); 600223637Sbz _IF_DEQUEUE(&ifp->if_snd, m); 601223637Sbz IF_UNLOCK(&ifp->if_snd); 602223637Sbz#else 603223637Sbz s = splnet(); 604223637Sbz IF_DEQUEUE(&ifp->if_snd, m); 605223637Sbz splx(s); 606223637Sbz#endif 607223637Sbz 608223637Sbz return (m); 609223637Sbz} 610223637Sbz 611126258Smlaier/* 612126258Smlaier * Start output on the pfsync interface. 613126258Smlaier */ 614126258Smlaiervoid 615126258Smlaierpfsyncstart(struct ifnet *ifp) 616126258Smlaier{ 617126258Smlaier struct mbuf *m; 618223637Sbz 619223637Sbz while ((m = pfsync_if_dequeue(ifp)) != NULL) { 620171168Smlaier#ifndef __FreeBSD__ 621126258Smlaier IF_DROP(&ifp->if_snd); 622171168Smlaier#endif 623223637Sbz m_freem(m); 624126258Smlaier } 625126258Smlaier} 626126258Smlaier 627126258Smlaierint 628171168Smlaierpfsync_alloc_scrub_memory(struct pfsync_state_peer *s, 629171168Smlaier struct pf_state_peer *d) 630130613Smlaier{ 631171168Smlaier if (s->scrub.scrub_flag && d->scrub == NULL) { 632223637Sbz#ifdef __FreeBSD__ 633223637Sbz d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 634223637Sbz#else 635223637Sbz d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 636223637Sbz#endif 637171168Smlaier if (d->scrub == NULL) 638171168Smlaier return (ENOMEM); 639171168Smlaier } 640171168Smlaier 641171168Smlaier return (0); 642171168Smlaier} 643171168Smlaier 644223637Sbz#ifndef __FreeBSD__ 645223637Sbzvoid 646223637Sbzpfsync_state_export(struct pfsync_state *sp, struct pf_state *st) 647223637Sbz{ 648223637Sbz bzero(sp, sizeof(struct pfsync_state)); 649223637Sbz 650223637Sbz /* copy from state key */ 651223637Sbz sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; 652223637Sbz sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; 653223637Sbz sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; 654223637Sbz sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; 655223637Sbz sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; 656223637Sbz sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; 657223637Sbz sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; 658223637Sbz sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; 659223637Sbz sp->proto = st->key[PF_SK_WIRE]->proto; 660223637Sbz sp->af = st->key[PF_SK_WIRE]->af; 661223637Sbz 662223637Sbz /* copy from state */ 663223637Sbz strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); 664223637Sbz bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 665223637Sbz sp->creation = htonl(time_second - st->creation); 666223637Sbz sp->expire = pf_state_expires(st); 667223637Sbz if (sp->expire <= time_second) 668223637Sbz sp->expire = htonl(0); 669223637Sbz else 670223637Sbz sp->expire = htonl(sp->expire - time_second); 671223637Sbz 672223637Sbz sp->direction = st->direction; 673223637Sbz sp->log = st->log; 674223637Sbz sp->timeout = st->timeout; 675223637Sbz sp->state_flags = st->state_flags; 676223637Sbz if (st->src_node) 677223637Sbz sp->sync_flags |= PFSYNC_FLAG_SRCNODE; 678223637Sbz if (st->nat_src_node) 679223637Sbz sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; 680223637Sbz 681223637Sbz bcopy(&st->id, &sp->id, sizeof(sp->id)); 682223637Sbz sp->creatorid = st->creatorid; 683223637Sbz pf_state_peer_hton(&st->src, &sp->src); 684223637Sbz pf_state_peer_hton(&st->dst, &sp->dst); 685223637Sbz 686223637Sbz if (st->rule.ptr == NULL) 687223637Sbz sp->rule = htonl(-1); 688223637Sbz else 689223637Sbz sp->rule = htonl(st->rule.ptr->nr); 690223637Sbz if (st->anchor.ptr == NULL) 691223637Sbz sp->anchor = htonl(-1); 692223637Sbz else 693223637Sbz sp->anchor = htonl(st->anchor.ptr->nr); 694223637Sbz if (st->nat_rule.ptr == NULL) 695223637Sbz sp->nat_rule = htonl(-1); 696223637Sbz else 697223637Sbz sp->nat_rule = htonl(st->nat_rule.ptr->nr); 698223637Sbz 699223637Sbz pf_state_counter_hton(st->packets[0], sp->packets[0]); 700223637Sbz pf_state_counter_hton(st->packets[1], sp->packets[1]); 701223637Sbz pf_state_counter_hton(st->bytes[0], sp->bytes[0]); 702223637Sbz pf_state_counter_hton(st->bytes[1], sp->bytes[1]); 703223637Sbz 704223637Sbz} 705223637Sbz#endif 706223637Sbz 707171168Smlaierint 708223637Sbzpfsync_state_import(struct pfsync_state *sp, u_int8_t flags) 709171168Smlaier{ 710130613Smlaier struct pf_state *st = NULL; 711223637Sbz struct pf_state_key *skw = NULL, *sks = NULL; 712130613Smlaier struct pf_rule *r = NULL; 713130613Smlaier struct pfi_kif *kif; 714223637Sbz int pool_flags; 715223637Sbz int error; 716130613Smlaier 717223637Sbz#ifdef __FreeBSD__ 718223637Sbz if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) { 719223637Sbz#else 720130613Smlaier if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 721223637Sbz#endif 722223637Sbz printf("pfsync_state_import: invalid creator id:" 723130613Smlaier " %08x\n", ntohl(sp->creatorid)); 724130613Smlaier return (EINVAL); 725130613Smlaier } 726130613Smlaier 727223637Sbz if ((kif = pfi_kif_get(sp->ifname)) == NULL) { 728223637Sbz#ifdef __FreeBSD__ 729223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 730223637Sbz#else 731130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 732223637Sbz#endif 733223637Sbz printf("pfsync_state_import: " 734130613Smlaier "unknown interface: %s\n", sp->ifname); 735223637Sbz if (flags & PFSYNC_SI_IOCTL) 736223637Sbz return (EINVAL); 737223637Sbz return (0); /* skip this state */ 738130613Smlaier } 739130613Smlaier 740130613Smlaier /* 741223637Sbz * If the ruleset checksums match or the state is coming from the ioctl, 742223637Sbz * it's safe to associate the state with the rule of that number. 743130613Smlaier */ 744223637Sbz if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && 745223637Sbz (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < 746223637Sbz pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 747171168Smlaier r = pf_main_ruleset.rules[ 748171168Smlaier PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; 749171168Smlaier else 750223637Sbz#ifdef __FreeBSD__ 751223637Sbz r = &V_pf_default_rule; 752223637Sbz#else 753171168Smlaier r = &pf_default_rule; 754223637Sbz#endif 755130613Smlaier 756223637Sbz if ((r->max_states && r->states_cur >= r->max_states)) 757223637Sbz goto cleanup; 758130613Smlaier 759223637Sbz#ifdef __FreeBSD__ 760223637Sbz if (flags & PFSYNC_SI_IOCTL) 761223637Sbz pool_flags = PR_WAITOK | PR_ZERO; 762223637Sbz else 763223637Sbz pool_flags = PR_ZERO; 764171168Smlaier 765223637Sbz if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL) 766223637Sbz goto cleanup; 767223637Sbz#else 768223637Sbz if (flags & PFSYNC_SI_IOCTL) 769223637Sbz pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; 770223637Sbz else 771223637Sbz pool_flags = PR_LIMITFAIL | PR_ZERO; 772130613Smlaier 773223637Sbz if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) 774223637Sbz goto cleanup; 775223637Sbz#endif 776145836Smlaier 777223637Sbz if ((skw = pf_alloc_state_key(pool_flags)) == NULL) 778223637Sbz goto cleanup; 779130613Smlaier 780223637Sbz if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], 781223637Sbz &sp->key[PF_SK_STACK].addr[0], sp->af) || 782223637Sbz PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], 783223637Sbz &sp->key[PF_SK_STACK].addr[1], sp->af) || 784223637Sbz sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || 785223637Sbz sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { 786223637Sbz if ((sks = pf_alloc_state_key(pool_flags)) == NULL) 787223637Sbz goto cleanup; 788223637Sbz } else 789223637Sbz sks = skw; 790130613Smlaier 791223637Sbz /* allocate memory for scrub info */ 792223637Sbz if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || 793223637Sbz pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) 794223637Sbz goto cleanup; 795223637Sbz 796223637Sbz /* copy to state key(s) */ 797223637Sbz skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; 798223637Sbz skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; 799223637Sbz skw->port[0] = sp->key[PF_SK_WIRE].port[0]; 800223637Sbz skw->port[1] = sp->key[PF_SK_WIRE].port[1]; 801223637Sbz skw->proto = sp->proto; 802223637Sbz skw->af = sp->af; 803223637Sbz if (sks != skw) { 804223637Sbz sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; 805223637Sbz sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; 806223637Sbz sks->port[0] = sp->key[PF_SK_STACK].port[0]; 807223637Sbz sks->port[1] = sp->key[PF_SK_STACK].port[1]; 808223637Sbz sks->proto = sp->proto; 809223637Sbz sks->af = sp->af; 810223637Sbz } 811223637Sbz 812223637Sbz /* copy to state */ 813130613Smlaier bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 814145836Smlaier st->creation = time_second - ntohl(sp->creation); 815223637Sbz st->expire = time_second; 816223637Sbz if (sp->expire) { 817223637Sbz /* XXX No adaptive scaling. */ 818223637Sbz st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire); 819223637Sbz } 820223637Sbz 821130613Smlaier st->expire = ntohl(sp->expire) + time_second; 822130613Smlaier st->direction = sp->direction; 823130613Smlaier st->log = sp->log; 824130613Smlaier st->timeout = sp->timeout; 825200930Sdelphij st->state_flags = sp->state_flags; 826130613Smlaier 827130613Smlaier bcopy(sp->id, &st->id, sizeof(st->id)); 828130613Smlaier st->creatorid = sp->creatorid; 829223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 830223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 831130613Smlaier 832223637Sbz st->rule.ptr = r; 833223637Sbz st->nat_rule.ptr = NULL; 834223637Sbz st->anchor.ptr = NULL; 835223637Sbz st->rt_kif = NULL; 836223637Sbz 837223637Sbz st->pfsync_time = time_second; 838223637Sbz st->sync_state = PFSYNC_S_NONE; 839223637Sbz 840223637Sbz /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 841223637Sbz r->states_cur++; 842223637Sbz r->states_tot++; 843223637Sbz 844223637Sbz if (!ISSET(flags, PFSYNC_SI_IOCTL)) 845223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 846223637Sbz 847223637Sbz if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { 848145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 849223637Sbz r->states_cur--; 850223637Sbz goto cleanup_state; 851223637Sbz } 852223637Sbz 853223637Sbz if (!ISSET(flags, PFSYNC_SI_IOCTL)) { 854223637Sbz CLR(st->state_flags, PFSTATE_NOSYNC); 855223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) { 856223637Sbz pfsync_q_ins(st, PFSYNC_S_IACK); 857223637Sbz schednetisr(NETISR_PFSYNC); 858223637Sbz } 859223637Sbz } 860223637Sbz CLR(st->state_flags, PFSTATE_ACK); 861223637Sbz 862223637Sbz return (0); 863223637Sbz 864223637Sbzcleanup: 865223637Sbz error = ENOMEM; 866223637Sbz if (skw == sks) 867223637Sbz sks = NULL; 868223637Sbz#ifdef __FreeBSD__ 869223637Sbz if (skw != NULL) 870223637Sbz pool_put(&V_pf_state_key_pl, skw); 871223637Sbz if (sks != NULL) 872223637Sbz pool_put(&V_pf_state_key_pl, sks); 873223637Sbz#else 874223637Sbz if (skw != NULL) 875223637Sbz pool_put(&pf_state_key_pl, skw); 876223637Sbz if (sks != NULL) 877223637Sbz pool_put(&pf_state_key_pl, sks); 878223637Sbz#endif 879223637Sbz 880223637Sbzcleanup_state: /* pf_state_insert frees the state keys */ 881223637Sbz if (st) { 882223637Sbz#ifdef __FreeBSD__ 883171168Smlaier if (st->dst.scrub) 884223637Sbz pool_put(&V_pf_state_scrub_pl, st->dst.scrub); 885223637Sbz if (st->src.scrub) 886223637Sbz pool_put(&V_pf_state_scrub_pl, st->src.scrub); 887223637Sbz pool_put(&V_pf_state_pl, st); 888223637Sbz#else 889223637Sbz if (st->dst.scrub) 890171168Smlaier pool_put(&pf_state_scrub_pl, st->dst.scrub); 891171168Smlaier if (st->src.scrub) 892171168Smlaier pool_put(&pf_state_scrub_pl, st->src.scrub); 893130613Smlaier pool_put(&pf_state_pl, st); 894223637Sbz#endif 895130613Smlaier } 896223637Sbz return (error); 897130613Smlaier} 898130613Smlaier 899130613Smlaiervoid 900130613Smlaier#ifdef __FreeBSD__ 901130613Smlaierpfsync_input(struct mbuf *m, __unused int off) 902130613Smlaier#else 903130613Smlaierpfsync_input(struct mbuf *m, ...) 904130613Smlaier#endif 905130613Smlaier{ 906223637Sbz#ifdef __FreeBSD__ 907223637Sbz struct pfsync_softc *sc = V_pfsyncif; 908223637Sbz#else 909223637Sbz struct pfsync_softc *sc = pfsyncif; 910223637Sbz#endif 911223637Sbz struct pfsync_pkt pkt; 912130613Smlaier struct ip *ip = mtod(m, struct ip *); 913130613Smlaier struct pfsync_header *ph; 914223637Sbz struct pfsync_subheader subh; 915130613Smlaier 916223637Sbz int offset; 917223637Sbz int rv; 918130613Smlaier 919223637Sbz V_pfsyncstats.pfsyncs_ipackets++; 920223637Sbz 921130613Smlaier /* verify that we have a sync interface configured */ 922223637Sbz#ifdef __FreeBSD__ 923223637Sbz if (!sc || !sc->sc_sync_if || !V_pf_status.running) 924223637Sbz#else 925223637Sbz if (!sc || !sc->sc_sync_if || !pf_status.running) 926223637Sbz#endif 927130613Smlaier goto done; 928130613Smlaier 929130613Smlaier /* verify that the packet came in on the right interface */ 930223637Sbz if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 931223637Sbz V_pfsyncstats.pfsyncs_badif++; 932130613Smlaier goto done; 933130613Smlaier } 934130613Smlaier 935223637Sbz#ifdef __FreeBSD__ 936223637Sbz sc->sc_ifp->if_ipackets++; 937223637Sbz sc->sc_ifp->if_ibytes += m->m_pkthdr.len; 938223637Sbz#else 939223637Sbz sc->sc_if.if_ipackets++; 940223637Sbz sc->sc_if.if_ibytes += m->m_pkthdr.len; 941223637Sbz#endif 942223637Sbz /* verify that the IP TTL is 255. */ 943130613Smlaier if (ip->ip_ttl != PFSYNC_DFLTTL) { 944223637Sbz V_pfsyncstats.pfsyncs_badttl++; 945130613Smlaier goto done; 946130613Smlaier } 947130613Smlaier 948223637Sbz offset = ip->ip_hl << 2; 949223637Sbz if (m->m_pkthdr.len < offset + sizeof(*ph)) { 950223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 951130613Smlaier goto done; 952130613Smlaier } 953130613Smlaier 954223637Sbz if (offset + sizeof(*ph) > m->m_len) { 955223637Sbz if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 956223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 957223637Sbz return; 958130613Smlaier } 959130613Smlaier ip = mtod(m, struct ip *); 960130613Smlaier } 961223637Sbz ph = (struct pfsync_header *)((char *)ip + offset); 962130613Smlaier 963130613Smlaier /* verify the version */ 964130613Smlaier if (ph->version != PFSYNC_VERSION) { 965223637Sbz V_pfsyncstats.pfsyncs_badver++; 966130613Smlaier goto done; 967130613Smlaier } 968130613Smlaier 969223637Sbz#if 0 970223637Sbz if (pfsync_input_hmac(m, offset) != 0) { 971223637Sbz /* XXX stats */ 972130613Smlaier goto done; 973130613Smlaier } 974223637Sbz#endif 975130613Smlaier 976130613Smlaier /* Cheaper to grab this now than having to mess with mbufs later */ 977223637Sbz pkt.ip = ip; 978223637Sbz pkt.src = ip->ip_src; 979223637Sbz pkt.flags = 0; 980130613Smlaier 981223637Sbz#ifdef __FreeBSD__ 982223637Sbz if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 983223637Sbz#else 984223637Sbz if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 985223637Sbz#endif 986223637Sbz pkt.flags |= PFSYNC_SI_CKSUM; 987171168Smlaier 988223637Sbz offset += sizeof(*ph); 989223637Sbz for (;;) { 990223637Sbz m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 991223637Sbz offset += sizeof(subh); 992223637Sbz 993223637Sbz if (subh.action >= PFSYNC_ACT_MAX) { 994223637Sbz V_pfsyncstats.pfsyncs_badact++; 995223637Sbz goto done; 996130613Smlaier } 997130613Smlaier 998223637Sbz rv = (*pfsync_acts[subh.action])(&pkt, m, offset, 999223637Sbz ntohs(subh.count)); 1000223637Sbz if (rv == -1) 1001223637Sbz return; 1002223637Sbz 1003223637Sbz offset += rv; 1004223637Sbz } 1005223637Sbz 1006223637Sbzdone: 1007223637Sbz m_freem(m); 1008223637Sbz} 1009223637Sbz 1010223637Sbzint 1011223637Sbzpfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1012223637Sbz{ 1013223637Sbz struct pfsync_clr *clr; 1014223637Sbz struct mbuf *mp; 1015223637Sbz int len = sizeof(*clr) * count; 1016223637Sbz int i, offp; 1017223637Sbz 1018223637Sbz struct pf_state *st, *nexts; 1019223637Sbz struct pf_state_key *sk, *nextsk; 1020223637Sbz struct pf_state_item *si; 1021223637Sbz u_int32_t creatorid; 1022223637Sbz int s; 1023223637Sbz 1024223637Sbz mp = m_pulldown(m, offset, len, &offp); 1025223637Sbz if (mp == NULL) { 1026223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1027223637Sbz return (-1); 1028223637Sbz } 1029223637Sbz clr = (struct pfsync_clr *)(mp->m_data + offp); 1030223637Sbz 1031223637Sbz s = splsoftnet(); 1032130613Smlaier#ifdef __FreeBSD__ 1033223637Sbz PF_LOCK(); 1034130613Smlaier#endif 1035223637Sbz for (i = 0; i < count; i++) { 1036223637Sbz creatorid = clr[i].creatorid; 1037223637Sbz 1038223637Sbz if (clr[i].ifname[0] == '\0') { 1039223637Sbz#ifdef __FreeBSD__ 1040223637Sbz for (st = RB_MIN(pf_state_tree_id, &V_tree_id); 1041223637Sbz st; st = nexts) { 1042223637Sbz nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st); 1043223637Sbz#else 1044145836Smlaier for (st = RB_MIN(pf_state_tree_id, &tree_id); 1045145836Smlaier st; st = nexts) { 1046171168Smlaier nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 1047223637Sbz#endif 1048145836Smlaier if (st->creatorid == creatorid) { 1049223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1050171168Smlaier pf_unlink_state(st); 1051145836Smlaier } 1052130613Smlaier } 1053130613Smlaier } else { 1054223637Sbz if (pfi_kif_get(clr[i].ifname) == NULL) 1055223637Sbz continue; 1056223637Sbz 1057223637Sbz /* XXX correct? */ 1058130613Smlaier#ifdef __FreeBSD__ 1059223637Sbz for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl); 1060223637Sbz#else 1061223637Sbz for (sk = RB_MIN(pf_state_tree, &pf_statetbl); 1062130613Smlaier#endif 1063223637Sbz sk; sk = nextsk) { 1064223637Sbz nextsk = RB_NEXT(pf_state_tree, 1065223637Sbz#ifdef __FreeBSD__ 1066223637Sbz &V_pf_statetbl, sk); 1067223637Sbz#else 1068223637Sbz &pf_statetbl, sk); 1069223637Sbz#endif 1070223637Sbz TAILQ_FOREACH(si, &sk->states, entry) { 1071223637Sbz if (si->s->creatorid == creatorid) { 1072223637Sbz SET(si->s->state_flags, 1073223637Sbz PFSTATE_NOSYNC); 1074223637Sbz pf_unlink_state(si->s); 1075223637Sbz } 1076145836Smlaier } 1077130613Smlaier } 1078130613Smlaier } 1079223637Sbz } 1080130613Smlaier#ifdef __FreeBSD__ 1081223637Sbz PF_UNLOCK(); 1082130613Smlaier#endif 1083223637Sbz splx(s); 1084130613Smlaier 1085223637Sbz return (len); 1086223637Sbz} 1087223637Sbz 1088223637Sbzint 1089223637Sbzpfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1090223637Sbz{ 1091223637Sbz struct mbuf *mp; 1092223637Sbz struct pfsync_state *sa, *sp; 1093223637Sbz int len = sizeof(*sp) * count; 1094223637Sbz int i, offp; 1095223637Sbz 1096223637Sbz int s; 1097223637Sbz 1098223637Sbz mp = m_pulldown(m, offset, len, &offp); 1099223637Sbz if (mp == NULL) { 1100223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1101223637Sbz return (-1); 1102130613Smlaier } 1103223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1104130613Smlaier 1105223637Sbz s = splsoftnet(); 1106130613Smlaier#ifdef __FreeBSD__ 1107223637Sbz PF_LOCK(); 1108130613Smlaier#endif 1109223637Sbz for (i = 0; i < count; i++) { 1110223637Sbz sp = &sa[i]; 1111130613Smlaier 1112223637Sbz /* check for invalid values */ 1113223637Sbz if (sp->timeout >= PFTM_MAX || 1114223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 1115223637Sbz sp->dst.state > PF_TCPS_PROXY_DST || 1116223637Sbz sp->direction > PF_OUT || 1117223637Sbz (sp->af != AF_INET && sp->af != AF_INET6)) { 1118130613Smlaier#ifdef __FreeBSD__ 1119223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1120223637Sbz#else 1121223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1122130613Smlaier#endif 1123223637Sbz printf("pfsync_input: PFSYNC5_ACT_INS: " 1124223637Sbz "invalid value\n"); 1125130613Smlaier } 1126223637Sbz V_pfsyncstats.pfsyncs_badval++; 1127223637Sbz continue; 1128130613Smlaier } 1129223637Sbz 1130223637Sbz if (pfsync_state_import(sp, pkt->flags) == ENOMEM) { 1131223637Sbz /* drop out, but process the rest of the actions */ 1132223637Sbz break; 1133223637Sbz } 1134223637Sbz } 1135130613Smlaier#ifdef __FreeBSD__ 1136223637Sbz PF_UNLOCK(); 1137130613Smlaier#endif 1138223637Sbz splx(s); 1139130613Smlaier 1140223637Sbz return (len); 1141223637Sbz} 1142223637Sbz 1143223637Sbzint 1144223637Sbzpfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1145223637Sbz{ 1146223637Sbz struct pfsync_ins_ack *ia, *iaa; 1147223637Sbz struct pf_state_cmp id_key; 1148223637Sbz struct pf_state *st; 1149223637Sbz 1150223637Sbz struct mbuf *mp; 1151223637Sbz int len = count * sizeof(*ia); 1152223637Sbz int offp, i; 1153223637Sbz int s; 1154223637Sbz 1155223637Sbz mp = m_pulldown(m, offset, len, &offp); 1156223637Sbz if (mp == NULL) { 1157223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1158223637Sbz return (-1); 1159223637Sbz } 1160223637Sbz iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 1161223637Sbz 1162223637Sbz s = splsoftnet(); 1163130613Smlaier#ifdef __FreeBSD__ 1164223637Sbz PF_LOCK(); 1165130613Smlaier#endif 1166223637Sbz for (i = 0; i < count; i++) { 1167223637Sbz ia = &iaa[i]; 1168145836Smlaier 1169223637Sbz bcopy(&ia->id, &id_key.id, sizeof(id_key.id)); 1170223637Sbz id_key.creatorid = ia->creatorid; 1171130613Smlaier 1172223637Sbz st = pf_find_state_byid(&id_key); 1173223637Sbz if (st == NULL) 1174223637Sbz continue; 1175130613Smlaier 1176223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1177223637Sbz pfsync_deferred(st, 0); 1178223637Sbz } 1179130613Smlaier#ifdef __FreeBSD__ 1180223637Sbz PF_UNLOCK(); 1181130613Smlaier#endif 1182223637Sbz splx(s); 1183130613Smlaier /* 1184223637Sbz * XXX this is not yet implemented, but we know the size of the 1185223637Sbz * message so we can skip it. 1186130613Smlaier */ 1187130613Smlaier 1188223637Sbz return (count * sizeof(struct pfsync_ins_ack)); 1189223637Sbz} 1190223637Sbz 1191223637Sbzint 1192223637Sbzpfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, 1193223637Sbz struct pfsync_state_peer *dst) 1194223637Sbz{ 1195223637Sbz int sfail = 0; 1196223637Sbz 1197223637Sbz /* 1198223637Sbz * The state should never go backwards except 1199223637Sbz * for syn-proxy states. Neither should the 1200223637Sbz * sequence window slide backwards. 1201223637Sbz */ 1202223637Sbz if (st->src.state > src->state && 1203223637Sbz (st->src.state < PF_TCPS_PROXY_SRC || 1204223637Sbz src->state >= PF_TCPS_PROXY_SRC)) 1205223637Sbz sfail = 1; 1206223637Sbz else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo))) 1207223637Sbz sfail = 3; 1208223637Sbz else if (st->dst.state > dst->state) { 1209223637Sbz /* There might still be useful 1210223637Sbz * information about the src state here, 1211223637Sbz * so import that part of the update, 1212223637Sbz * then "fail" so we send the updated 1213223637Sbz * state back to the peer who is missing 1214223637Sbz * our what we know. */ 1215223637Sbz pf_state_peer_ntoh(src, &st->src); 1216223637Sbz /* XXX do anything with timeouts? */ 1217223637Sbz sfail = 7; 1218223637Sbz } else if (st->dst.state >= TCPS_SYN_SENT && 1219223637Sbz SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo))) 1220223637Sbz sfail = 4; 1221223637Sbz 1222223637Sbz return (sfail); 1223223637Sbz} 1224223637Sbz 1225223637Sbzint 1226223637Sbzpfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1227223637Sbz{ 1228223637Sbz struct pfsync_state *sa, *sp; 1229223637Sbz struct pf_state_cmp id_key; 1230223637Sbz struct pf_state_key *sk; 1231223637Sbz struct pf_state *st; 1232223637Sbz int sfail; 1233223637Sbz 1234223637Sbz struct mbuf *mp; 1235223637Sbz int len = count * sizeof(*sp); 1236223637Sbz int offp, i; 1237223637Sbz int s; 1238223637Sbz 1239223637Sbz mp = m_pulldown(m, offset, len, &offp); 1240223637Sbz if (mp == NULL) { 1241223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1242223637Sbz return (-1); 1243223637Sbz } 1244223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1245223637Sbz 1246223637Sbz s = splsoftnet(); 1247130613Smlaier#ifdef __FreeBSD__ 1248223637Sbz PF_LOCK(); 1249130613Smlaier#endif 1250223637Sbz for (i = 0; i < count; i++) { 1251223637Sbz sp = &sa[i]; 1252130613Smlaier 1253223637Sbz /* check for invalid values */ 1254223637Sbz if (sp->timeout >= PFTM_MAX || 1255223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 1256223637Sbz sp->dst.state > PF_TCPS_PROXY_DST) { 1257223637Sbz#ifdef __FreeBSD__ 1258223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1259223637Sbz#else 1260223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1261223637Sbz#endif 1262223637Sbz printf("pfsync_input: PFSYNC_ACT_UPD: " 1263223637Sbz "invalid value\n"); 1264130613Smlaier } 1265223637Sbz V_pfsyncstats.pfsyncs_badval++; 1266223637Sbz continue; 1267130613Smlaier } 1268223637Sbz 1269223637Sbz bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1270223637Sbz id_key.creatorid = sp->creatorid; 1271223637Sbz 1272223637Sbz st = pf_find_state_byid(&id_key); 1273223637Sbz if (st == NULL) { 1274223637Sbz /* insert the update */ 1275223637Sbz if (pfsync_state_import(sp, 0)) 1276223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1277223637Sbz continue; 1278223637Sbz } 1279223637Sbz 1280223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1281223637Sbz pfsync_deferred(st, 1); 1282223637Sbz 1283223637Sbz sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1284223637Sbz sfail = 0; 1285223637Sbz if (sk->proto == IPPROTO_TCP) 1286223637Sbz sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst); 1287223637Sbz else { 1288223637Sbz /* 1289223637Sbz * Non-TCP protocol state machine always go 1290223637Sbz * forwards 1291223637Sbz */ 1292223637Sbz if (st->src.state > sp->src.state) 1293223637Sbz sfail = 5; 1294223637Sbz else if (st->dst.state > sp->dst.state) 1295223637Sbz sfail = 6; 1296223637Sbz } 1297223637Sbz 1298223637Sbz if (sfail) { 1299130613Smlaier#ifdef __FreeBSD__ 1300223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1301223637Sbz#else 1302223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1303130613Smlaier#endif 1304223637Sbz printf("pfsync: %s stale update (%d)" 1305223637Sbz " id: %016llx creatorid: %08x\n", 1306223637Sbz (sfail < 7 ? "ignoring" : "partial"), 1307223637Sbz sfail, betoh64(st->id), 1308223637Sbz ntohl(st->creatorid)); 1309223637Sbz } 1310223637Sbz V_pfsyncstats.pfsyncs_stale++; 1311130613Smlaier 1312223637Sbz pfsync_update_state(st); 1313223637Sbz schednetisr(NETISR_PFSYNC); 1314223637Sbz continue; 1315130613Smlaier } 1316223637Sbz pfsync_alloc_scrub_memory(&sp->dst, &st->dst); 1317223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 1318223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 1319223637Sbz st->expire = ntohl(sp->expire) + time_second; 1320223637Sbz st->timeout = sp->timeout; 1321223637Sbz st->pfsync_time = time_second; 1322223637Sbz } 1323223637Sbz#ifdef __FreeBSD__ 1324223637Sbz PF_UNLOCK(); 1325223637Sbz#endif 1326223637Sbz splx(s); 1327130613Smlaier 1328223637Sbz return (len); 1329223637Sbz} 1330223637Sbz 1331223637Sbzint 1332223637Sbzpfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1333223637Sbz{ 1334223637Sbz struct pfsync_upd_c *ua, *up; 1335223637Sbz struct pf_state_key *sk; 1336223637Sbz struct pf_state_cmp id_key; 1337223637Sbz struct pf_state *st; 1338223637Sbz 1339223637Sbz int len = count * sizeof(*up); 1340223637Sbz int sfail; 1341223637Sbz 1342223637Sbz struct mbuf *mp; 1343223637Sbz int offp, i; 1344223637Sbz int s; 1345223637Sbz 1346223637Sbz mp = m_pulldown(m, offset, len, &offp); 1347223637Sbz if (mp == NULL) { 1348223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1349223637Sbz return (-1); 1350223637Sbz } 1351223637Sbz ua = (struct pfsync_upd_c *)(mp->m_data + offp); 1352223637Sbz 1353223637Sbz s = splsoftnet(); 1354130613Smlaier#ifdef __FreeBSD__ 1355223637Sbz PF_LOCK(); 1356130613Smlaier#endif 1357223637Sbz for (i = 0; i < count; i++) { 1358223637Sbz up = &ua[i]; 1359223637Sbz 1360223637Sbz /* check for invalid values */ 1361223637Sbz if (up->timeout >= PFTM_MAX || 1362223637Sbz up->src.state > PF_TCPS_PROXY_DST || 1363223637Sbz up->dst.state > PF_TCPS_PROXY_DST) { 1364223637Sbz#ifdef __FreeBSD__ 1365223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1366223637Sbz#else 1367223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1368223637Sbz#endif 1369223637Sbz printf("pfsync_input: " 1370223637Sbz "PFSYNC_ACT_UPD_C: " 1371223637Sbz "invalid value\n"); 1372130613Smlaier } 1373223637Sbz V_pfsyncstats.pfsyncs_badval++; 1374223637Sbz continue; 1375223637Sbz } 1376130613Smlaier 1377223637Sbz bcopy(&up->id, &id_key.id, sizeof(id_key.id)); 1378223637Sbz id_key.creatorid = up->creatorid; 1379130613Smlaier 1380223637Sbz st = pf_find_state_byid(&id_key); 1381223637Sbz if (st == NULL) { 1382223637Sbz /* We don't have this state. Ask for it. */ 1383223637Sbz pfsync_request_update(id_key.creatorid, id_key.id); 1384223637Sbz continue; 1385223637Sbz } 1386223637Sbz 1387223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 1388223637Sbz pfsync_deferred(st, 1); 1389223637Sbz 1390223637Sbz sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1391223637Sbz sfail = 0; 1392223637Sbz if (sk->proto == IPPROTO_TCP) 1393223637Sbz sfail = pfsync_upd_tcp(st, &up->src, &up->dst); 1394223637Sbz else { 1395223637Sbz /* 1396223637Sbz * Non-TCP protocol state machine always go forwards 1397223637Sbz */ 1398223637Sbz if (st->src.state > up->src.state) 1399223637Sbz sfail = 5; 1400223637Sbz else if (st->dst.state > up->dst.state) 1401223637Sbz sfail = 6; 1402223637Sbz } 1403223637Sbz 1404223637Sbz if (sfail) { 1405171168Smlaier#ifdef __FreeBSD__ 1406223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1407223637Sbz#else 1408223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 1409171168Smlaier#endif 1410223637Sbz printf("pfsync: ignoring stale update " 1411223637Sbz "(%d) id: %016llx " 1412223637Sbz "creatorid: %08x\n", sfail, 1413223637Sbz betoh64(st->id), 1414223637Sbz ntohl(st->creatorid)); 1415130613Smlaier } 1416223637Sbz V_pfsyncstats.pfsyncs_stale++; 1417145836Smlaier 1418223637Sbz pfsync_update_state(st); 1419223637Sbz schednetisr(NETISR_PFSYNC); 1420223637Sbz continue; 1421130613Smlaier } 1422223637Sbz pfsync_alloc_scrub_memory(&up->dst, &st->dst); 1423223637Sbz pf_state_peer_ntoh(&up->src, &st->src); 1424223637Sbz pf_state_peer_ntoh(&up->dst, &st->dst); 1425223637Sbz st->expire = ntohl(up->expire) + time_second; 1426223637Sbz st->timeout = up->timeout; 1427223637Sbz st->pfsync_time = time_second; 1428223637Sbz } 1429130613Smlaier#ifdef __FreeBSD__ 1430223637Sbz PF_UNLOCK(); 1431130613Smlaier#endif 1432223637Sbz splx(s); 1433223637Sbz 1434223637Sbz return (len); 1435223637Sbz} 1436223637Sbz 1437223637Sbzint 1438223637Sbzpfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1439223637Sbz{ 1440223637Sbz struct pfsync_upd_req *ur, *ura; 1441223637Sbz struct mbuf *mp; 1442223637Sbz int len = count * sizeof(*ur); 1443223637Sbz int i, offp; 1444223637Sbz 1445223637Sbz struct pf_state_cmp id_key; 1446223637Sbz struct pf_state *st; 1447223637Sbz 1448223637Sbz mp = m_pulldown(m, offset, len, &offp); 1449223637Sbz if (mp == NULL) { 1450223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1451223637Sbz return (-1); 1452130613Smlaier } 1453223637Sbz ura = (struct pfsync_upd_req *)(mp->m_data + offp); 1454130613Smlaier 1455223637Sbz for (i = 0; i < count; i++) { 1456223637Sbz ur = &ura[i]; 1457130613Smlaier 1458223637Sbz bcopy(&ur->id, &id_key.id, sizeof(id_key.id)); 1459223637Sbz id_key.creatorid = ur->creatorid; 1460223637Sbz 1461223637Sbz if (id_key.id == 0 && id_key.creatorid == 0) 1462223637Sbz pfsync_bulk_start(); 1463223637Sbz else { 1464223637Sbz st = pf_find_state_byid(&id_key); 1465130613Smlaier if (st == NULL) { 1466223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1467130613Smlaier continue; 1468130613Smlaier } 1469223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) 1470223637Sbz continue; 1471223637Sbz 1472223637Sbz pfsync_update_state_req(st); 1473130613Smlaier } 1474223637Sbz } 1475223637Sbz 1476223637Sbz return (len); 1477223637Sbz} 1478223637Sbz 1479223637Sbzint 1480223637Sbzpfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1481223637Sbz{ 1482223637Sbz struct mbuf *mp; 1483223637Sbz struct pfsync_state *sa, *sp; 1484223637Sbz struct pf_state_cmp id_key; 1485223637Sbz struct pf_state *st; 1486223637Sbz int len = count * sizeof(*sp); 1487223637Sbz int offp, i; 1488223637Sbz int s; 1489223637Sbz 1490223637Sbz mp = m_pulldown(m, offset, len, &offp); 1491223637Sbz if (mp == NULL) { 1492223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1493223637Sbz return (-1); 1494223637Sbz } 1495223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1496223637Sbz 1497223637Sbz s = splsoftnet(); 1498130613Smlaier#ifdef __FreeBSD__ 1499223637Sbz PF_LOCK(); 1500130613Smlaier#endif 1501223637Sbz for (i = 0; i < count; i++) { 1502223637Sbz sp = &sa[i]; 1503223637Sbz 1504223637Sbz bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1505223637Sbz id_key.creatorid = sp->creatorid; 1506223637Sbz 1507223637Sbz st = pf_find_state_byid(&id_key); 1508223637Sbz if (st == NULL) { 1509223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1510223637Sbz continue; 1511130613Smlaier } 1512223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1513223637Sbz pf_unlink_state(st); 1514223637Sbz } 1515223637Sbz#ifdef __FreeBSD__ 1516223637Sbz PF_UNLOCK(); 1517223637Sbz#endif 1518223637Sbz splx(s); 1519130613Smlaier 1520223637Sbz return (len); 1521223637Sbz} 1522223637Sbz 1523223637Sbzint 1524223637Sbzpfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1525223637Sbz{ 1526223637Sbz struct mbuf *mp; 1527223637Sbz struct pfsync_del_c *sa, *sp; 1528223637Sbz struct pf_state_cmp id_key; 1529223637Sbz struct pf_state *st; 1530223637Sbz int len = count * sizeof(*sp); 1531223637Sbz int offp, i; 1532223637Sbz int s; 1533223637Sbz 1534223637Sbz mp = m_pulldown(m, offset, len, &offp); 1535223637Sbz if (mp == NULL) { 1536223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1537223637Sbz return (-1); 1538223637Sbz } 1539223637Sbz sa = (struct pfsync_del_c *)(mp->m_data + offp); 1540223637Sbz 1541223637Sbz s = splsoftnet(); 1542130613Smlaier#ifdef __FreeBSD__ 1543223637Sbz PF_LOCK(); 1544130613Smlaier#endif 1545223637Sbz for (i = 0; i < count; i++) { 1546223637Sbz sp = &sa[i]; 1547130613Smlaier 1548223637Sbz bcopy(&sp->id, &id_key.id, sizeof(id_key.id)); 1549223637Sbz id_key.creatorid = sp->creatorid; 1550223637Sbz 1551223637Sbz st = pf_find_state_byid(&id_key); 1552223637Sbz if (st == NULL) { 1553223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1554223637Sbz continue; 1555223637Sbz } 1556223637Sbz 1557223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 1558223637Sbz pf_unlink_state(st); 1559223637Sbz } 1560130613Smlaier#ifdef __FreeBSD__ 1561223637Sbz PF_LOCK(); 1562223637Sbz#endif 1563223637Sbz splx(s); 1564223637Sbz 1565223637Sbz return (len); 1566223637Sbz} 1567223637Sbz 1568223637Sbzint 1569223637Sbzpfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1570223637Sbz{ 1571223637Sbz#ifdef __FreeBSD__ 1572223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1573130613Smlaier#else 1574223637Sbz struct pfsync_softc *sc = pfsyncif; 1575130613Smlaier#endif 1576223637Sbz struct pfsync_bus *bus; 1577223637Sbz struct mbuf *mp; 1578223637Sbz int len = count * sizeof(*bus); 1579223637Sbz int offp; 1580223637Sbz 1581223637Sbz /* If we're not waiting for a bulk update, who cares. */ 1582223637Sbz if (sc->sc_ureq_sent == 0) 1583223637Sbz return (len); 1584223637Sbz 1585223637Sbz mp = m_pulldown(m, offset, len, &offp); 1586223637Sbz if (mp == NULL) { 1587223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1588223637Sbz return (-1); 1589223637Sbz } 1590223637Sbz bus = (struct pfsync_bus *)(mp->m_data + offp); 1591223637Sbz 1592223637Sbz switch (bus->status) { 1593223637Sbz case PFSYNC_BUS_START: 1594130613Smlaier#ifdef __FreeBSD__ 1595223637Sbz callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, 1596223637Sbz V_pfsyncif); 1597223637Sbz#else 1598223637Sbz timeout_add_sec(&sc->sc_bulkfail_tmo, 5); /* XXX magic */ 1599130613Smlaier#endif 1600223637Sbz#ifdef XXX 1601223637Sbz pf_pool_limits[PF_LIMIT_STATES].limit / 1602223637Sbz (PFSYNC_BULKPACKETS * sc->sc_maxcount)); 1603223637Sbz#endif 1604223637Sbz#ifdef __FreeBSD__ 1605223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1606223637Sbz#else 1607223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1608223637Sbz#endif 1609223637Sbz printf("pfsync: received bulk update start\n"); 1610130613Smlaier break; 1611130613Smlaier 1612223637Sbz case PFSYNC_BUS_END: 1613223637Sbz if (time_uptime - ntohl(bus->endtime) >= 1614223637Sbz sc->sc_ureq_sent) { 1615223637Sbz /* that's it, we're happy */ 1616223637Sbz sc->sc_ureq_sent = 0; 1617223637Sbz sc->sc_bulk_tries = 0; 1618223637Sbz timeout_del(&sc->sc_bulkfail_tmo); 1619223637Sbz#if NCARP > 0 1620223637Sbz#ifdef notyet 1621130613Smlaier#ifdef __FreeBSD__ 1622223637Sbz if (!sc->pfsync_sync_ok) 1623130613Smlaier#else 1624223637Sbz if (!pfsync_sync_ok) 1625130613Smlaier#endif 1626223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 1627223637Sbz#endif 1628223637Sbz#endif 1629130613Smlaier#ifdef __FreeBSD__ 1630223637Sbz sc->pfsync_sync_ok = 1; 1631223637Sbz#else 1632223637Sbz pfsync_sync_ok = 1; 1633171168Smlaier#endif 1634223637Sbz#ifdef __FreeBSD__ 1635223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1636130613Smlaier#else 1637223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1638130613Smlaier#endif 1639223637Sbz printf("pfsync: received valid " 1640223637Sbz "bulk update end\n"); 1641223637Sbz } else { 1642223637Sbz#ifdef __FreeBSD__ 1643223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1644223637Sbz#else 1645223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1646145836Smlaier#endif 1647223637Sbz printf("pfsync: received invalid " 1648223637Sbz "bulk update end: bad timestamp\n"); 1649130613Smlaier } 1650130613Smlaier break; 1651223637Sbz } 1652223637Sbz 1653223637Sbz return (len); 1654223637Sbz} 1655223637Sbz 1656223637Sbzint 1657223637Sbzpfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1658223637Sbz{ 1659223637Sbz int len = count * sizeof(struct pfsync_tdb); 1660223637Sbz 1661223637Sbz#if defined(IPSEC) 1662223637Sbz struct pfsync_tdb *tp; 1663223637Sbz struct mbuf *mp; 1664223637Sbz int offp; 1665223637Sbz int i; 1666223637Sbz int s; 1667223637Sbz 1668223637Sbz mp = m_pulldown(m, offset, len, &offp); 1669223637Sbz if (mp == NULL) { 1670223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1671223637Sbz return (-1); 1672223637Sbz } 1673223637Sbz tp = (struct pfsync_tdb *)(mp->m_data + offp); 1674223637Sbz 1675223637Sbz s = splsoftnet(); 1676171168Smlaier#ifdef __FreeBSD__ 1677223637Sbz PF_LOCK(); 1678171168Smlaier#endif 1679223637Sbz for (i = 0; i < count; i++) 1680223637Sbz pfsync_update_net_tdb(&tp[i]); 1681171168Smlaier#ifdef __FreeBSD__ 1682223637Sbz PF_UNLOCK(); 1683171168Smlaier#endif 1684223637Sbz splx(s); 1685171168Smlaier#endif 1686223637Sbz 1687223637Sbz return (len); 1688223637Sbz} 1689223637Sbz 1690223637Sbz#if defined(IPSEC) 1691223637Sbz/* Update an in-kernel tdb. Silently fail if no tdb is found. */ 1692223637Sbzvoid 1693223637Sbzpfsync_update_net_tdb(struct pfsync_tdb *pt) 1694223637Sbz{ 1695223637Sbz struct tdb *tdb; 1696223637Sbz int s; 1697223637Sbz 1698223637Sbz /* check for invalid values */ 1699223637Sbz if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 1700223637Sbz (pt->dst.sa.sa_family != AF_INET && 1701223637Sbz pt->dst.sa.sa_family != AF_INET6)) 1702223637Sbz goto bad; 1703223637Sbz 1704223637Sbz s = spltdb(); 1705223637Sbz tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 1706223637Sbz if (tdb) { 1707223637Sbz pt->rpl = ntohl(pt->rpl); 1708223637Sbz pt->cur_bytes = betoh64(pt->cur_bytes); 1709223637Sbz 1710223637Sbz /* Neither replay nor byte counter should ever decrease. */ 1711223637Sbz if (pt->rpl < tdb->tdb_rpl || 1712223637Sbz pt->cur_bytes < tdb->tdb_cur_bytes) { 1713223637Sbz splx(s); 1714223637Sbz goto bad; 1715223637Sbz } 1716223637Sbz 1717223637Sbz tdb->tdb_rpl = pt->rpl; 1718223637Sbz tdb->tdb_cur_bytes = pt->cur_bytes; 1719130613Smlaier } 1720223637Sbz splx(s); 1721223637Sbz return; 1722130613Smlaier 1723223637Sbzbad: 1724223637Sbz#ifdef __FreeBSD__ 1725223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1726223637Sbz#else 1727223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 1728223637Sbz#endif 1729223637Sbz printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 1730223637Sbz "invalid value\n"); 1731223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1732223637Sbz return; 1733130613Smlaier} 1734223637Sbz#endif 1735130613Smlaier 1736223637Sbz 1737130613Smlaierint 1738223637Sbzpfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1739223637Sbz{ 1740223637Sbz /* check if we are at the right place in the packet */ 1741223637Sbz if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof)) 1742223637Sbz V_pfsyncstats.pfsyncs_badact++; 1743223637Sbz 1744223637Sbz /* we're done. free and let the caller return */ 1745223637Sbz m_freem(m); 1746223637Sbz return (-1); 1747223637Sbz} 1748223637Sbz 1749223637Sbzint 1750223637Sbzpfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1751223637Sbz{ 1752223637Sbz V_pfsyncstats.pfsyncs_badact++; 1753223637Sbz 1754223637Sbz m_freem(m); 1755223637Sbz return (-1); 1756223637Sbz} 1757223637Sbz 1758223637Sbzint 1759126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 1760223637Sbz#ifdef __FreeBSD__ 1761223637Sbz struct route *rt) 1762223637Sbz#else 1763223637Sbz struct rtentry *rt) 1764223637Sbz#endif 1765126258Smlaier{ 1766126258Smlaier m_freem(m); 1767126258Smlaier return (0); 1768126258Smlaier} 1769126258Smlaier 1770126258Smlaier/* ARGSUSED */ 1771126258Smlaierint 1772126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1773126258Smlaier{ 1774130613Smlaier#ifndef __FreeBSD__ 1775130613Smlaier struct proc *p = curproc; 1776130613Smlaier#endif 1777126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1778126258Smlaier struct ifreq *ifr = (struct ifreq *)data; 1779130613Smlaier struct ip_moptions *imo = &sc->sc_imo; 1780130613Smlaier struct pfsyncreq pfsyncr; 1781130613Smlaier struct ifnet *sifp; 1782223637Sbz struct ip *ip; 1783130613Smlaier int s, error; 1784126258Smlaier 1785126258Smlaier switch (cmd) { 1786223637Sbz#if 0 1787126258Smlaier case SIOCSIFADDR: 1788126258Smlaier case SIOCAIFADDR: 1789126258Smlaier case SIOCSIFDSTADDR: 1790223637Sbz#endif 1791126258Smlaier case SIOCSIFFLAGS: 1792148891Smlaier#ifdef __FreeBSD__ 1793126258Smlaier if (ifp->if_flags & IFF_UP) 1794148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1795126258Smlaier else 1796148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1797148891Smlaier#else 1798148891Smlaier if (ifp->if_flags & IFF_UP) 1799148891Smlaier ifp->if_flags |= IFF_RUNNING; 1800148891Smlaier else 1801148891Smlaier ifp->if_flags &= ~IFF_RUNNING; 1802148891Smlaier#endif 1803126258Smlaier break; 1804126258Smlaier case SIOCSIFMTU: 1805223637Sbz if (ifr->ifr_mtu <= PFSYNC_MINPKT) 1806126258Smlaier return (EINVAL); 1807223637Sbz if (ifr->ifr_mtu > MCLBYTES) /* XXX could be bigger */ 1808126258Smlaier ifr->ifr_mtu = MCLBYTES; 1809223637Sbz if (ifr->ifr_mtu < ifp->if_mtu) { 1810223637Sbz s = splnet(); 1811130613Smlaier#ifdef __FreeBSD__ 1812223637Sbz PF_LOCK(); 1813130613Smlaier#endif 1814223637Sbz pfsync_sendout(); 1815130613Smlaier#ifdef __FreeBSD__ 1816223637Sbz PF_UNLOCK(); 1817130613Smlaier#endif 1818223637Sbz splx(s); 1819223637Sbz } 1820223637Sbz ifp->if_mtu = ifr->ifr_mtu; 1821126258Smlaier break; 1822130613Smlaier case SIOCGETPFSYNC: 1823130613Smlaier bzero(&pfsyncr, sizeof(pfsyncr)); 1824223637Sbz if (sc->sc_sync_if) { 1825145836Smlaier strlcpy(pfsyncr.pfsyncr_syncdev, 1826223637Sbz sc->sc_sync_if->if_xname, IFNAMSIZ); 1827223637Sbz } 1828145836Smlaier pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1829130613Smlaier pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1830223637Sbz return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); 1831223637Sbz 1832130613Smlaier case SIOCSETPFSYNC: 1833130613Smlaier#ifdef __FreeBSD__ 1834164033Srwatson if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1835130613Smlaier#else 1836130613Smlaier if ((error = suser(p, p->p_acflag)) != 0) 1837130613Smlaier#endif 1838130613Smlaier return (error); 1839130613Smlaier if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1840130613Smlaier return (error); 1841130613Smlaier 1842171168Smlaier#ifdef __FreeBSD__ 1843171168Smlaier PF_LOCK(); 1844171168Smlaier#endif 1845145836Smlaier if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1846159603Smlaier#ifdef __FreeBSD__ 1847159603Smlaier sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1848159603Smlaier#else 1849145836Smlaier sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1850159603Smlaier#endif 1851145836Smlaier else 1852145836Smlaier sc->sc_sync_peer.s_addr = 1853145836Smlaier pfsyncr.pfsyncr_syncpeer.s_addr; 1854145836Smlaier 1855130613Smlaier if (pfsyncr.pfsyncr_maxupdates > 255) 1856171168Smlaier#ifdef __FreeBSD__ 1857171168Smlaier { 1858171168Smlaier PF_UNLOCK(); 1859171168Smlaier#endif 1860130613Smlaier return (EINVAL); 1861130613Smlaier#ifdef __FreeBSD__ 1862171168Smlaier } 1863130613Smlaier#endif 1864130613Smlaier sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1865130613Smlaier 1866145836Smlaier if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1867223637Sbz sc->sc_sync_if = NULL; 1868171168Smlaier#ifdef __FreeBSD__ 1869171168Smlaier PF_UNLOCK(); 1870171168Smlaier#endif 1871145836Smlaier if (imo->imo_num_memberships > 0) { 1872223637Sbz in_delmulti(imo->imo_membership[ 1873223637Sbz --imo->imo_num_memberships]); 1874145836Smlaier imo->imo_multicast_ifp = NULL; 1875145836Smlaier } 1876130613Smlaier break; 1877130613Smlaier } 1878145836Smlaier 1879130613Smlaier#ifdef __FreeBSD__ 1880171168Smlaier PF_UNLOCK(); 1881130613Smlaier#endif 1882171168Smlaier if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) 1883130613Smlaier return (EINVAL); 1884223637Sbz 1885171168Smlaier#ifdef __FreeBSD__ 1886171168Smlaier PF_LOCK(); 1887171168Smlaier#endif 1888130613Smlaier s = splnet(); 1889141584Smlaier#ifdef __FreeBSD__ 1890171168Smlaier if (sifp->if_mtu < sc->sc_ifp->if_mtu || 1891141584Smlaier#else 1892130613Smlaier if (sifp->if_mtu < sc->sc_if.if_mtu || 1893141584Smlaier#endif 1894223637Sbz (sc->sc_sync_if != NULL && 1895223637Sbz sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1896130613Smlaier sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1897223637Sbz pfsync_sendout(); 1898223637Sbz sc->sc_sync_if = sifp; 1899130613Smlaier 1900130613Smlaier if (imo->imo_num_memberships > 0) { 1901171168Smlaier#ifdef __FreeBSD__ 1902171168Smlaier PF_UNLOCK(); 1903171168Smlaier#endif 1904130613Smlaier in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1905171168Smlaier#ifdef __FreeBSD__ 1906171168Smlaier PF_LOCK(); 1907171168Smlaier#endif 1908130613Smlaier imo->imo_multicast_ifp = NULL; 1909130613Smlaier } 1910130613Smlaier 1911223637Sbz if (sc->sc_sync_if && 1912159603Smlaier#ifdef __FreeBSD__ 1913159603Smlaier sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1914159603Smlaier#else 1915145836Smlaier sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1916159603Smlaier#endif 1917130613Smlaier struct in_addr addr; 1918130613Smlaier 1919223637Sbz if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 1920223637Sbz sc->sc_sync_if = NULL; 1921130613Smlaier#ifdef __FreeBSD__ 1922145836Smlaier PF_UNLOCK(); 1923145836Smlaier#endif 1924145836Smlaier splx(s); 1925145836Smlaier return (EADDRNOTAVAIL); 1926145836Smlaier } 1927171168Smlaier 1928145836Smlaier#ifdef __FreeBSD__ 1929130613Smlaier addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1930130613Smlaier#else 1931130613Smlaier addr.s_addr = INADDR_PFSYNC_GROUP; 1932130613Smlaier#endif 1933145836Smlaier 1934171168Smlaier#ifdef __FreeBSD__ 1935171168Smlaier PF_UNLOCK(); 1936171168Smlaier#endif 1937130613Smlaier if ((imo->imo_membership[0] = 1938223637Sbz in_addmulti(&addr, sc->sc_sync_if)) == NULL) { 1939223637Sbz sc->sc_sync_if = NULL; 1940130613Smlaier splx(s); 1941130613Smlaier return (ENOBUFS); 1942130613Smlaier } 1943171168Smlaier#ifdef __FreeBSD__ 1944171168Smlaier PF_LOCK(); 1945171168Smlaier#endif 1946130613Smlaier imo->imo_num_memberships++; 1947223637Sbz imo->imo_multicast_ifp = sc->sc_sync_if; 1948130613Smlaier imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1949130613Smlaier imo->imo_multicast_loop = 0; 1950145836Smlaier } 1951130613Smlaier 1952223637Sbz ip = &sc->sc_template; 1953223637Sbz bzero(ip, sizeof(*ip)); 1954223637Sbz ip->ip_v = IPVERSION; 1955223637Sbz ip->ip_hl = sizeof(sc->sc_template) >> 2; 1956223637Sbz ip->ip_tos = IPTOS_LOWDELAY; 1957223637Sbz /* len and id are set later */ 1958223637Sbz ip->ip_off = htons(IP_DF); 1959223637Sbz ip->ip_ttl = PFSYNC_DFLTTL; 1960223637Sbz ip->ip_p = IPPROTO_PFSYNC; 1961223637Sbz ip->ip_src.s_addr = INADDR_ANY; 1962223637Sbz ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; 1963223637Sbz 1964223637Sbz if (sc->sc_sync_if) { 1965130613Smlaier /* Request a full state table update. */ 1966130613Smlaier sc->sc_ureq_sent = time_uptime; 1967145836Smlaier#if NCARP > 0 1968223637Sbz#ifdef notyet 1969223637Sbz#ifdef __FreeBSD__ 1970223637Sbz if (sc->pfsync_sync_ok) 1971223637Sbz#else 1972145836Smlaier if (pfsync_sync_ok) 1973130613Smlaier#endif 1974171168Smlaier carp_group_demote_adj(&sc->sc_if, 1); 1975171168Smlaier#endif 1976171168Smlaier#endif 1977223637Sbz#ifdef __FreeBSD__ 1978223637Sbz sc->pfsync_sync_ok = 0; 1979223637Sbz#else 1980130613Smlaier pfsync_sync_ok = 0; 1981223637Sbz#endif 1982223637Sbz#ifdef __FreeBSD__ 1983223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1984223637Sbz#else 1985130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1986223637Sbz#endif 1987130613Smlaier printf("pfsync: requesting bulk update\n"); 1988130613Smlaier#ifdef __FreeBSD__ 1989223637Sbz callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 1990223637Sbz pfsync_bulk_fail, V_pfsyncif); 1991130613Smlaier#else 1992223637Sbz timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 1993130613Smlaier#endif 1994223637Sbz pfsync_request_update(0, 0); 1995130613Smlaier } 1996130613Smlaier#ifdef __FreeBSD__ 1997130613Smlaier PF_UNLOCK(); 1998130613Smlaier#endif 1999130613Smlaier splx(s); 2000130613Smlaier 2001130613Smlaier break; 2002130613Smlaier 2003126258Smlaier default: 2004126258Smlaier return (ENOTTY); 2005126258Smlaier } 2006126258Smlaier 2007126258Smlaier return (0); 2008126258Smlaier} 2009126258Smlaier 2010223637Sbzint 2011223637Sbzpfsync_out_state(struct pf_state *st, struct mbuf *m, int offset) 2012130613Smlaier{ 2013223637Sbz struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset); 2014130613Smlaier 2015223637Sbz pfsync_state_export(sp, st); 2016223637Sbz 2017223637Sbz return (sizeof(*sp)); 2018223637Sbz} 2019223637Sbz 2020223637Sbzint 2021223637Sbzpfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset) 2022223637Sbz{ 2023223637Sbz struct pfsync_ins_ack *iack = 2024223637Sbz (struct pfsync_ins_ack *)(m->m_data + offset); 2025223637Sbz 2026223637Sbz iack->id = st->id; 2027223637Sbz iack->creatorid = st->creatorid; 2028223637Sbz 2029223637Sbz return (sizeof(*iack)); 2030223637Sbz} 2031223637Sbz 2032223637Sbzint 2033223637Sbzpfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset) 2034223637Sbz{ 2035223637Sbz struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset); 2036223637Sbz 2037223637Sbz up->id = st->id; 2038223637Sbz pf_state_peer_hton(&st->src, &up->src); 2039223637Sbz pf_state_peer_hton(&st->dst, &up->dst); 2040223637Sbz up->creatorid = st->creatorid; 2041223637Sbz 2042223637Sbz up->expire = pf_state_expires(st); 2043223637Sbz if (up->expire <= time_second) 2044223637Sbz up->expire = htonl(0); 2045130613Smlaier else 2046223637Sbz up->expire = htonl(up->expire - time_second); 2047223637Sbz up->timeout = st->timeout; 2048130613Smlaier 2049223637Sbz bzero(up->_pad, sizeof(up->_pad)); /* XXX */ 2050223637Sbz 2051223637Sbz return (sizeof(*up)); 2052223637Sbz} 2053223637Sbz 2054223637Sbzint 2055223637Sbzpfsync_out_del(struct pf_state *st, struct mbuf *m, int offset) 2056223637Sbz{ 2057223637Sbz struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset); 2058223637Sbz 2059223637Sbz dp->id = st->id; 2060223637Sbz dp->creatorid = st->creatorid; 2061223637Sbz 2062223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 2063223637Sbz 2064223637Sbz return (sizeof(*dp)); 2065223637Sbz} 2066223637Sbz 2067223637Sbzvoid 2068223637Sbzpfsync_drop(struct pfsync_softc *sc) 2069223637Sbz{ 2070223637Sbz struct pf_state *st; 2071223637Sbz struct pfsync_upd_req_item *ur; 2072223637Sbz#ifdef notyet 2073223637Sbz struct tdb *t; 2074223637Sbz#endif 2075223637Sbz int q; 2076223637Sbz 2077223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 2078223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2079223637Sbz continue; 2080223637Sbz 2081223637Sbz TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2082223637Sbz#ifdef PFSYNC_DEBUG 2083141584Smlaier#ifdef __FreeBSD__ 2084223637Sbz KASSERT(st->sync_state == q, 2085223637Sbz ("%s: st->sync_state == q", 2086223637Sbz __FUNCTION__)); 2087141584Smlaier#else 2088223637Sbz KASSERT(st->sync_state == q); 2089171168Smlaier#endif 2090223637Sbz#endif 2091223637Sbz st->sync_state = PFSYNC_S_NONE; 2092223637Sbz } 2093223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 2094223637Sbz } 2095223637Sbz 2096223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2097223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2098223637Sbz pool_put(&sc->sc_pool, ur); 2099223637Sbz } 2100223637Sbz 2101223637Sbz sc->sc_plus = NULL; 2102223637Sbz 2103223637Sbz#ifdef notyet 2104223637Sbz if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2105223637Sbz TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) 2106223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2107223637Sbz 2108223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 2109223637Sbz } 2110223637Sbz#endif 2111223637Sbz 2112223637Sbz sc->sc_len = PFSYNC_MINPKT; 2113126258Smlaier} 2114126258Smlaier 2115223637Sbzvoid 2116223637Sbzpfsync_sendout(void) 2117126258Smlaier{ 2118223637Sbz#ifdef __FreeBSD__ 2119223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2120223637Sbz#else 2121223637Sbz struct pfsync_softc *sc = pfsyncif; 2122223637Sbz#endif 2123223637Sbz#if NBPFILTER > 0 2124223637Sbz#ifdef __FreeBSD__ 2125223637Sbz struct ifnet *ifp = sc->sc_ifp; 2126223637Sbz#else 2127223637Sbz struct ifnet *ifp = &sc->sc_if; 2128223637Sbz#endif 2129126258Smlaier struct mbuf *m; 2130223637Sbz#endif 2131223637Sbz struct ip *ip; 2132223637Sbz struct pfsync_header *ph; 2133223637Sbz struct pfsync_subheader *subh; 2134223637Sbz struct pf_state *st; 2135223637Sbz struct pfsync_upd_req_item *ur; 2136223637Sbz#ifdef notyet 2137223637Sbz struct tdb *t; 2138223637Sbz#endif 2139223637Sbz#ifdef __FreeBSD__ 2140223637Sbz size_t pktlen; 2141223637Sbz#endif 2142223637Sbz int offset; 2143223637Sbz int q, count = 0; 2144126258Smlaier 2145223637Sbz#ifdef __FreeBSD__ 2146223637Sbz PF_ASSERT(MA_OWNED); 2147223637Sbz#else 2148223637Sbz splassert(IPL_NET); 2149223637Sbz#endif 2150223637Sbz 2151223637Sbz if (sc == NULL || sc->sc_len == PFSYNC_MINPKT) 2152223637Sbz return; 2153223637Sbz 2154223637Sbz#if NBPFILTER > 0 2155223637Sbz if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { 2156223637Sbz#else 2157223637Sbz if (sc->sc_sync_if == NULL) { 2158223637Sbz#endif 2159223637Sbz pfsync_drop(sc); 2160223637Sbz return; 2161223637Sbz } 2162223637Sbz 2163126258Smlaier MGETHDR(m, M_DONTWAIT, MT_DATA); 2164126258Smlaier if (m == NULL) { 2165141584Smlaier#ifdef __FreeBSD__ 2166171168Smlaier sc->sc_ifp->if_oerrors++; 2167141584Smlaier#else 2168126258Smlaier sc->sc_if.if_oerrors++; 2169141584Smlaier#endif 2170223637Sbz V_pfsyncstats.pfsyncs_onomem++; 2171223637Sbz pfsync_drop(sc); 2172223637Sbz return; 2173126258Smlaier } 2174126258Smlaier 2175223637Sbz#ifdef __FreeBSD__ 2176223637Sbz pktlen = max_linkhdr + sc->sc_len; 2177223637Sbz if (pktlen > MHLEN) { 2178223637Sbz /* Find the right pool to allocate from. */ 2179223637Sbz /* XXX: This is ugly. */ 2180223637Sbz m_cljget(m, M_DONTWAIT, pktlen <= MSIZE ? MSIZE : 2181223637Sbz pktlen <= MCLBYTES ? MCLBYTES : 2182223637Sbz#if MJUMPAGESIZE != MCLBYTES 2183223637Sbz pktlen <= MJUMPAGESIZE ? MJUMPAGESIZE : 2184171168Smlaier#endif 2185223637Sbz pktlen <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); 2186223637Sbz#else 2187223637Sbz if (max_linkhdr + sc->sc_len > MHLEN) { 2188223637Sbz MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len); 2189223637Sbz#endif 2190223637Sbz if (!ISSET(m->m_flags, M_EXT)) { 2191126258Smlaier m_free(m); 2192141584Smlaier#ifdef __FreeBSD__ 2193171168Smlaier sc->sc_ifp->if_oerrors++; 2194141584Smlaier#else 2195126258Smlaier sc->sc_if.if_oerrors++; 2196141584Smlaier#endif 2197223637Sbz V_pfsyncstats.pfsyncs_onomem++; 2198223637Sbz pfsync_drop(sc); 2199223637Sbz return; 2200126258Smlaier } 2201223637Sbz } 2202223637Sbz m->m_data += max_linkhdr; 2203223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 2204130613Smlaier 2205223637Sbz /* build the ip header */ 2206223637Sbz ip = (struct ip *)m->m_data; 2207223637Sbz bcopy(&sc->sc_template, ip, sizeof(*ip)); 2208223637Sbz offset = sizeof(*ip); 2209126258Smlaier 2210223637Sbz ip->ip_len = htons(m->m_pkthdr.len); 2211223637Sbz ip->ip_id = htons(ip_randomid()); 2212126258Smlaier 2213223637Sbz /* build the pfsync header */ 2214223637Sbz ph = (struct pfsync_header *)(m->m_data + offset); 2215223637Sbz bzero(ph, sizeof(*ph)); 2216223637Sbz offset += sizeof(*ph); 2217126258Smlaier 2218223637Sbz ph->version = PFSYNC_VERSION; 2219223637Sbz ph->len = htons(sc->sc_len - sizeof(*ip)); 2220130613Smlaier#ifdef __FreeBSD__ 2221223637Sbz bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2222171168Smlaier#else 2223223637Sbz bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2224130613Smlaier#endif 2225171168Smlaier 2226223637Sbz /* walk the queues */ 2227223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 2228223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2229223637Sbz continue; 2230223637Sbz 2231223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2232223637Sbz offset += sizeof(*subh); 2233223637Sbz 2234223637Sbz count = 0; 2235223637Sbz TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2236223637Sbz#ifdef PFSYNC_DEBUG 2237159603Smlaier#ifdef __FreeBSD__ 2238223637Sbz KASSERT(st->sync_state == q, 2239223637Sbz ("%s: st->sync_state == q", 2240223637Sbz __FUNCTION__)); 2241159603Smlaier#else 2242223637Sbz KASSERT(st->sync_state == q); 2243159603Smlaier#endif 2244223637Sbz#endif 2245130613Smlaier 2246223637Sbz offset += pfsync_qs[q].write(st, m, offset); 2247223637Sbz st->sync_state = PFSYNC_S_NONE; 2248223637Sbz count++; 2249126258Smlaier } 2250223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 2251130613Smlaier 2252223637Sbz bzero(subh, sizeof(*subh)); 2253223637Sbz subh->action = pfsync_qs[q].action; 2254223637Sbz subh->count = htons(count); 2255126258Smlaier } 2256126258Smlaier 2257223637Sbz if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { 2258223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2259223637Sbz offset += sizeof(*subh); 2260126258Smlaier 2261223637Sbz count = 0; 2262223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2263223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2264130613Smlaier 2265223637Sbz bcopy(&ur->ur_msg, m->m_data + offset, 2266223637Sbz sizeof(ur->ur_msg)); 2267223637Sbz offset += sizeof(ur->ur_msg); 2268130613Smlaier 2269223637Sbz pool_put(&sc->sc_pool, ur); 2270130613Smlaier 2271223637Sbz count++; 2272223637Sbz } 2273130613Smlaier 2274223637Sbz bzero(subh, sizeof(*subh)); 2275223637Sbz subh->action = PFSYNC_ACT_UPD_REQ; 2276223637Sbz subh->count = htons(count); 2277223637Sbz } 2278130613Smlaier 2279223637Sbz /* has someone built a custom region for us to add? */ 2280223637Sbz if (sc->sc_plus != NULL) { 2281223637Sbz bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); 2282223637Sbz offset += sc->sc_pluslen; 2283130613Smlaier 2284223637Sbz sc->sc_plus = NULL; 2285130613Smlaier } 2286130613Smlaier 2287223637Sbz#ifdef notyet 2288223637Sbz if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2289223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2290223637Sbz offset += sizeof(*subh); 2291126258Smlaier 2292223637Sbz count = 0; 2293223637Sbz TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) { 2294223637Sbz offset += pfsync_out_tdb(t, m, offset); 2295223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2296126258Smlaier 2297223637Sbz count++; 2298130613Smlaier } 2299223637Sbz TAILQ_INIT(&sc->sc_tdb_q); 2300223637Sbz 2301223637Sbz bzero(subh, sizeof(*subh)); 2302223637Sbz subh->action = PFSYNC_ACT_TDB; 2303223637Sbz subh->count = htons(count); 2304130613Smlaier } 2305223637Sbz#endif 2306130613Smlaier 2307223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 2308223637Sbz offset += sizeof(*subh); 2309130613Smlaier 2310223637Sbz bzero(subh, sizeof(*subh)); 2311223637Sbz subh->action = PFSYNC_ACT_EOF; 2312223637Sbz subh->count = htons(1); 2313130613Smlaier 2314223637Sbz /* XXX write checksum in EOF here */ 2315130613Smlaier 2316223637Sbz /* we're done, let's put it on the wire */ 2317223637Sbz#if NBPFILTER > 0 2318223637Sbz if (ifp->if_bpf) { 2319223637Sbz m->m_data += sizeof(*ip); 2320223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); 2321223637Sbz#ifdef __FreeBSD__ 2322223637Sbz BPF_MTAP(ifp, m); 2323223637Sbz#else 2324223637Sbz bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 2325223637Sbz#endif 2326223637Sbz m->m_data -= sizeof(*ip); 2327223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 2328130613Smlaier } 2329130613Smlaier 2330223637Sbz if (sc->sc_sync_if == NULL) { 2331223637Sbz sc->sc_len = PFSYNC_MINPKT; 2332223637Sbz m_freem(m); 2333223637Sbz return; 2334223637Sbz } 2335223637Sbz#endif 2336126258Smlaier 2337223637Sbz#ifdef __FreeBSD__ 2338223637Sbz sc->sc_ifp->if_opackets++; 2339223637Sbz sc->sc_ifp->if_obytes += m->m_pkthdr.len; 2340223637Sbz#else 2341223637Sbz sc->sc_if.if_opackets++; 2342223637Sbz sc->sc_if.if_obytes += m->m_pkthdr.len; 2343223637Sbz#endif 2344223637Sbz 2345223637Sbz#ifdef __FreeBSD__ 2346223637Sbz PF_UNLOCK(); 2347223637Sbz#endif 2348223637Sbz if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0) 2349223637Sbz#ifdef __FreeBSD__ 2350223637Sbz { 2351223637Sbz PF_LOCK(); 2352223637Sbz#endif 2353223637Sbz V_pfsyncstats.pfsyncs_opackets++; 2354223637Sbz#ifdef __FreeBSD__ 2355223637Sbz } 2356223637Sbz#endif 2357223637Sbz else 2358223637Sbz#ifdef __FreeBSD__ 2359223637Sbz { 2360223637Sbz PF_LOCK(); 2361223637Sbz#endif 2362223637Sbz V_pfsyncstats.pfsyncs_oerrors++; 2363223637Sbz#ifdef __FreeBSD__ 2364223637Sbz } 2365223637Sbz#endif 2366223637Sbz 2367223637Sbz /* start again */ 2368223637Sbz sc->sc_len = PFSYNC_MINPKT; 2369126258Smlaier} 2370126258Smlaier 2371223637Sbzvoid 2372223637Sbzpfsync_insert_state(struct pf_state *st) 2373126258Smlaier{ 2374223637Sbz#ifdef __FreeBSD__ 2375223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2376223637Sbz#else 2377171168Smlaier struct pfsync_softc *sc = pfsyncif; 2378223637Sbz#endif 2379130613Smlaier 2380130613Smlaier#ifdef __FreeBSD__ 2381223637Sbz PF_ASSERT(MA_OWNED); 2382171168Smlaier#else 2383223637Sbz splassert(IPL_SOFTNET); 2384126261Smlaier#endif 2385130613Smlaier 2386223637Sbz if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) || 2387223637Sbz st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 2388223637Sbz SET(st->state_flags, PFSTATE_NOSYNC); 2389223637Sbz return; 2390130613Smlaier } 2391130613Smlaier 2392223637Sbz if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC)) 2393223637Sbz return; 2394130613Smlaier 2395223637Sbz#ifdef PFSYNC_DEBUG 2396223637Sbz#ifdef __FreeBSD__ 2397223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 2398223637Sbz ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2399223637Sbz#else 2400223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE); 2401223637Sbz#endif 2402223637Sbz#endif 2403223637Sbz 2404223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2405223637Sbz#ifdef __FreeBSD__ 2406223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2407223637Sbz V_pfsyncif); 2408223637Sbz#else 2409223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2410223637Sbz#endif 2411223637Sbz 2412223637Sbz pfsync_q_ins(st, PFSYNC_S_INS); 2413223637Sbz 2414223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2415223637Sbz schednetisr(NETISR_PFSYNC); 2416223637Sbz else 2417223637Sbz st->sync_updates = 0; 2418130613Smlaier} 2419130613Smlaier 2420223637Sbzint defer = 10; 2421223637Sbz 2422130613Smlaierint 2423223637Sbzpfsync_defer(struct pf_state *st, struct mbuf *m) 2424130613Smlaier{ 2425223637Sbz#ifdef __FreeBSD__ 2426223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2427223637Sbz#else 2428171168Smlaier struct pfsync_softc *sc = pfsyncif; 2429223637Sbz#endif 2430223637Sbz struct pfsync_deferral *pd; 2431126258Smlaier 2432223637Sbz#ifdef __FreeBSD__ 2433223637Sbz PF_ASSERT(MA_OWNED); 2434223637Sbz#else 2435223637Sbz splassert(IPL_SOFTNET); 2436223637Sbz#endif 2437223637Sbz 2438223637Sbz if (sc->sc_deferred >= 128) 2439223637Sbz pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 2440223637Sbz 2441223637Sbz pd = pool_get(&sc->sc_pool, M_NOWAIT); 2442223637Sbz if (pd == NULL) 2443171168Smlaier return (0); 2444223637Sbz sc->sc_deferred++; 2445171168Smlaier 2446130613Smlaier#ifdef __FreeBSD__ 2447223637Sbz m->m_flags |= M_SKIP_FIREWALL; 2448171168Smlaier#else 2449223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2450171168Smlaier#endif 2451223637Sbz SET(st->state_flags, PFSTATE_ACK); 2452223637Sbz 2453223637Sbz pd->pd_st = st; 2454223637Sbz pd->pd_m = m; 2455223637Sbz 2456223637Sbz TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); 2457171168Smlaier#ifdef __FreeBSD__ 2458223637Sbz callout_init(&pd->pd_tmo, CALLOUT_MPSAFE); 2459223637Sbz callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo, 2460223637Sbz pd); 2461223637Sbz#else 2462223637Sbz timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd); 2463223637Sbz timeout_add(&pd->pd_tmo, defer); 2464130613Smlaier#endif 2465126258Smlaier 2466223637Sbz return (1); 2467126258Smlaier} 2468126258Smlaier 2469126258Smlaiervoid 2470223637Sbzpfsync_undefer(struct pfsync_deferral *pd, int drop) 2471126258Smlaier{ 2472223637Sbz#ifdef __FreeBSD__ 2473223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2474223637Sbz#else 2475223637Sbz struct pfsync_softc *sc = pfsyncif; 2476223637Sbz#endif 2477126258Smlaier int s; 2478126258Smlaier 2479130613Smlaier#ifdef __FreeBSD__ 2480223637Sbz PF_ASSERT(MA_OWNED); 2481223637Sbz#else 2482223637Sbz splassert(IPL_SOFTNET); 2483130613Smlaier#endif 2484223637Sbz 2485223637Sbz TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 2486223637Sbz sc->sc_deferred--; 2487223637Sbz 2488223637Sbz CLR(pd->pd_st->state_flags, PFSTATE_ACK); 2489223637Sbz timeout_del(&pd->pd_tmo); /* bah */ 2490223637Sbz if (drop) 2491223637Sbz m_freem(pd->pd_m); 2492223637Sbz else { 2493223637Sbz s = splnet(); 2494130613Smlaier#ifdef __FreeBSD__ 2495223637Sbz /* XXX: use pf_defered?! */ 2496223637Sbz PF_UNLOCK(); 2497130613Smlaier#endif 2498223637Sbz ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0, 2499223637Sbz (void *)NULL, (void *)NULL); 2500223637Sbz#ifdef __FreeBSD__ 2501223637Sbz PF_LOCK(); 2502223637Sbz#endif 2503223637Sbz splx(s); 2504223637Sbz } 2505223637Sbz 2506223637Sbz pool_put(&sc->sc_pool, pd); 2507126258Smlaier} 2508126258Smlaier 2509171168Smlaiervoid 2510223637Sbzpfsync_defer_tmo(void *arg) 2511171168Smlaier{ 2512223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE) 2513223637Sbz struct pfsync_deferral *pd = arg; 2514223637Sbz#endif 2515171168Smlaier int s; 2516171168Smlaier 2517223637Sbz s = splsoftnet(); 2518171168Smlaier#ifdef __FreeBSD__ 2519223637Sbz CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */ 2520171168Smlaier PF_LOCK(); 2521171168Smlaier#endif 2522223637Sbz pfsync_undefer(arg, 0); 2523171168Smlaier#ifdef __FreeBSD__ 2524171168Smlaier PF_UNLOCK(); 2525223637Sbz CURVNET_RESTORE(); 2526171168Smlaier#endif 2527171168Smlaier splx(s); 2528171168Smlaier} 2529223637Sbz 2530223637Sbzvoid 2531223637Sbzpfsync_deferred(struct pf_state *st, int drop) 2532223637Sbz{ 2533223637Sbz#ifdef __FreeBSD__ 2534223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2535223637Sbz#else 2536223637Sbz struct pfsync_softc *sc = pfsyncif; 2537171168Smlaier#endif 2538223637Sbz struct pfsync_deferral *pd; 2539171168Smlaier 2540223637Sbz TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { 2541223637Sbz if (pd->pd_st == st) { 2542223637Sbz pfsync_undefer(pd, drop); 2543223637Sbz return; 2544223637Sbz } 2545223637Sbz } 2546223637Sbz 2547223637Sbz panic("pfsync_send_deferred: unable to find deferred state"); 2548223637Sbz} 2549223637Sbz 2550223637Sbzu_int pfsync_upds = 0; 2551223637Sbz 2552130613Smlaiervoid 2553223637Sbzpfsync_update_state(struct pf_state *st) 2554130613Smlaier{ 2555223637Sbz#ifdef __FreeBSD__ 2556223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2557223637Sbz#else 2558223637Sbz struct pfsync_softc *sc = pfsyncif; 2559223637Sbz#endif 2560223637Sbz int sync = 0; 2561130613Smlaier 2562130613Smlaier#ifdef __FreeBSD__ 2563130613Smlaier PF_ASSERT(MA_OWNED); 2564223637Sbz#else 2565223637Sbz splassert(IPL_SOFTNET); 2566130613Smlaier#endif 2567130613Smlaier 2568223637Sbz if (sc == NULL) 2569223637Sbz return; 2570223637Sbz 2571223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2572223637Sbz pfsync_deferred(st, 0); 2573223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2574223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2575223637Sbz pfsync_q_del(st); 2576223637Sbz return; 2577130613Smlaier } 2578223637Sbz 2579223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2580223637Sbz#ifdef __FreeBSD__ 2581223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2582223637Sbz V_pfsyncif); 2583223637Sbz#else 2584223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2585223637Sbz#endif 2586223637Sbz 2587223637Sbz switch (st->sync_state) { 2588223637Sbz case PFSYNC_S_UPD_C: 2589223637Sbz case PFSYNC_S_UPD: 2590223637Sbz case PFSYNC_S_INS: 2591223637Sbz /* we're already handling it */ 2592223637Sbz 2593223637Sbz st->sync_updates++; 2594223637Sbz if (st->sync_updates >= sc->sc_maxupdates) 2595223637Sbz sync = 1; 2596223637Sbz break; 2597223637Sbz 2598223637Sbz case PFSYNC_S_IACK: 2599223637Sbz pfsync_q_del(st); 2600223637Sbz case PFSYNC_S_NONE: 2601223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD_C); 2602223637Sbz st->sync_updates = 0; 2603223637Sbz break; 2604223637Sbz 2605223637Sbz default: 2606223637Sbz panic("pfsync_update_state: unexpected sync state %d", 2607223637Sbz st->sync_state); 2608223637Sbz } 2609223637Sbz 2610223637Sbz if (sync || (time_second - st->pfsync_time) < 2) { 2611223637Sbz pfsync_upds++; 2612223637Sbz schednetisr(NETISR_PFSYNC); 2613223637Sbz } 2614130613Smlaier} 2615130613Smlaier 2616130613Smlaiervoid 2617223637Sbzpfsync_request_update(u_int32_t creatorid, u_int64_t id) 2618130613Smlaier{ 2619130613Smlaier#ifdef __FreeBSD__ 2620223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2621223637Sbz#else 2622223637Sbz struct pfsync_softc *sc = pfsyncif; 2623130613Smlaier#endif 2624223637Sbz struct pfsync_upd_req_item *item; 2625223637Sbz size_t nlen = sizeof(struct pfsync_upd_req); 2626223637Sbz int s; 2627130613Smlaier 2628130613Smlaier /* 2629223637Sbz * this code does nothing to prevent multiple update requests for the 2630223637Sbz * same state being generated. 2631130613Smlaier */ 2632130613Smlaier 2633223637Sbz item = pool_get(&sc->sc_pool, PR_NOWAIT); 2634223637Sbz if (item == NULL) { 2635223637Sbz /* XXX stats */ 2636223637Sbz return; 2637223637Sbz } 2638171168Smlaier 2639223637Sbz item->ur_msg.id = id; 2640223637Sbz item->ur_msg.creatorid = creatorid; 2641171168Smlaier 2642223637Sbz if (TAILQ_EMPTY(&sc->sc_upd_req_list)) 2643223637Sbz nlen += sizeof(struct pfsync_subheader); 2644223637Sbz 2645130613Smlaier#ifdef __FreeBSD__ 2646223637Sbz if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2647130613Smlaier#else 2648223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2649130613Smlaier#endif 2650223637Sbz s = splnet(); 2651223637Sbz pfsync_sendout(); 2652223637Sbz splx(s); 2653223637Sbz 2654223637Sbz nlen = sizeof(struct pfsync_subheader) + 2655223637Sbz sizeof(struct pfsync_upd_req); 2656130613Smlaier } 2657223637Sbz 2658223637Sbz TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); 2659223637Sbz sc->sc_len += nlen; 2660223637Sbz 2661223637Sbz schednetisr(NETISR_PFSYNC); 2662223637Sbz} 2663223637Sbz 2664223637Sbzvoid 2665223637Sbzpfsync_update_state_req(struct pf_state *st) 2666223637Sbz{ 2667130613Smlaier#ifdef __FreeBSD__ 2668223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2669223637Sbz#else 2670223637Sbz struct pfsync_softc *sc = pfsyncif; 2671130613Smlaier#endif 2672223637Sbz 2673223637Sbz if (sc == NULL) 2674223637Sbz panic("pfsync_update_state_req: nonexistant instance"); 2675223637Sbz 2676223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2677223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2678223637Sbz pfsync_q_del(st); 2679223637Sbz return; 2680223637Sbz } 2681223637Sbz 2682223637Sbz switch (st->sync_state) { 2683223637Sbz case PFSYNC_S_UPD_C: 2684223637Sbz case PFSYNC_S_IACK: 2685223637Sbz pfsync_q_del(st); 2686223637Sbz case PFSYNC_S_NONE: 2687223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD); 2688223637Sbz schednetisr(NETISR_PFSYNC); 2689223637Sbz return; 2690223637Sbz 2691223637Sbz case PFSYNC_S_INS: 2692223637Sbz case PFSYNC_S_UPD: 2693223637Sbz case PFSYNC_S_DEL: 2694223637Sbz /* we're already handling it */ 2695223637Sbz return; 2696223637Sbz 2697223637Sbz default: 2698223637Sbz panic("pfsync_update_state_req: unexpected sync state %d", 2699223637Sbz st->sync_state); 2700223637Sbz } 2701130613Smlaier} 2702130613Smlaier 2703130613Smlaiervoid 2704223637Sbzpfsync_delete_state(struct pf_state *st) 2705130613Smlaier{ 2706130613Smlaier#ifdef __FreeBSD__ 2707223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2708223637Sbz#else 2709223637Sbz struct pfsync_softc *sc = pfsyncif; 2710130613Smlaier#endif 2711223637Sbz 2712130613Smlaier#ifdef __FreeBSD__ 2713223637Sbz PF_ASSERT(MA_OWNED); 2714130613Smlaier#else 2715223637Sbz splassert(IPL_SOFTNET); 2716130613Smlaier#endif 2717223637Sbz 2718223637Sbz if (sc == NULL) 2719223637Sbz return; 2720223637Sbz 2721223637Sbz if (ISSET(st->state_flags, PFSTATE_ACK)) 2722223637Sbz pfsync_deferred(st, 1); 2723223637Sbz if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2724223637Sbz if (st->sync_state != PFSYNC_S_NONE) 2725223637Sbz pfsync_q_del(st); 2726223637Sbz return; 2727223637Sbz } 2728223637Sbz 2729223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 2730171168Smlaier#ifdef __FreeBSD__ 2731223637Sbz callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2732223637Sbz V_pfsyncif); 2733171168Smlaier#else 2734223637Sbz timeout_add_sec(&sc->sc_tmo, 1); 2735171168Smlaier#endif 2736223637Sbz 2737223637Sbz switch (st->sync_state) { 2738223637Sbz case PFSYNC_S_INS: 2739223637Sbz /* we never got to tell the world so just forget about it */ 2740223637Sbz pfsync_q_del(st); 2741223637Sbz return; 2742223637Sbz 2743223637Sbz case PFSYNC_S_UPD_C: 2744223637Sbz case PFSYNC_S_UPD: 2745223637Sbz case PFSYNC_S_IACK: 2746223637Sbz pfsync_q_del(st); 2747223637Sbz /* FALLTHROUGH to putting it on the del list */ 2748223637Sbz 2749223637Sbz case PFSYNC_S_NONE: 2750223637Sbz pfsync_q_ins(st, PFSYNC_S_DEL); 2751223637Sbz return; 2752223637Sbz 2753223637Sbz default: 2754223637Sbz panic("pfsync_delete_state: unexpected sync state %d", 2755223637Sbz st->sync_state); 2756130613Smlaier } 2757223637Sbz} 2758223637Sbz 2759223637Sbzvoid 2760223637Sbzpfsync_clear_states(u_int32_t creatorid, const char *ifname) 2761223637Sbz{ 2762223637Sbz struct { 2763223637Sbz struct pfsync_subheader subh; 2764223637Sbz struct pfsync_clr clr; 2765223637Sbz } __packed r; 2766223637Sbz 2767130613Smlaier#ifdef __FreeBSD__ 2768223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2769223637Sbz#else 2770223637Sbz struct pfsync_softc *sc = pfsyncif; 2771130613Smlaier#endif 2772223637Sbz 2773223637Sbz#ifdef __FreeBSD__ 2774223637Sbz PF_ASSERT(MA_OWNED); 2775223637Sbz#else 2776223637Sbz splassert(IPL_SOFTNET); 2777223637Sbz#endif 2778223637Sbz 2779223637Sbz if (sc == NULL) 2780223637Sbz return; 2781223637Sbz 2782223637Sbz bzero(&r, sizeof(r)); 2783223637Sbz 2784223637Sbz r.subh.action = PFSYNC_ACT_CLR; 2785223637Sbz r.subh.count = htons(1); 2786223637Sbz 2787223637Sbz strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 2788223637Sbz r.clr.creatorid = creatorid; 2789223637Sbz 2790223637Sbz pfsync_send_plus(&r, sizeof(r)); 2791130613Smlaier} 2792130613Smlaier 2793223637Sbzvoid 2794223637Sbzpfsync_q_ins(struct pf_state *st, int q) 2795126258Smlaier{ 2796171168Smlaier#ifdef __FreeBSD__ 2797223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2798171168Smlaier#else 2799223637Sbz struct pfsync_softc *sc = pfsyncif; 2800138666Smlaier#endif 2801223637Sbz size_t nlen = pfsync_qs[q].len; 2802223637Sbz int s; 2803223637Sbz 2804223637Sbz#ifdef __FreeBSD__ 2805223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 2806223637Sbz ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2807223637Sbz#else 2808223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE); 2809171168Smlaier#endif 2810126258Smlaier 2811223637Sbz#if 1 || defined(PFSYNC_DEBUG) 2812223637Sbz if (sc->sc_len < PFSYNC_MINPKT) 2813127145Smlaier#ifdef __FreeBSD__ 2814223637Sbz panic("pfsync pkt len is too low %zu", sc->sc_len); 2815223637Sbz#else 2816223637Sbz panic("pfsync pkt len is too low %d", sc->sc_len); 2817171168Smlaier#endif 2818223637Sbz#endif 2819223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2820223637Sbz nlen += sizeof(struct pfsync_subheader); 2821130613Smlaier 2822165632Sjhb#ifdef __FreeBSD__ 2823223637Sbz if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2824165632Sjhb#else 2825223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2826126258Smlaier#endif 2827223637Sbz s = splnet(); 2828223637Sbz#ifdef __FreeBSD__ 2829223637Sbz PF_LOCK(); 2830165632Sjhb#endif 2831223637Sbz pfsync_sendout(); 2832223637Sbz#ifdef __FreeBSD__ 2833223637Sbz PF_UNLOCK(); 2834223637Sbz#endif 2835223637Sbz splx(s); 2836126258Smlaier 2837223637Sbz nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 2838130613Smlaier } 2839126258Smlaier 2840223637Sbz sc->sc_len += nlen; 2841223637Sbz TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); 2842223637Sbz st->sync_state = q; 2843171168Smlaier} 2844171168Smlaier 2845223637Sbzvoid 2846223637Sbzpfsync_q_del(struct pf_state *st) 2847171168Smlaier{ 2848159603Smlaier#ifdef __FreeBSD__ 2849223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2850171168Smlaier#else 2851223637Sbz struct pfsync_softc *sc = pfsyncif; 2852171168Smlaier#endif 2853223637Sbz int q = st->sync_state; 2854171168Smlaier 2855171168Smlaier#ifdef __FreeBSD__ 2856223637Sbz KASSERT(st->sync_state != PFSYNC_S_NONE, 2857223637Sbz ("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__)); 2858223637Sbz#else 2859223637Sbz KASSERT(st->sync_state != PFSYNC_S_NONE); 2860171168Smlaier#endif 2861171168Smlaier 2862223637Sbz sc->sc_len -= pfsync_qs[q].len; 2863223637Sbz TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); 2864223637Sbz st->sync_state = PFSYNC_S_NONE; 2865171168Smlaier 2866223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2867223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2868223637Sbz} 2869223637Sbz 2870223637Sbz#ifdef notyet 2871223637Sbzvoid 2872223637Sbzpfsync_update_tdb(struct tdb *t, int output) 2873223637Sbz{ 2874171168Smlaier#ifdef __FreeBSD__ 2875223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2876171168Smlaier#else 2877223637Sbz struct pfsync_softc *sc = pfsyncif; 2878171168Smlaier#endif 2879223637Sbz size_t nlen = sizeof(struct pfsync_tdb); 2880223637Sbz int s; 2881171168Smlaier 2882223637Sbz if (sc == NULL) 2883223637Sbz return; 2884223637Sbz 2885223637Sbz if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) { 2886223637Sbz if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2887223637Sbz nlen += sizeof(struct pfsync_subheader); 2888223637Sbz 2889223637Sbz if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2890223637Sbz s = splnet(); 2891223637Sbz pfsync_sendout(); 2892223637Sbz splx(s); 2893223637Sbz 2894223637Sbz nlen = sizeof(struct pfsync_subheader) + 2895223637Sbz sizeof(struct pfsync_tdb); 2896223637Sbz } 2897223637Sbz 2898223637Sbz sc->sc_len += nlen; 2899223637Sbz TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry); 2900223637Sbz SET(t->tdb_flags, TDBF_PFSYNC); 2901223637Sbz t->tdb_updates = 0; 2902223637Sbz } else { 2903223637Sbz if (++t->tdb_updates >= sc->sc_maxupdates) 2904223637Sbz schednetisr(NETISR_PFSYNC); 2905223637Sbz } 2906223637Sbz 2907223637Sbz if (output) 2908223637Sbz SET(t->tdb_flags, TDBF_PFSYNC_RPL); 2909223637Sbz else 2910223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC_RPL); 2911171168Smlaier} 2912223637Sbz 2913223637Sbzvoid 2914223637Sbzpfsync_delete_tdb(struct tdb *t) 2915223637Sbz{ 2916223637Sbz#ifdef __FreeBSD__ 2917223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2918223637Sbz#else 2919223637Sbz struct pfsync_softc *sc = pfsyncif; 2920171168Smlaier#endif 2921171168Smlaier 2922223637Sbz if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC)) 2923223637Sbz return; 2924223637Sbz 2925223637Sbz sc->sc_len -= sizeof(struct pfsync_tdb); 2926223637Sbz TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry); 2927223637Sbz CLR(t->tdb_flags, TDBF_PFSYNC); 2928223637Sbz 2929223637Sbz if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2930223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2931223637Sbz} 2932223637Sbz 2933171168Smlaierint 2934223637Sbzpfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset) 2935171168Smlaier{ 2936223637Sbz struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset); 2937171168Smlaier 2938223637Sbz bzero(ut, sizeof(*ut)); 2939223637Sbz ut->spi = t->tdb_spi; 2940223637Sbz bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst)); 2941223637Sbz /* 2942223637Sbz * When a failover happens, the master's rpl is probably above 2943223637Sbz * what we see here (we may be up to a second late), so 2944223637Sbz * increase it a bit for outbound tdbs to manage most such 2945223637Sbz * situations. 2946223637Sbz * 2947223637Sbz * For now, just add an offset that is likely to be larger 2948223637Sbz * than the number of packets we can see in one second. The RFC 2949223637Sbz * just says the next packet must have a higher seq value. 2950223637Sbz * 2951223637Sbz * XXX What is a good algorithm for this? We could use 2952223637Sbz * a rate-determined increase, but to know it, we would have 2953223637Sbz * to extend struct tdb. 2954223637Sbz * XXX pt->rpl can wrap over MAXINT, but if so the real tdb 2955223637Sbz * will soon be replaced anyway. For now, just don't handle 2956223637Sbz * this edge case. 2957223637Sbz */ 2958223637Sbz#define RPL_INCR 16384 2959223637Sbz ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ? 2960223637Sbz RPL_INCR : 0)); 2961223637Sbz ut->cur_bytes = htobe64(t->tdb_cur_bytes); 2962223637Sbz ut->sproto = t->tdb_sproto; 2963223637Sbz 2964223637Sbz return (sizeof(*ut)); 2965223637Sbz} 2966223637Sbz#endif 2967223637Sbz 2968223637Sbzvoid 2969223637Sbzpfsync_bulk_start(void) 2970223637Sbz{ 2971171168Smlaier#ifdef __FreeBSD__ 2972223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2973223637Sbz#else 2974223637Sbz struct pfsync_softc *sc = pfsyncif; 2975171168Smlaier#endif 2976223637Sbz 2977223637Sbz sc->sc_ureq_received = time_uptime; 2978223637Sbz 2979223637Sbz if (sc->sc_bulk_next == NULL) 2980171168Smlaier#ifdef __FreeBSD__ 2981223637Sbz sc->sc_bulk_next = TAILQ_FIRST(&V_state_list); 2982159603Smlaier#else 2983223637Sbz sc->sc_bulk_next = TAILQ_FIRST(&state_list); 2984159603Smlaier#endif 2985223637Sbz sc->sc_bulk_last = sc->sc_bulk_next; 2986223637Sbz 2987223637Sbz#ifdef __FreeBSD__ 2988223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 2989223637Sbz#else 2990223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 2991223637Sbz#endif 2992223637Sbz printf("pfsync: received bulk update request\n"); 2993223637Sbz 2994223637Sbz pfsync_bulk_status(PFSYNC_BUS_START); 2995223637Sbz pfsync_bulk_update(sc); 2996223637Sbz} 2997223637Sbz 2998223637Sbzvoid 2999223637Sbzpfsync_bulk_update(void *arg) 3000223637Sbz{ 3001223637Sbz struct pfsync_softc *sc = arg; 3002223637Sbz struct pf_state *st = sc->sc_bulk_next; 3003223637Sbz int i = 0; 3004223637Sbz int s; 3005223637Sbz 3006223637Sbz s = splsoftnet(); 3007223637Sbz#ifdef __FreeBSD__ 3008223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3009223637Sbz PF_LOCK(); 3010223637Sbz#endif 3011223637Sbz do { 3012223637Sbz if (st->sync_state == PFSYNC_S_NONE && 3013223637Sbz st->timeout < PFTM_MAX && 3014223637Sbz st->pfsync_time <= sc->sc_ureq_received) { 3015223637Sbz pfsync_update_state_req(st); 3016223637Sbz i++; 3017130613Smlaier } 3018223637Sbz 3019223637Sbz st = TAILQ_NEXT(st, entry_list); 3020223637Sbz if (st == NULL) 3021130613Smlaier#ifdef __FreeBSD__ 3022223637Sbz st = TAILQ_FIRST(&V_state_list); 3023130613Smlaier#else 3024223637Sbz st = TAILQ_FIRST(&state_list); 3025130613Smlaier#endif 3026223637Sbz 3027223637Sbz if (i > 0 && TAILQ_EMPTY(&sc->sc_qs[PFSYNC_S_UPD])) { 3028223637Sbz sc->sc_bulk_next = st; 3029130613Smlaier#ifdef __FreeBSD__ 3030223637Sbz callout_reset(&sc->sc_bulk_tmo, 1, 3031223637Sbz pfsync_bulk_fail, sc); 3032130613Smlaier#else 3033223637Sbz timeout_add(&sc->sc_bulk_tmo, 1); 3034130613Smlaier#endif 3035223637Sbz goto out; 3036223637Sbz } 3037223637Sbz } while (st != sc->sc_bulk_last); 3038130613Smlaier 3039223637Sbz /* we're done */ 3040223637Sbz sc->sc_bulk_next = NULL; 3041223637Sbz sc->sc_bulk_last = NULL; 3042223637Sbz pfsync_bulk_status(PFSYNC_BUS_END); 3043130613Smlaier 3044223637Sbzout: 3045130613Smlaier#ifdef __FreeBSD__ 3046223637Sbz PF_UNLOCK(); 3047223637Sbz CURVNET_RESTORE(); 3048223637Sbz#endif 3049223637Sbz splx(s); 3050223637Sbz} 3051223637Sbz 3052223637Sbzvoid 3053223637Sbzpfsync_bulk_status(u_int8_t status) 3054223637Sbz{ 3055223637Sbz struct { 3056223637Sbz struct pfsync_subheader subh; 3057223637Sbz struct pfsync_bus bus; 3058223637Sbz } __packed r; 3059223637Sbz 3060223637Sbz#ifdef __FreeBSD__ 3061223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3062130613Smlaier#else 3063223637Sbz struct pfsync_softc *sc = pfsyncif; 3064130613Smlaier#endif 3065130613Smlaier 3066223637Sbz bzero(&r, sizeof(r)); 3067171168Smlaier 3068223637Sbz r.subh.action = PFSYNC_ACT_BUS; 3069223637Sbz r.subh.count = htons(1); 3070223637Sbz 3071130613Smlaier#ifdef __FreeBSD__ 3072223637Sbz r.bus.creatorid = V_pf_status.hostid; 3073147261Smlaier#else 3074223637Sbz r.bus.creatorid = pf_status.hostid; 3075130613Smlaier#endif 3076223637Sbz r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 3077223637Sbz r.bus.status = status; 3078130613Smlaier 3079223637Sbz pfsync_send_plus(&r, sizeof(r)); 3080126258Smlaier} 3081126261Smlaier 3082171168Smlaiervoid 3083223637Sbzpfsync_bulk_fail(void *arg) 3084171168Smlaier{ 3085223637Sbz struct pfsync_softc *sc = arg; 3086171168Smlaier 3087223637Sbz#ifdef __FreeBSD__ 3088223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3089223637Sbz#endif 3090171168Smlaier 3091223637Sbz if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 3092223637Sbz /* Try again */ 3093223637Sbz#ifdef __FreeBSD__ 3094223637Sbz callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 3095223637Sbz pfsync_bulk_fail, V_pfsyncif); 3096223637Sbz#else 3097223637Sbz timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 3098223637Sbz#endif 3099223637Sbz pfsync_request_update(0, 0); 3100223637Sbz } else { 3101223637Sbz /* Pretend like the transfer was ok */ 3102223637Sbz sc->sc_ureq_sent = 0; 3103223637Sbz sc->sc_bulk_tries = 0; 3104223637Sbz#if NCARP > 0 3105223637Sbz#ifdef notyet 3106223637Sbz#ifdef __FreeBSD__ 3107223637Sbz if (!sc->pfsync_sync_ok) 3108223637Sbz#else 3109223637Sbz if (!pfsync_sync_ok) 3110223637Sbz#endif 3111223637Sbz carp_group_demote_adj(&sc->sc_if, -1); 3112223637Sbz#endif 3113223637Sbz#endif 3114223637Sbz#ifdef __FreeBSD__ 3115223637Sbz sc->pfsync_sync_ok = 1; 3116223637Sbz#else 3117223637Sbz pfsync_sync_ok = 1; 3118223637Sbz#endif 3119223637Sbz#ifdef __FreeBSD__ 3120223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 3121223637Sbz#else 3122223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) 3123223637Sbz#endif 3124223637Sbz printf("pfsync: failed to receive bulk update\n"); 3125223637Sbz } 3126171168Smlaier 3127223637Sbz#ifdef __FreeBSD__ 3128223637Sbz CURVNET_RESTORE(); 3129223637Sbz#endif 3130223637Sbz} 3131171168Smlaier 3132223637Sbzvoid 3133223637Sbzpfsync_send_plus(void *plus, size_t pluslen) 3134223637Sbz{ 3135223637Sbz#ifdef __FreeBSD__ 3136223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3137223637Sbz#else 3138223637Sbz struct pfsync_softc *sc = pfsyncif; 3139223637Sbz#endif 3140223637Sbz int s; 3141223637Sbz 3142223637Sbz#ifdef __FreeBSD__ 3143223637Sbz if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) { 3144223637Sbz#else 3145223637Sbz if (sc->sc_len + pluslen > sc->sc_if.if_mtu) { 3146223637Sbz#endif 3147223637Sbz s = splnet(); 3148223637Sbz#ifdef __FreeBSD__ 3149223637Sbz PF_LOCK(); 3150223637Sbz#endif 3151223637Sbz pfsync_sendout(); 3152223637Sbz#ifdef __FreeBSD__ 3153223637Sbz PF_UNLOCK(); 3154223637Sbz#endif 3155223637Sbz splx(s); 3156171168Smlaier } 3157223637Sbz 3158223637Sbz sc->sc_plus = plus; 3159223637Sbz sc->sc_len += (sc->sc_pluslen = pluslen); 3160223637Sbz 3161223637Sbz s = splnet(); 3162223637Sbz#ifdef __FreeBSD__ 3163223637Sbz PF_LOCK(); 3164223637Sbz#endif 3165223637Sbz pfsync_sendout(); 3166223637Sbz#ifdef __FreeBSD__ 3167223637Sbz PF_UNLOCK(); 3168223637Sbz#endif 3169171168Smlaier splx(s); 3170171168Smlaier} 3171171168Smlaier 3172171168Smlaierint 3173223637Sbzpfsync_up(void) 3174171168Smlaier{ 3175223637Sbz#ifdef __FreeBSD__ 3176223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3177223637Sbz#else 3178171168Smlaier struct pfsync_softc *sc = pfsyncif; 3179223637Sbz#endif 3180171168Smlaier 3181147261Smlaier#ifdef __FreeBSD__ 3182223637Sbz if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING)) 3183171168Smlaier#else 3184223637Sbz if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) 3185171168Smlaier#endif 3186223637Sbz return (0); 3187223637Sbz 3188223637Sbz return (1); 3189223637Sbz} 3190223637Sbz 3191223637Sbzint 3192223637Sbzpfsync_state_in_use(struct pf_state *st) 3193223637Sbz{ 3194171168Smlaier#ifdef __FreeBSD__ 3195223637Sbz struct pfsync_softc *sc = V_pfsyncif; 3196171168Smlaier#else 3197223637Sbz struct pfsync_softc *sc = pfsyncif; 3198171168Smlaier#endif 3199223637Sbz 3200223637Sbz if (sc == NULL) 3201171168Smlaier return (0); 3202171168Smlaier 3203223637Sbz if (st->sync_state != PFSYNC_S_NONE) 3204223637Sbz return (1); 3205223637Sbz 3206223637Sbz if (sc->sc_bulk_next == NULL && sc->sc_bulk_last == NULL) 3207223637Sbz return (0); 3208223637Sbz 3209223637Sbz return (1); 3210223637Sbz} 3211223637Sbz 3212223637Sbzu_int pfsync_ints; 3213223637Sbzu_int pfsync_tmos; 3214223637Sbz 3215223637Sbzvoid 3216223637Sbzpfsync_timeout(void *arg) 3217223637Sbz{ 3218223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE) 3219223637Sbz struct pfsync_softc *sc = arg; 3220223637Sbz#endif 3221223637Sbz int s; 3222223637Sbz 3223171168Smlaier#ifdef __FreeBSD__ 3224223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3225171168Smlaier#endif 3226223637Sbz 3227223637Sbz pfsync_tmos++; 3228223637Sbz 3229171168Smlaier s = splnet(); 3230223637Sbz#ifdef __FreeBSD__ 3231223637Sbz PF_LOCK(); 3232223637Sbz#endif 3233223637Sbz pfsync_sendout(); 3234223637Sbz#ifdef __FreeBSD__ 3235223637Sbz PF_UNLOCK(); 3236223637Sbz#endif 3237223637Sbz splx(s); 3238171168Smlaier 3239223637Sbz#ifdef __FreeBSD__ 3240223637Sbz CURVNET_RESTORE(); 3241223637Sbz#endif 3242223637Sbz} 3243171168Smlaier 3244223637Sbz/* this is a softnet/netisr handler */ 3245223637Sbzvoid 3246223637Sbz#ifdef __FreeBSD__ 3247223637Sbzpfsyncintr(void *arg) 3248223637Sbz#else 3249223637Sbzpfsyncintr(void) 3250223637Sbz#endif 3251223637Sbz{ 3252223637Sbz#ifdef __FreeBSD__ 3253223637Sbz struct pfsync_softc *sc = arg; 3254223637Sbz#endif 3255223637Sbz int s; 3256171168Smlaier 3257223637Sbz#ifdef __FreeBSD__ 3258223637Sbz if (sc == NULL) 3259223637Sbz return; 3260171168Smlaier 3261223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3262223637Sbz#endif 3263223637Sbz pfsync_ints++; 3264171168Smlaier 3265223637Sbz s = splnet(); 3266223637Sbz#ifdef __FreeBSD__ 3267223637Sbz PF_LOCK(); 3268223637Sbz#endif 3269223637Sbz pfsync_sendout(); 3270223637Sbz#ifdef __FreeBSD__ 3271223637Sbz PF_UNLOCK(); 3272223637Sbz#endif 3273223637Sbz splx(s); 3274171168Smlaier 3275223637Sbz#ifdef __FreeBSD__ 3276223637Sbz CURVNET_RESTORE(); 3277223637Sbz#endif 3278171168Smlaier} 3279171168Smlaier 3280223637Sbzint 3281223637Sbzpfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 3282223637Sbz size_t newlen) 3283223637Sbz{ 3284223637Sbz 3285223637Sbz#ifdef notyet 3286223637Sbz /* All sysctl names at this level are terminal. */ 3287223637Sbz if (namelen != 1) 3288223637Sbz return (ENOTDIR); 3289223637Sbz 3290223637Sbz switch (name[0]) { 3291223637Sbz case PFSYNCCTL_STATS: 3292223637Sbz if (newp != NULL) 3293223637Sbz return (EPERM); 3294223637Sbz return (sysctl_struct(oldp, oldlenp, newp, newlen, 3295223637Sbz &V_pfsyncstats, sizeof(V_pfsyncstats))); 3296223637Sbz } 3297223637Sbz#endif 3298223637Sbz return (ENOPROTOOPT); 3299223637Sbz} 3300223637Sbz 3301171168Smlaier#ifdef __FreeBSD__ 3302171168Smlaiervoid 3303167710Sbmspfsync_ifdetach(void *arg, struct ifnet *ifp) 3304167710Sbms{ 3305167710Sbms struct pfsync_softc *sc = (struct pfsync_softc *)arg; 3306167710Sbms struct ip_moptions *imo; 3307167710Sbms 3308223637Sbz if (sc == NULL || sc->sc_sync_if != ifp) 3309171168Smlaier return; /* not for us; unlocked read */ 3310167710Sbms 3311223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 3312223637Sbz 3313167710Sbms PF_LOCK(); 3314167710Sbms 3315167710Sbms /* Deal with a member interface going away from under us. */ 3316223637Sbz sc->sc_sync_if = NULL; 3317167710Sbms imo = &sc->sc_imo; 3318167710Sbms if (imo->imo_num_memberships > 0) { 3319168700Sbms KASSERT(imo->imo_num_memberships == 1, 3320171168Smlaier ("%s: imo_num_memberships != 1", __func__)); 3321168700Sbms /* 3322168700Sbms * Our event handler is always called after protocol 3323168700Sbms * domains have been detached from the underlying ifnet. 3324168700Sbms * Do not call in_delmulti(); we held a single reference 3325168700Sbms * which the protocol domain has purged in in_purgemaddrs(). 3326168700Sbms */ 3327171168Smlaier PF_UNLOCK(); 3328168700Sbms imo->imo_membership[--imo->imo_num_memberships] = NULL; 3329171168Smlaier PF_LOCK(); 3330167710Sbms imo->imo_multicast_ifp = NULL; 3331167710Sbms } 3332167710Sbms 3333167710Sbms PF_UNLOCK(); 3334223637Sbz 3335223637Sbz CURVNET_RESTORE(); 3336167710Sbms} 3337167710Sbms 3338223637Sbzstatic int 3339223637Sbzvnet_pfsync_init(const void *unused) 3340147261Smlaier{ 3341223637Sbz int error = 0; 3342126261Smlaier 3343223637Sbz pfsyncattach(0); 3344223637Sbz 3345223637Sbz error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif, 3346223637Sbz SWI_NET, INTR_MPSAFE, &pfsync_swi.pfsync_swi_cookie); 3347223637Sbz if (error) 3348223637Sbz panic("%s: swi_add %d", __func__, error); 3349223637Sbz 3350223637Sbz pfsync_state_import_ptr = pfsync_state_import; 3351223637Sbz pfsync_up_ptr = pfsync_up; 3352223637Sbz pfsync_insert_state_ptr = pfsync_insert_state; 3353223637Sbz pfsync_update_state_ptr = pfsync_update_state; 3354223637Sbz pfsync_delete_state_ptr = pfsync_delete_state; 3355223637Sbz pfsync_clear_states_ptr = pfsync_clear_states; 3356223637Sbz pfsync_state_in_use_ptr = pfsync_state_in_use; 3357223637Sbz pfsync_defer_ptr = pfsync_defer; 3358223637Sbz 3359223637Sbz return (0); 3360147261Smlaier} 3361147261Smlaier 3362126261Smlaierstatic int 3363223637Sbzvnet_pfsync_uninit(const void *unused) 3364223637Sbz{ 3365223637Sbz 3366223637Sbz swi_remove(pfsync_swi.pfsync_swi_cookie); 3367223637Sbz 3368223637Sbz pfsync_state_import_ptr = NULL; 3369223637Sbz pfsync_up_ptr = NULL; 3370223637Sbz pfsync_insert_state_ptr = NULL; 3371223637Sbz pfsync_update_state_ptr = NULL; 3372223637Sbz pfsync_delete_state_ptr = NULL; 3373223637Sbz pfsync_clear_states_ptr = NULL; 3374223637Sbz pfsync_state_in_use_ptr = NULL; 3375223637Sbz pfsync_defer_ptr = NULL; 3376223637Sbz 3377223637Sbz if_clone_detach(&pfsync_cloner); 3378223637Sbz 3379223637Sbz return (0); 3380223637Sbz} 3381223637Sbz 3382223637Sbz/* Define startup order. */ 3383223637Sbz#define PFSYNC_SYSINIT_ORDER SI_SUB_PROTO_BEGIN 3384223637Sbz#define PFSYNC_MODEVENT_ORDER (SI_ORDER_FIRST) /* On boot slot in here. */ 3385223637Sbz#define PFSYNC_VNET_ORDER (PFSYNC_MODEVENT_ORDER + 2) /* Later still. */ 3386223637Sbz 3387223637Sbz/* 3388223637Sbz * Starting up. 3389223637Sbz * VNET_SYSINIT is called for each existing vnet and each new vnet. 3390223637Sbz */ 3391223637SbzVNET_SYSINIT(vnet_pfsync_init, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER, 3392223637Sbz vnet_pfsync_init, NULL); 3393223637Sbz 3394223637Sbz/* 3395223637Sbz * Closing up shop. These are done in REVERSE ORDER, 3396223637Sbz * Not called on reboot. 3397223637Sbz * VNET_SYSUNINIT is called for each exiting vnet as it exits. 3398223637Sbz */ 3399223637SbzVNET_SYSUNINIT(vnet_pfsync_uninit, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER, 3400223637Sbz vnet_pfsync_uninit, NULL); 3401223637Sbzstatic int 3402126261Smlaierpfsync_modevent(module_t mod, int type, void *data) 3403126261Smlaier{ 3404126261Smlaier int error = 0; 3405126261Smlaier 3406126261Smlaier switch (type) { 3407126261Smlaier case MOD_LOAD: 3408223637Sbz#ifndef __FreeBSD__ 3409171168Smlaier pfsyncattach(0); 3410223637Sbz#endif 3411126261Smlaier break; 3412126261Smlaier case MOD_UNLOAD: 3413223637Sbz#ifndef __FreeBSD__ 3414126261Smlaier if_clone_detach(&pfsync_cloner); 3415223637Sbz#endif 3416126261Smlaier break; 3417126261Smlaier default: 3418126261Smlaier error = EINVAL; 3419126261Smlaier break; 3420126261Smlaier } 3421126261Smlaier 3422126261Smlaier return error; 3423126261Smlaier} 3424126261Smlaier 3425126261Smlaierstatic moduledata_t pfsync_mod = { 3426126261Smlaier "pfsync", 3427126261Smlaier pfsync_modevent, 3428126261Smlaier 0 3429126261Smlaier}; 3430126261Smlaier 3431126261Smlaier#define PFSYNC_MODVER 1 3432126261Smlaier 3433135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 3434126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER); 3435223637SbzMODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 3436126261Smlaier#endif /* __FreeBSD__ */ 3437