102742ec6SJoerg Sonnenberger /*
202742ec6SJoerg Sonnenberger * Copyright (c) 2002 Michael Shalayeff
302742ec6SJoerg Sonnenberger * All rights reserved.
402742ec6SJoerg Sonnenberger *
502742ec6SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
602742ec6SJoerg Sonnenberger * modification, are permitted provided that the following conditions
702742ec6SJoerg Sonnenberger * are met:
802742ec6SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
902742ec6SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer.
1002742ec6SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
1102742ec6SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
1202742ec6SJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
1302742ec6SJoerg Sonnenberger *
1402742ec6SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1502742ec6SJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1602742ec6SJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1702742ec6SJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
1802742ec6SJoerg Sonnenberger * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1902742ec6SJoerg Sonnenberger * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2002742ec6SJoerg Sonnenberger * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2102742ec6SJoerg Sonnenberger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2202742ec6SJoerg Sonnenberger * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2302742ec6SJoerg Sonnenberger * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2402742ec6SJoerg Sonnenberger * THE POSSIBILITY OF SUCH DAMAGE.
253a0038bfSMatthew Dillon *
263a0038bfSMatthew Dillon * $OpenBSD: if_pfsync.c,v 1.98 2008/06/29 08:42:15 mcbride Exp $
2702742ec6SJoerg Sonnenberger */
2802742ec6SJoerg Sonnenberger
29c3c8c553SJan Lentfer #include "opt_inet.h"
30c3c8c553SJan Lentfer #include "opt_inet6.h"
315992bdfcSSepherosa Ziehau #include "opt_carp.h"
322b00f643SSascha Wildner #include "use_bpf.h"
3302742ec6SJoerg Sonnenberger
3402742ec6SJoerg Sonnenberger #include <sys/param.h>
35c3c8c553SJan Lentfer #include <sys/endian.h>
3602742ec6SJoerg Sonnenberger #include <sys/proc.h>
37*2b3f93eaSMatthew Dillon #include <sys/caps.h>
3802742ec6SJoerg Sonnenberger #include <sys/systm.h>
3902742ec6SJoerg Sonnenberger #include <sys/time.h>
4002742ec6SJoerg Sonnenberger #include <sys/mbuf.h>
4102742ec6SJoerg Sonnenberger #include <sys/socket.h>
4202742ec6SJoerg Sonnenberger #include <sys/kernel.h>
43c3c8c553SJan Lentfer #include <sys/malloc.h>
44c3c8c553SJan Lentfer #include <sys/module.h>
45ef15d469SSepherosa Ziehau #include <sys/msgport2.h>
46c3c8c553SJan Lentfer #include <sys/sockio.h>
47c3c8c553SJan Lentfer #include <sys/thread2.h>
48c3c8c553SJan Lentfer
49c3c8c553SJan Lentfer #include <machine/inttypes.h>
5002742ec6SJoerg Sonnenberger
5102742ec6SJoerg Sonnenberger #include <net/if.h>
5202742ec6SJoerg Sonnenberger #include <net/if_types.h>
53ef9870ecSSepherosa Ziehau #include <net/ifq_var.h>
5402742ec6SJoerg Sonnenberger #include <net/route.h>
5502742ec6SJoerg Sonnenberger #include <net/bpf.h>
56ef15d469SSepherosa Ziehau #include <net/netisr2.h>
57ef15d469SSepherosa Ziehau #include <net/netmsg2.h>
5870224baaSJan Lentfer #include <netinet/in.h>
5970224baaSJan Lentfer #include <netinet/if_ether.h>
60315a7da3SJan Lentfer #include <netinet/ip_carp.h>
6170224baaSJan Lentfer #include <netinet/tcp.h>
6270224baaSJan Lentfer #include <netinet/tcp_seq.h>
6302742ec6SJoerg Sonnenberger
6402742ec6SJoerg Sonnenberger #ifdef INET
6502742ec6SJoerg Sonnenberger #include <netinet/in_systm.h>
6602742ec6SJoerg Sonnenberger #include <netinet/in_var.h>
6702742ec6SJoerg Sonnenberger #include <netinet/ip.h>
6802742ec6SJoerg Sonnenberger #include <netinet/ip_var.h>
6902742ec6SJoerg Sonnenberger #endif
7002742ec6SJoerg Sonnenberger
7102742ec6SJoerg Sonnenberger #ifdef INET6
7202742ec6SJoerg Sonnenberger #include <netinet6/nd6.h>
7302742ec6SJoerg Sonnenberger #endif /* INET6 */
7402742ec6SJoerg Sonnenberger
75c3c8c553SJan Lentfer #include <net/pf/pfvar.h>
76c3c8c553SJan Lentfer #include <net/pf/if_pfsync.h>
7702742ec6SJoerg Sonnenberger
78c3c8c553SJan Lentfer #define PFSYNCNAME "pfsync"
7902742ec6SJoerg Sonnenberger
8002742ec6SJoerg Sonnenberger #define PFSYNC_MINMTU \
8102742ec6SJoerg Sonnenberger (sizeof(struct pfsync_header) + sizeof(struct pf_state))
8202742ec6SJoerg Sonnenberger
8302742ec6SJoerg Sonnenberger #ifdef PFSYNCDEBUG
84c3c8c553SJan Lentfer #define DPRINTF(x) do { if (pfsyncdebug) kprintf x ; } while (0)
8502742ec6SJoerg Sonnenberger int pfsyncdebug;
8602742ec6SJoerg Sonnenberger #else
8702742ec6SJoerg Sonnenberger #define DPRINTF(x)
8802742ec6SJoerg Sonnenberger #endif
8902742ec6SJoerg Sonnenberger
9070224baaSJan Lentfer struct pfsync_softc *pfsyncif = NULL;
9102742ec6SJoerg Sonnenberger struct pfsyncstats pfsyncstats;
9202742ec6SJoerg Sonnenberger
9370224baaSJan Lentfer void pfsyncattach(int);
94a7e9152eSSepherosa Ziehau static int pfsync_clone_destroy(struct ifnet *);
95bb54c3a2SAaron LI static int pfsync_clone_create(struct if_clone *, int, caddr_t, caddr_t);
9602742ec6SJoerg Sonnenberger void pfsync_setmtu(struct pfsync_softc *, int);
9770224baaSJan Lentfer int pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
9870224baaSJan Lentfer struct pf_state_peer *);
9902742ec6SJoerg Sonnenberger int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
10002742ec6SJoerg Sonnenberger struct rtentry *);
101c3c8c553SJan Lentfer int pfsyncioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
102f0a26983SSepherosa Ziehau void pfsyncstart(struct ifnet *, struct ifaltq_subque *);
10302742ec6SJoerg Sonnenberger
10402742ec6SJoerg Sonnenberger struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
10502742ec6SJoerg Sonnenberger int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
10602742ec6SJoerg Sonnenberger int pfsync_sendout(struct pfsync_softc *);
10770224baaSJan Lentfer int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
10802742ec6SJoerg Sonnenberger void pfsync_timeout(void *);
10902742ec6SJoerg Sonnenberger void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
11002742ec6SJoerg Sonnenberger void pfsync_bulk_update(void *);
11102742ec6SJoerg Sonnenberger void pfsync_bulkfail(void *);
11202742ec6SJoerg Sonnenberger
113ef15d469SSepherosa Ziehau static struct in_multi *pfsync_in_addmulti(struct ifnet *);
114ef15d469SSepherosa Ziehau static void pfsync_in_delmulti(struct in_multi *);
115ef15d469SSepherosa Ziehau
116c3c8c553SJan Lentfer static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
117c3c8c553SJan Lentfer static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
118c3c8c553SJan Lentfer
11970224baaSJan Lentfer int pfsync_sync_ok;
12002742ec6SJoerg Sonnenberger
12170224baaSJan Lentfer struct if_clone pfsync_cloner =
122c3c8c553SJan Lentfer IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy, 1 ,1);
12370224baaSJan Lentfer
124bb54c3a2SAaron LI
12570224baaSJan Lentfer void
pfsyncattach(int npfsync)12670224baaSJan Lentfer pfsyncattach(int npfsync)
12702742ec6SJoerg Sonnenberger {
12870224baaSJan Lentfer if_clone_attach(&pfsync_cloner);
12902742ec6SJoerg Sonnenberger }
130bb54c3a2SAaron LI
131c3c8c553SJan Lentfer static int
pfsync_clone_create(struct if_clone * ifc,int unit,caddr_t params __unused,caddr_t data __unused)132bb54c3a2SAaron LI pfsync_clone_create(struct if_clone *ifc, int unit,
133bb54c3a2SAaron LI caddr_t params __unused, caddr_t data __unused)
13402742ec6SJoerg Sonnenberger {
135c3c8c553SJan Lentfer struct pfsync_softc *sc;
13602742ec6SJoerg Sonnenberger struct ifnet *ifp;
13702742ec6SJoerg Sonnenberger
1382a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
1392a7a2b1cSJan Lentfer
14002742ec6SJoerg Sonnenberger pfsync_sync_ok = 1;
141c8f430baSAaron LI
142c8f430baSAaron LI sc = kmalloc(sizeof(*sc), M_PFSYNC, M_WAITOK | M_ZERO);
143c3c8c553SJan Lentfer sc->sc_mbuf = NULL;
144c3c8c553SJan Lentfer sc->sc_mbuf_net = NULL;
145c3c8c553SJan Lentfer sc->sc_mbuf_tdb = NULL;
146c3c8c553SJan Lentfer sc->sc_statep.s = NULL;
147c3c8c553SJan Lentfer sc->sc_statep_net.s = NULL;
148c3c8c553SJan Lentfer sc->sc_statep_tdb.t = NULL;
149c3c8c553SJan Lentfer sc->sc_maxupdates = 128;
150c3c8c553SJan Lentfer sc->sc_sync_peer.s_addr =htonl(INADDR_PFSYNC_GROUP);
151c3c8c553SJan Lentfer sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
152c3c8c553SJan Lentfer sc->sc_ureq_received = 0;
153c3c8c553SJan Lentfer sc->sc_ureq_sent = 0;
154c3c8c553SJan Lentfer sc->sc_bulk_send_next = NULL;
155c3c8c553SJan Lentfer sc->sc_bulk_terminator = NULL;
1563a0038bfSMatthew Dillon sc->sc_bulk_send_cpu = 0;
1573a0038bfSMatthew Dillon sc->sc_bulk_terminator_cpu = 0;
158ed1f0be2SJan Lentfer sc->sc_imo.imo_max_memberships = IP_MAX_MEMBERSHIPS;
1592a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
160c8f430baSAaron LI
161c3c8c553SJan Lentfer ifp = &sc->sc_if;
162c3c8c553SJan Lentfer if_initname(ifp, ifc->ifc_name, unit);
16302742ec6SJoerg Sonnenberger ifp->if_ioctl = pfsyncioctl;
16402742ec6SJoerg Sonnenberger ifp->if_output = pfsyncoutput;
16502742ec6SJoerg Sonnenberger ifp->if_start = pfsyncstart;
16602742ec6SJoerg Sonnenberger ifp->if_type = IFT_PFSYNC;
167ef9870ecSSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
16802742ec6SJoerg Sonnenberger ifp->if_hdrlen = PFSYNC_HDRLEN;
169c3c8c553SJan Lentfer ifp->if_baudrate = IF_Mbps(100);
170c3c8c553SJan Lentfer ifp->if_softc = sc;
171c8f430baSAaron LI
172c3c8c553SJan Lentfer pfsync_setmtu(sc, MCLBYTES);
173c3c8c553SJan Lentfer callout_init(&sc->sc_tmo);
174ed1f0be2SJan Lentfer /* callout_init(&sc->sc_tdb_tmo); XXX we don't support tdb (yet) */
175c3c8c553SJan Lentfer callout_init(&sc->sc_bulk_tmo);
176c3c8c553SJan Lentfer callout_init(&sc->sc_bulkfail_tmo);
177c8f430baSAaron LI
178ed1f0be2SJan Lentfer if_attach(ifp, NULL);
1792b00f643SSascha Wildner #if NBPF > 0
180c8f430baSAaron LI bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
181c8f430baSAaron LI #endif
18202742ec6SJoerg Sonnenberger
1832b00f643SSascha Wildner #ifdef CARP
18470224baaSJan Lentfer if_addgroup(ifp, "carp");
18570224baaSJan Lentfer #endif
186ed1f0be2SJan Lentfer
1872a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
188c8f430baSAaron LI LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
1892a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
190c8f430baSAaron LI
19170224baaSJan Lentfer return (0);
19270224baaSJan Lentfer }
19370224baaSJan Lentfer
194a7e9152eSSepherosa Ziehau static int
pfsync_clone_destroy(struct ifnet * ifp)19570224baaSJan Lentfer pfsync_clone_destroy(struct ifnet *ifp)
19670224baaSJan Lentfer {
197c4705c47SSepherosa Ziehau struct netmsg_base msg;
198c4705c47SSepherosa Ziehau
1992a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
2002a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
201ed1f0be2SJan Lentfer
202ed1f0be2SJan Lentfer struct pfsync_softc *sc = ifp->if_softc;
203ed1f0be2SJan Lentfer callout_stop(&sc->sc_tmo);
204ed1f0be2SJan Lentfer /* callout_stop(&sc->sc_tdb_tmo); XXX we don't support tdb (yet) */
205ed1f0be2SJan Lentfer callout_stop(&sc->sc_bulk_tmo);
206ed1f0be2SJan Lentfer callout_stop(&sc->sc_bulkfail_tmo);
2072b00f643SSascha Wildner #ifdef CARP
208ed1f0be2SJan Lentfer if (!pfsync_sync_ok)
209ed1f0be2SJan Lentfer carp_group_demote_adj(&sc->sc_if, -1);
210ed1f0be2SJan Lentfer #endif
211c4705c47SSepherosa Ziehau
212c4705c47SSepherosa Ziehau /* Unpend async sendouts. */
213c4705c47SSepherosa Ziehau netmsg_init(&msg, NULL, &curthread->td_msgport, 0, netmsg_sync_handler);
214c4705c47SSepherosa Ziehau netisr_domsg(&msg, 0);
215c4705c47SSepherosa Ziehau
2162b00f643SSascha Wildner #if NBPF > 0
21770224baaSJan Lentfer bpfdetach(ifp);
21870224baaSJan Lentfer #endif
21970224baaSJan Lentfer if_detach(ifp);
2202a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
221ed1f0be2SJan Lentfer LIST_REMOVE(sc, sc_next);
222ed1f0be2SJan Lentfer kfree(sc, M_PFSYNC);
223ed1f0be2SJan Lentfer lwkt_reltoken(&pf_token);
224ed1f0be2SJan Lentfer
225a7e9152eSSepherosa Ziehau return 0;
22602742ec6SJoerg Sonnenberger }
22702742ec6SJoerg Sonnenberger
22802742ec6SJoerg Sonnenberger /*
22902742ec6SJoerg Sonnenberger * Start output on the pfsync interface.
23002742ec6SJoerg Sonnenberger */
23102742ec6SJoerg Sonnenberger void
pfsyncstart(struct ifnet * ifp,struct ifaltq_subque * ifsq)232f0a26983SSepherosa Ziehau pfsyncstart(struct ifnet *ifp, struct ifaltq_subque *ifsq)
23302742ec6SJoerg Sonnenberger {
234f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
235f0a26983SSepherosa Ziehau ifsq_purge(ifsq);
23602742ec6SJoerg Sonnenberger }
23702742ec6SJoerg Sonnenberger
23802742ec6SJoerg Sonnenberger int
pfsync_alloc_scrub_memory(struct pfsync_state_peer * s,struct pf_state_peer * d)23970224baaSJan Lentfer pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
24070224baaSJan Lentfer struct pf_state_peer *d)
24170224baaSJan Lentfer {
24270224baaSJan Lentfer if (s->scrub.scrub_flag && d->scrub == NULL) {
2431186cbc0SJan Lentfer d->scrub = kmalloc(sizeof(struct pf_state_scrub), M_PFSYNC, M_NOWAIT|M_ZERO);
2441186cbc0SJan Lentfer
24570224baaSJan Lentfer if (d->scrub == NULL)
24670224baaSJan Lentfer return (ENOMEM);
24770224baaSJan Lentfer }
24870224baaSJan Lentfer
24970224baaSJan Lentfer return (0);
25070224baaSJan Lentfer }
25170224baaSJan Lentfer
252ed1f0be2SJan Lentfer void
pfsync_state_export(struct pfsync_state * sp,struct pf_state * st)253ed1f0be2SJan Lentfer pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
254ed1f0be2SJan Lentfer {
255ed1f0be2SJan Lentfer bzero(sp, sizeof(struct pfsync_state));
256ed1f0be2SJan Lentfer
257ed1f0be2SJan Lentfer /* copy from state key */
258ed1f0be2SJan Lentfer sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
259ed1f0be2SJan Lentfer sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
260ed1f0be2SJan Lentfer sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
261ed1f0be2SJan Lentfer sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
262ed1f0be2SJan Lentfer sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
263ed1f0be2SJan Lentfer sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
264ed1f0be2SJan Lentfer sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
265ed1f0be2SJan Lentfer sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
266ed1f0be2SJan Lentfer sp->proto = st->key[PF_SK_WIRE]->proto;
267ed1f0be2SJan Lentfer sp->af = st->key[PF_SK_WIRE]->af;
268ed1f0be2SJan Lentfer
269ed1f0be2SJan Lentfer /* copy from state */
270ed1f0be2SJan Lentfer strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
271ed1f0be2SJan Lentfer bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
272ed1f0be2SJan Lentfer sp->creation = htonl(time_second - st->creation);
273ed1f0be2SJan Lentfer sp->expire = pf_state_expires(st);
274ed1f0be2SJan Lentfer if (sp->expire <= time_second)
275ed1f0be2SJan Lentfer sp->expire = htonl(0);
276ed1f0be2SJan Lentfer else
277ed1f0be2SJan Lentfer sp->expire = htonl(sp->expire - time_second);
278ed1f0be2SJan Lentfer
279ed1f0be2SJan Lentfer sp->direction = st->direction;
280ed1f0be2SJan Lentfer sp->log = st->log;
2815f2a38e8SMatthew Dillon sp->cpuid = st->cpuid;
2825f2a38e8SMatthew Dillon sp->pickup_mode = st->pickup_mode;
283ed1f0be2SJan Lentfer sp->timeout = st->timeout;
284ed1f0be2SJan Lentfer sp->state_flags = st->state_flags;
285ed1f0be2SJan Lentfer if (st->src_node)
286ed1f0be2SJan Lentfer sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
287ed1f0be2SJan Lentfer if (st->nat_src_node)
288ed1f0be2SJan Lentfer sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
289ed1f0be2SJan Lentfer
290ed1f0be2SJan Lentfer bcopy(&st->id, &sp->id, sizeof(sp->id));
291ed1f0be2SJan Lentfer sp->creatorid = st->creatorid;
292ed1f0be2SJan Lentfer pf_state_peer_hton(&st->src, &sp->src);
293ed1f0be2SJan Lentfer pf_state_peer_hton(&st->dst, &sp->dst);
294ed1f0be2SJan Lentfer
295ed1f0be2SJan Lentfer if (st->rule.ptr == NULL)
296ed1f0be2SJan Lentfer sp->rule = htonl(-1);
297ed1f0be2SJan Lentfer else
298ed1f0be2SJan Lentfer sp->rule = htonl(st->rule.ptr->nr);
299ed1f0be2SJan Lentfer if (st->anchor.ptr == NULL)
300ed1f0be2SJan Lentfer sp->anchor = htonl(-1);
301ed1f0be2SJan Lentfer else
302ed1f0be2SJan Lentfer sp->anchor = htonl(st->anchor.ptr->nr);
303ed1f0be2SJan Lentfer if (st->nat_rule.ptr == NULL)
304ed1f0be2SJan Lentfer sp->nat_rule = htonl(-1);
305ed1f0be2SJan Lentfer else
306ed1f0be2SJan Lentfer sp->nat_rule = htonl(st->nat_rule.ptr->nr);
307ed1f0be2SJan Lentfer
308ed1f0be2SJan Lentfer pf_state_counter_hton(st->packets[0], sp->packets[0]);
309ed1f0be2SJan Lentfer pf_state_counter_hton(st->packets[1], sp->packets[1]);
310ed1f0be2SJan Lentfer pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
311ed1f0be2SJan Lentfer pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
312ed1f0be2SJan Lentfer
313ed1f0be2SJan Lentfer }
314ed1f0be2SJan Lentfer
31570224baaSJan Lentfer int
pfsync_state_import(struct pfsync_state * sp,u_int8_t flags)316ed1f0be2SJan Lentfer pfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
31702742ec6SJoerg Sonnenberger {
31802742ec6SJoerg Sonnenberger struct pf_state *st = NULL;
319ed1f0be2SJan Lentfer struct pf_state_key *skw = NULL, *sks = NULL;
32002742ec6SJoerg Sonnenberger struct pf_rule *r = NULL;
32102742ec6SJoerg Sonnenberger struct pfi_kif *kif;
322ed1f0be2SJan Lentfer int pool_flags;
323ed1f0be2SJan Lentfer int error;
32402742ec6SJoerg Sonnenberger
32502742ec6SJoerg Sonnenberger if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
326c3c8c553SJan Lentfer kprintf("pfsync_insert_net_state: invalid creator id:"
32770224baaSJan Lentfer " %08x\n", ntohl(sp->creatorid));
32802742ec6SJoerg Sonnenberger return (EINVAL);
32902742ec6SJoerg Sonnenberger }
33002742ec6SJoerg Sonnenberger
331ed1f0be2SJan Lentfer if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
33202742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
333c3c8c553SJan Lentfer kprintf("pfsync_insert_net_state: "
33402742ec6SJoerg Sonnenberger "unknown interface: %s\n", sp->ifname);
335ed1f0be2SJan Lentfer if (flags & PFSYNC_SI_IOCTL)
336ed1f0be2SJan Lentfer return (EINVAL);
337ed1f0be2SJan Lentfer return (0); /* skip this state */
33802742ec6SJoerg Sonnenberger }
33902742ec6SJoerg Sonnenberger
34002742ec6SJoerg Sonnenberger /*
341ed1f0be2SJan Lentfer * If the ruleset checksums match or the state is coming from the ioctl,
342ed1f0be2SJan Lentfer * it's safe to associate the state with the rule of that number.
34302742ec6SJoerg Sonnenberger */
344ed1f0be2SJan Lentfer if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
345ed1f0be2SJan Lentfer (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
346315a7da3SJan Lentfer pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
34770224baaSJan Lentfer r = pf_main_ruleset.rules[
34870224baaSJan Lentfer PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
34970224baaSJan Lentfer else
35002742ec6SJoerg Sonnenberger r = &pf_default_rule;
35102742ec6SJoerg Sonnenberger
352ed1f0be2SJan Lentfer if ((r->max_states && r->states_cur >= r->max_states))
353ed1f0be2SJan Lentfer goto cleanup;
35402742ec6SJoerg Sonnenberger
355ed1f0be2SJan Lentfer if (flags & PFSYNC_SI_IOCTL)
3561186cbc0SJan Lentfer pool_flags = M_WAITOK | M_NULLOK | M_ZERO;
357ed1f0be2SJan Lentfer else
3581186cbc0SJan Lentfer pool_flags = M_WAITOK | M_ZERO;
359ed1f0be2SJan Lentfer
3601186cbc0SJan Lentfer if ((st = kmalloc(sizeof(struct pf_state), M_PFSYNC, pool_flags)) == NULL)
361ed1f0be2SJan Lentfer goto cleanup;
36232772c96SMatthew Dillon lockinit(&st->lk, "pfstlk", 0, 0);
363ed1f0be2SJan Lentfer
364ed1f0be2SJan Lentfer if ((skw = pf_alloc_state_key(pool_flags)) == NULL)
365ed1f0be2SJan Lentfer goto cleanup;
366ed1f0be2SJan Lentfer
367ed1f0be2SJan Lentfer if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0],
368ed1f0be2SJan Lentfer &sp->key[PF_SK_STACK].addr[0], sp->af) ||
369ed1f0be2SJan Lentfer PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1],
370ed1f0be2SJan Lentfer &sp->key[PF_SK_STACK].addr[1], sp->af) ||
371ed1f0be2SJan Lentfer sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] ||
372ed1f0be2SJan Lentfer sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) {
373ed1f0be2SJan Lentfer if ((sks = pf_alloc_state_key(pool_flags)) == NULL)
374ed1f0be2SJan Lentfer goto cleanup;
375ed1f0be2SJan Lentfer } else
376ed1f0be2SJan Lentfer sks = skw;
377315a7da3SJan Lentfer
37870224baaSJan Lentfer /* allocate memory for scrub info */
37970224baaSJan Lentfer if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
380ed1f0be2SJan Lentfer pfsync_alloc_scrub_memory(&sp->dst, &st->dst))
381ed1f0be2SJan Lentfer goto cleanup;
382ed1f0be2SJan Lentfer
383ed1f0be2SJan Lentfer /* copy to state key(s) */
384ed1f0be2SJan Lentfer skw->addr[0] = sp->key[PF_SK_WIRE].addr[0];
385ed1f0be2SJan Lentfer skw->addr[1] = sp->key[PF_SK_WIRE].addr[1];
386ed1f0be2SJan Lentfer skw->port[0] = sp->key[PF_SK_WIRE].port[0];
387ed1f0be2SJan Lentfer skw->port[1] = sp->key[PF_SK_WIRE].port[1];
388ed1f0be2SJan Lentfer skw->proto = sp->proto;
389ed1f0be2SJan Lentfer skw->af = sp->af;
390ed1f0be2SJan Lentfer if (sks != skw) {
391ed1f0be2SJan Lentfer sks->addr[0] = sp->key[PF_SK_STACK].addr[0];
392ed1f0be2SJan Lentfer sks->addr[1] = sp->key[PF_SK_STACK].addr[1];
393ed1f0be2SJan Lentfer sks->port[0] = sp->key[PF_SK_STACK].port[0];
394ed1f0be2SJan Lentfer sks->port[1] = sp->key[PF_SK_STACK].port[1];
395ed1f0be2SJan Lentfer sks->proto = sp->proto;
396ed1f0be2SJan Lentfer sks->af = sp->af;
39770224baaSJan Lentfer }
39870224baaSJan Lentfer
399ed1f0be2SJan Lentfer /* copy to state */
40002742ec6SJoerg Sonnenberger bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
40170224baaSJan Lentfer st->creation = time_second - ntohl(sp->creation);
402ed1f0be2SJan Lentfer st->expire = time_second;
403ed1f0be2SJan Lentfer if (sp->expire) {
404ed1f0be2SJan Lentfer /* XXX No adaptive scaling. */
405ed1f0be2SJan Lentfer st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire);
406ed1f0be2SJan Lentfer }
40702742ec6SJoerg Sonnenberger
408ed1f0be2SJan Lentfer st->expire = ntohl(sp->expire) + time_second;
409ed1f0be2SJan Lentfer st->direction = sp->direction;
41002742ec6SJoerg Sonnenberger st->log = sp->log;
41102742ec6SJoerg Sonnenberger st->timeout = sp->timeout;
412ed1f0be2SJan Lentfer st->state_flags = sp->state_flags;
413ed1f0be2SJan Lentfer if (!(flags & PFSYNC_SI_IOCTL))
414ed1f0be2SJan Lentfer st->sync_flags = PFSTATE_FROMSYNC;
41502742ec6SJoerg Sonnenberger
41602742ec6SJoerg Sonnenberger bcopy(sp->id, &st->id, sizeof(st->id));
41702742ec6SJoerg Sonnenberger st->creatorid = sp->creatorid;
418ed1f0be2SJan Lentfer pf_state_peer_ntoh(&sp->src, &st->src);
419ed1f0be2SJan Lentfer pf_state_peer_ntoh(&sp->dst, &st->dst);
42002742ec6SJoerg Sonnenberger
421ed1f0be2SJan Lentfer st->rule.ptr = r;
422ed1f0be2SJan Lentfer st->nat_rule.ptr = NULL;
423ed1f0be2SJan Lentfer st->anchor.ptr = NULL;
424ed1f0be2SJan Lentfer st->rt_kif = NULL;
425ed1f0be2SJan Lentfer
426ed1f0be2SJan Lentfer st->pfsync_time = 0;
427ed1f0be2SJan Lentfer
428ed1f0be2SJan Lentfer
429ed1f0be2SJan Lentfer /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
430ed1f0be2SJan Lentfer r->states_cur++;
431ed1f0be2SJan Lentfer r->states_tot++;
432ed1f0be2SJan Lentfer
433ed1f0be2SJan Lentfer if ((error = pf_state_insert(kif, skw, sks, st)) != 0) {
43470224baaSJan Lentfer /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
435ed1f0be2SJan Lentfer r->states_cur--;
436ed1f0be2SJan Lentfer goto cleanup_state;
437ed1f0be2SJan Lentfer }
438ed1f0be2SJan Lentfer
439ed1f0be2SJan Lentfer return (0);
440ed1f0be2SJan Lentfer
441ed1f0be2SJan Lentfer cleanup:
442ed1f0be2SJan Lentfer error = ENOMEM;
443ed1f0be2SJan Lentfer if (skw == sks)
444ed1f0be2SJan Lentfer sks = NULL;
445ed1f0be2SJan Lentfer if (skw != NULL)
4461186cbc0SJan Lentfer kfree(skw, M_PFSYNC);
447ed1f0be2SJan Lentfer if (sks != NULL)
4481186cbc0SJan Lentfer kfree(sks, M_PFSYNC);
449ed1f0be2SJan Lentfer
450ed1f0be2SJan Lentfer cleanup_state: /* pf_state_insert frees the state keys */
451ed1f0be2SJan Lentfer if (st) {
45270224baaSJan Lentfer if (st->dst.scrub)
4531186cbc0SJan Lentfer kfree(st->dst.scrub, M_PFSYNC);
45470224baaSJan Lentfer if (st->src.scrub)
4551186cbc0SJan Lentfer kfree(st->src.scrub, M_PFSYNC);
4561186cbc0SJan Lentfer kfree(st, M_PFSYNC);
45702742ec6SJoerg Sonnenberger }
458ed1f0be2SJan Lentfer return (error);
45902742ec6SJoerg Sonnenberger }
46002742ec6SJoerg Sonnenberger
46102742ec6SJoerg Sonnenberger void
pfsync_input(struct mbuf * m,...)46202742ec6SJoerg Sonnenberger pfsync_input(struct mbuf *m, ...)
46302742ec6SJoerg Sonnenberger {
46402742ec6SJoerg Sonnenberger struct ip *ip = mtod(m, struct ip *);
46502742ec6SJoerg Sonnenberger struct pfsync_header *ph;
46670224baaSJan Lentfer struct pfsync_softc *sc = pfsyncif;
46770224baaSJan Lentfer struct pf_state *st;
468315a7da3SJan Lentfer struct pf_state_key *sk;
469ed1f0be2SJan Lentfer struct pf_state_item *si;
470315a7da3SJan Lentfer struct pf_state_cmp id_key;
47102742ec6SJoerg Sonnenberger struct pfsync_state *sp;
47202742ec6SJoerg Sonnenberger struct pfsync_state_upd *up;
47302742ec6SJoerg Sonnenberger struct pfsync_state_del *dp;
47402742ec6SJoerg Sonnenberger struct pfsync_state_clr *cp;
47502742ec6SJoerg Sonnenberger struct pfsync_state_upd_req *rup;
47602742ec6SJoerg Sonnenberger struct pfsync_state_bus *bus;
47702742ec6SJoerg Sonnenberger struct in_addr src;
47802742ec6SJoerg Sonnenberger struct mbuf *mp;
479c3c8c553SJan Lentfer int iplen, action, error, i, count, offp, sfail, stale = 0;
480ed1f0be2SJan Lentfer u_int8_t flags = 0;
48102742ec6SJoerg Sonnenberger
4822a7a2b1cSJan Lentfer /* This function is not yet called from anywhere */
4832a7a2b1cSJan Lentfer /* Still we assume for safety that pf_token must be held */
4842a7a2b1cSJan Lentfer ASSERT_LWKT_TOKEN_HELD(&pf_token);
4852a7a2b1cSJan Lentfer
48602742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_ipackets++;
48702742ec6SJoerg Sonnenberger
48802742ec6SJoerg Sonnenberger /* verify that we have a sync interface configured */
48970224baaSJan Lentfer if (!sc || !sc->sc_sync_ifp || !pf_status.running)
49002742ec6SJoerg Sonnenberger goto done;
49102742ec6SJoerg Sonnenberger
49202742ec6SJoerg Sonnenberger /* verify that the packet came in on the right interface */
49302742ec6SJoerg Sonnenberger if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
49402742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badif++;
49502742ec6SJoerg Sonnenberger goto done;
49602742ec6SJoerg Sonnenberger }
49702742ec6SJoerg Sonnenberger
49802742ec6SJoerg Sonnenberger /* verify that the IP TTL is 255. */
49902742ec6SJoerg Sonnenberger if (ip->ip_ttl != PFSYNC_DFLTTL) {
50002742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badttl++;
50102742ec6SJoerg Sonnenberger goto done;
50202742ec6SJoerg Sonnenberger }
50302742ec6SJoerg Sonnenberger
50402742ec6SJoerg Sonnenberger iplen = ip->ip_hl << 2;
50502742ec6SJoerg Sonnenberger
50602742ec6SJoerg Sonnenberger if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
50702742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_hdrops++;
50802742ec6SJoerg Sonnenberger goto done;
50902742ec6SJoerg Sonnenberger }
51002742ec6SJoerg Sonnenberger
51102742ec6SJoerg Sonnenberger if (iplen + sizeof(*ph) > m->m_len) {
51202742ec6SJoerg Sonnenberger if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
51302742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_hdrops++;
51402742ec6SJoerg Sonnenberger goto done;
51502742ec6SJoerg Sonnenberger }
51602742ec6SJoerg Sonnenberger ip = mtod(m, struct ip *);
51702742ec6SJoerg Sonnenberger }
51802742ec6SJoerg Sonnenberger ph = (struct pfsync_header *)((char *)ip + iplen);
51902742ec6SJoerg Sonnenberger
52002742ec6SJoerg Sonnenberger /* verify the version */
52102742ec6SJoerg Sonnenberger if (ph->version != PFSYNC_VERSION) {
52202742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badver++;
52302742ec6SJoerg Sonnenberger goto done;
52402742ec6SJoerg Sonnenberger }
52502742ec6SJoerg Sonnenberger
52602742ec6SJoerg Sonnenberger action = ph->action;
52702742ec6SJoerg Sonnenberger count = ph->count;
52802742ec6SJoerg Sonnenberger
52902742ec6SJoerg Sonnenberger /* make sure it's a valid action code */
53002742ec6SJoerg Sonnenberger if (action >= PFSYNC_ACT_MAX) {
53102742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badact++;
53202742ec6SJoerg Sonnenberger goto done;
53302742ec6SJoerg Sonnenberger }
53402742ec6SJoerg Sonnenberger
53502742ec6SJoerg Sonnenberger /* Cheaper to grab this now than having to mess with mbufs later */
53602742ec6SJoerg Sonnenberger src = ip->ip_src;
53702742ec6SJoerg Sonnenberger
53870224baaSJan Lentfer if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
539ed1f0be2SJan Lentfer flags |= PFSYNC_SI_CKSUM;
54070224baaSJan Lentfer
54102742ec6SJoerg Sonnenberger switch (action) {
54202742ec6SJoerg Sonnenberger case PFSYNC_ACT_CLR: {
54370224baaSJan Lentfer struct pf_state *nexts;
544315a7da3SJan Lentfer struct pf_state_key *nextsk;
54502742ec6SJoerg Sonnenberger struct pfi_kif *kif;
5463a0038bfSMatthew Dillon globaldata_t save_gd = mycpu;
5473a0038bfSMatthew Dillon int nn;
5483a0038bfSMatthew Dillon
54902742ec6SJoerg Sonnenberger u_int32_t creatorid;
55002742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
55102742ec6SJoerg Sonnenberger sizeof(*cp), &offp)) == NULL) {
55202742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
55302742ec6SJoerg Sonnenberger return;
55402742ec6SJoerg Sonnenberger }
55502742ec6SJoerg Sonnenberger cp = (struct pfsync_state_clr *)(mp->m_data + offp);
55602742ec6SJoerg Sonnenberger creatorid = cp->creatorid;
55702742ec6SJoerg Sonnenberger
558c3c8c553SJan Lentfer crit_enter();
55902742ec6SJoerg Sonnenberger if (cp->ifname[0] == '\0') {
5603a0038bfSMatthew Dillon lwkt_gettoken(&pf_token);
5613a0038bfSMatthew Dillon for (nn = 0; nn < ncpus; ++nn) {
5623a0038bfSMatthew Dillon lwkt_setcpu_self(globaldata_find(nn));
5633a0038bfSMatthew Dillon for (st = RB_MIN(pf_state_tree_id,
5643a0038bfSMatthew Dillon &tree_id[nn]);
56570224baaSJan Lentfer st; st = nexts) {
5663a0038bfSMatthew Dillon nexts = RB_NEXT(pf_state_tree_id,
5673a0038bfSMatthew Dillon &tree_id[n], st);
56870224baaSJan Lentfer if (st->creatorid == creatorid) {
5693a0038bfSMatthew Dillon st->sync_flags |=
5703a0038bfSMatthew Dillon PFSTATE_FROMSYNC;
57170224baaSJan Lentfer pf_unlink_state(st);
57270224baaSJan Lentfer }
57302742ec6SJoerg Sonnenberger }
5743a0038bfSMatthew Dillon }
5753a0038bfSMatthew Dillon lwkt_setcpu_self(save_gd);
5763a0038bfSMatthew Dillon lwkt_reltoken(&pf_token);
57702742ec6SJoerg Sonnenberger } else {
57870224baaSJan Lentfer if ((kif = pfi_kif_get(cp->ifname)) == NULL) {
579c3c8c553SJan Lentfer crit_exit();
58070224baaSJan Lentfer return;
58102742ec6SJoerg Sonnenberger }
582ed1f0be2SJan Lentfer /* XXX correct? */
5833a0038bfSMatthew Dillon lwkt_gettoken(&pf_token);
5843a0038bfSMatthew Dillon for (nn = 0; nn < ncpus; ++nn) {
5853a0038bfSMatthew Dillon lwkt_setcpu_self(globaldata_find(nn));
586ed1f0be2SJan Lentfer for (sk = RB_MIN(pf_state_tree,
5873a0038bfSMatthew Dillon &pf_statetbl[nn]);
5883a0038bfSMatthew Dillon sk;
5893a0038bfSMatthew Dillon sk = nextsk) {
590ed1f0be2SJan Lentfer nextsk = RB_NEXT(pf_state_tree,
5913a0038bfSMatthew Dillon &pf_statetbl[n], sk);
592ed1f0be2SJan Lentfer TAILQ_FOREACH(si, &sk->states, entry) {
5933a0038bfSMatthew Dillon if (si->s->creatorid ==
5943a0038bfSMatthew Dillon creatorid) {
595ed1f0be2SJan Lentfer si->s->sync_flags |=
596315a7da3SJan Lentfer PFSTATE_FROMSYNC;
597ed1f0be2SJan Lentfer pf_unlink_state(si->s);
59802742ec6SJoerg Sonnenberger }
59902742ec6SJoerg Sonnenberger }
60070224baaSJan Lentfer }
601315a7da3SJan Lentfer }
6023a0038bfSMatthew Dillon lwkt_setcpu_self(save_gd);
6033a0038bfSMatthew Dillon lwkt_reltoken(&pf_token);
6043a0038bfSMatthew Dillon }
605c3c8c553SJan Lentfer crit_exit();
60602742ec6SJoerg Sonnenberger
60702742ec6SJoerg Sonnenberger break;
60802742ec6SJoerg Sonnenberger }
60902742ec6SJoerg Sonnenberger case PFSYNC_ACT_INS:
61002742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
61102742ec6SJoerg Sonnenberger count * sizeof(*sp), &offp)) == NULL) {
61202742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
61302742ec6SJoerg Sonnenberger return;
61402742ec6SJoerg Sonnenberger }
61502742ec6SJoerg Sonnenberger
616c3c8c553SJan Lentfer crit_enter();
61702742ec6SJoerg Sonnenberger for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
61802742ec6SJoerg Sonnenberger i < count; i++, sp++) {
61902742ec6SJoerg Sonnenberger /* check for invalid values */
62002742ec6SJoerg Sonnenberger if (sp->timeout >= PFTM_MAX ||
62102742ec6SJoerg Sonnenberger sp->src.state > PF_TCPS_PROXY_DST ||
62202742ec6SJoerg Sonnenberger sp->dst.state > PF_TCPS_PROXY_DST ||
62302742ec6SJoerg Sonnenberger sp->direction > PF_OUT ||
62402742ec6SJoerg Sonnenberger (sp->af != AF_INET && sp->af != AF_INET6)) {
62502742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
626c3c8c553SJan Lentfer kprintf("pfsync_insert: PFSYNC_ACT_INS: "
62702742ec6SJoerg Sonnenberger "invalid value\n");
628ed1f0be2SJan Lentfer pfsyncstats.pfsyncs_badval++;
62902742ec6SJoerg Sonnenberger continue;
63002742ec6SJoerg Sonnenberger }
63102742ec6SJoerg Sonnenberger
632ed1f0be2SJan Lentfer if ((error = pfsync_state_import(sp, flags))) {
63302742ec6SJoerg Sonnenberger if (error == ENOMEM) {
634c3c8c553SJan Lentfer crit_exit();
63502742ec6SJoerg Sonnenberger goto done;
63602742ec6SJoerg Sonnenberger }
63702742ec6SJoerg Sonnenberger }
63802742ec6SJoerg Sonnenberger }
639c3c8c553SJan Lentfer crit_exit();
64002742ec6SJoerg Sonnenberger break;
64102742ec6SJoerg Sonnenberger case PFSYNC_ACT_UPD:
64202742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
64302742ec6SJoerg Sonnenberger count * sizeof(*sp), &offp)) == NULL) {
64402742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
64502742ec6SJoerg Sonnenberger return;
64602742ec6SJoerg Sonnenberger }
64702742ec6SJoerg Sonnenberger
648c3c8c553SJan Lentfer crit_enter();
64902742ec6SJoerg Sonnenberger for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
65002742ec6SJoerg Sonnenberger i < count; i++, sp++) {
65170224baaSJan Lentfer int flags = PFSYNC_FLAG_STALE;
65270224baaSJan Lentfer
65302742ec6SJoerg Sonnenberger /* check for invalid values */
65402742ec6SJoerg Sonnenberger if (sp->timeout >= PFTM_MAX ||
65502742ec6SJoerg Sonnenberger sp->src.state > PF_TCPS_PROXY_DST ||
65602742ec6SJoerg Sonnenberger sp->dst.state > PF_TCPS_PROXY_DST) {
65702742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
658c3c8c553SJan Lentfer kprintf("pfsync_insert: PFSYNC_ACT_UPD: "
65902742ec6SJoerg Sonnenberger "invalid value\n");
660ed1f0be2SJan Lentfer pfsyncstats.pfsyncs_badval++;
66102742ec6SJoerg Sonnenberger continue;
66202742ec6SJoerg Sonnenberger }
66302742ec6SJoerg Sonnenberger
664315a7da3SJan Lentfer bcopy(sp->id, &id_key.id, sizeof(id_key.id));
665315a7da3SJan Lentfer id_key.creatorid = sp->creatorid;
66602742ec6SJoerg Sonnenberger
667315a7da3SJan Lentfer st = pf_find_state_byid(&id_key);
66802742ec6SJoerg Sonnenberger if (st == NULL) {
66902742ec6SJoerg Sonnenberger /* insert the update */
670ed1f0be2SJan Lentfer if (pfsync_state_import(sp, flags))
67102742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badstate++;
67202742ec6SJoerg Sonnenberger continue;
67302742ec6SJoerg Sonnenberger }
674ed1f0be2SJan Lentfer sk = st->key[PF_SK_WIRE]; /* XXX right one? */
67570224baaSJan Lentfer sfail = 0;
676315a7da3SJan Lentfer if (sk->proto == IPPROTO_TCP) {
67770224baaSJan Lentfer /*
67870224baaSJan Lentfer * The state should never go backwards except
67970224baaSJan Lentfer * for syn-proxy states. Neither should the
68070224baaSJan Lentfer * sequence window slide backwards.
68170224baaSJan Lentfer */
68270224baaSJan Lentfer if (st->src.state > sp->src.state &&
68370224baaSJan Lentfer (st->src.state < PF_TCPS_PROXY_SRC ||
68470224baaSJan Lentfer sp->src.state >= PF_TCPS_PROXY_SRC))
68570224baaSJan Lentfer sfail = 1;
68670224baaSJan Lentfer else if (SEQ_GT(st->src.seqlo,
68770224baaSJan Lentfer ntohl(sp->src.seqlo)))
68870224baaSJan Lentfer sfail = 3;
68970224baaSJan Lentfer else if (st->dst.state > sp->dst.state) {
69070224baaSJan Lentfer /* There might still be useful
69170224baaSJan Lentfer * information about the src state here,
69270224baaSJan Lentfer * so import that part of the update,
69370224baaSJan Lentfer * then "fail" so we send the updated
69470224baaSJan Lentfer * state back to the peer who is missing
69570224baaSJan Lentfer * our what we know. */
69670224baaSJan Lentfer pf_state_peer_ntoh(&sp->src, &st->src);
69770224baaSJan Lentfer /* XXX do anything with timeouts? */
69870224baaSJan Lentfer sfail = 7;
69970224baaSJan Lentfer flags = 0;
70070224baaSJan Lentfer } else if (st->dst.state >= TCPS_SYN_SENT &&
70170224baaSJan Lentfer SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
70270224baaSJan Lentfer sfail = 4;
70370224baaSJan Lentfer } else {
70470224baaSJan Lentfer /*
70570224baaSJan Lentfer * Non-TCP protocol state machine always go
70670224baaSJan Lentfer * forwards
70770224baaSJan Lentfer */
70870224baaSJan Lentfer if (st->src.state > sp->src.state)
70970224baaSJan Lentfer sfail = 5;
71070224baaSJan Lentfer else if (st->dst.state > sp->dst.state)
71170224baaSJan Lentfer sfail = 6;
71270224baaSJan Lentfer }
71370224baaSJan Lentfer if (sfail) {
71470224baaSJan Lentfer if (pf_status.debug >= PF_DEBUG_MISC)
715c3c8c553SJan Lentfer kprintf("pfsync: %s stale update "
7168dfe42a9SSascha Wildner "(%d) id: %016jx "
71770224baaSJan Lentfer "creatorid: %08x\n",
71870224baaSJan Lentfer (sfail < 7 ? "ignoring"
71970224baaSJan Lentfer : "partial"), sfail,
7208dfe42a9SSascha Wildner (uintmax_t)be64toh(st->id),
72170224baaSJan Lentfer ntohl(st->creatorid));
722ed1f0be2SJan Lentfer pfsyncstats.pfsyncs_stale++;
72370224baaSJan Lentfer
72470224baaSJan Lentfer if (!(sp->sync_flags & PFSTATE_STALE)) {
72570224baaSJan Lentfer /* we have a better state, send it */
72670224baaSJan Lentfer if (sc->sc_mbuf != NULL && !stale)
72770224baaSJan Lentfer pfsync_sendout(sc);
72870224baaSJan Lentfer stale++;
72970224baaSJan Lentfer if (!st->sync_flags)
73070224baaSJan Lentfer pfsync_pack_state(
73170224baaSJan Lentfer PFSYNC_ACT_UPD, st, flags);
73270224baaSJan Lentfer }
73370224baaSJan Lentfer continue;
73470224baaSJan Lentfer }
73570224baaSJan Lentfer pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
73602742ec6SJoerg Sonnenberger pf_state_peer_ntoh(&sp->src, &st->src);
73702742ec6SJoerg Sonnenberger pf_state_peer_ntoh(&sp->dst, &st->dst);
73802742ec6SJoerg Sonnenberger st->expire = ntohl(sp->expire) + time_second;
73902742ec6SJoerg Sonnenberger st->timeout = sp->timeout;
74002742ec6SJoerg Sonnenberger }
74170224baaSJan Lentfer if (stale && sc->sc_mbuf != NULL)
74270224baaSJan Lentfer pfsync_sendout(sc);
743c3c8c553SJan Lentfer crit_exit();
74402742ec6SJoerg Sonnenberger break;
74502742ec6SJoerg Sonnenberger /*
74602742ec6SJoerg Sonnenberger * It's not strictly necessary for us to support the "uncompressed"
74702742ec6SJoerg Sonnenberger * delete action, but it's relatively simple and maintains consistency.
74802742ec6SJoerg Sonnenberger */
74902742ec6SJoerg Sonnenberger case PFSYNC_ACT_DEL:
75002742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
75102742ec6SJoerg Sonnenberger count * sizeof(*sp), &offp)) == NULL) {
75202742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
75302742ec6SJoerg Sonnenberger return;
75402742ec6SJoerg Sonnenberger }
75502742ec6SJoerg Sonnenberger
756c3c8c553SJan Lentfer crit_enter();
75702742ec6SJoerg Sonnenberger for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
75802742ec6SJoerg Sonnenberger i < count; i++, sp++) {
759315a7da3SJan Lentfer bcopy(sp->id, &id_key.id, sizeof(id_key.id));
760315a7da3SJan Lentfer id_key.creatorid = sp->creatorid;
76102742ec6SJoerg Sonnenberger
762315a7da3SJan Lentfer st = pf_find_state_byid(&id_key);
76302742ec6SJoerg Sonnenberger if (st == NULL) {
76402742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badstate++;
76502742ec6SJoerg Sonnenberger continue;
76602742ec6SJoerg Sonnenberger }
76702742ec6SJoerg Sonnenberger st->sync_flags |= PFSTATE_FROMSYNC;
76870224baaSJan Lentfer pf_unlink_state(st);
76902742ec6SJoerg Sonnenberger }
770c3c8c553SJan Lentfer crit_exit();
77102742ec6SJoerg Sonnenberger break;
77202742ec6SJoerg Sonnenberger case PFSYNC_ACT_UPD_C: {
77302742ec6SJoerg Sonnenberger int update_requested = 0;
77402742ec6SJoerg Sonnenberger
77502742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
77602742ec6SJoerg Sonnenberger count * sizeof(*up), &offp)) == NULL) {
77702742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
77802742ec6SJoerg Sonnenberger return;
77902742ec6SJoerg Sonnenberger }
78002742ec6SJoerg Sonnenberger
781c3c8c553SJan Lentfer crit_enter();
78202742ec6SJoerg Sonnenberger for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
78302742ec6SJoerg Sonnenberger i < count; i++, up++) {
78402742ec6SJoerg Sonnenberger /* check for invalid values */
78502742ec6SJoerg Sonnenberger if (up->timeout >= PFTM_MAX ||
78602742ec6SJoerg Sonnenberger up->src.state > PF_TCPS_PROXY_DST ||
78702742ec6SJoerg Sonnenberger up->dst.state > PF_TCPS_PROXY_DST) {
78802742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
789c3c8c553SJan Lentfer kprintf("pfsync_insert: "
79002742ec6SJoerg Sonnenberger "PFSYNC_ACT_UPD_C: "
79102742ec6SJoerg Sonnenberger "invalid value\n");
792ed1f0be2SJan Lentfer pfsyncstats.pfsyncs_badval++;
79302742ec6SJoerg Sonnenberger continue;
79402742ec6SJoerg Sonnenberger }
79502742ec6SJoerg Sonnenberger
796315a7da3SJan Lentfer bcopy(up->id, &id_key.id, sizeof(id_key.id));
797315a7da3SJan Lentfer id_key.creatorid = up->creatorid;
79802742ec6SJoerg Sonnenberger
799315a7da3SJan Lentfer st = pf_find_state_byid(&id_key);
80002742ec6SJoerg Sonnenberger if (st == NULL) {
80102742ec6SJoerg Sonnenberger /* We don't have this state. Ask for it. */
80270224baaSJan Lentfer error = pfsync_request_update(up, &src);
80370224baaSJan Lentfer if (error == ENOMEM) {
804c3c8c553SJan Lentfer crit_exit();
80570224baaSJan Lentfer goto done;
80670224baaSJan Lentfer }
80702742ec6SJoerg Sonnenberger update_requested = 1;
80802742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badstate++;
80902742ec6SJoerg Sonnenberger continue;
81002742ec6SJoerg Sonnenberger }
811ed1f0be2SJan Lentfer sk = st->key[PF_SK_WIRE]; /* XXX right one? */
81270224baaSJan Lentfer sfail = 0;
813315a7da3SJan Lentfer if (sk->proto == IPPROTO_TCP) {
81470224baaSJan Lentfer /*
81570224baaSJan Lentfer * The state should never go backwards except
81670224baaSJan Lentfer * for syn-proxy states. Neither should the
81770224baaSJan Lentfer * sequence window slide backwards.
81870224baaSJan Lentfer */
81970224baaSJan Lentfer if (st->src.state > up->src.state &&
82070224baaSJan Lentfer (st->src.state < PF_TCPS_PROXY_SRC ||
82170224baaSJan Lentfer up->src.state >= PF_TCPS_PROXY_SRC))
82270224baaSJan Lentfer sfail = 1;
82370224baaSJan Lentfer else if (st->dst.state > up->dst.state)
82470224baaSJan Lentfer sfail = 2;
82570224baaSJan Lentfer else if (SEQ_GT(st->src.seqlo,
82670224baaSJan Lentfer ntohl(up->src.seqlo)))
82770224baaSJan Lentfer sfail = 3;
82870224baaSJan Lentfer else if (st->dst.state >= TCPS_SYN_SENT &&
82970224baaSJan Lentfer SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
83070224baaSJan Lentfer sfail = 4;
83170224baaSJan Lentfer } else {
83270224baaSJan Lentfer /*
83370224baaSJan Lentfer * Non-TCP protocol state machine always go
83470224baaSJan Lentfer * forwards
83570224baaSJan Lentfer */
83670224baaSJan Lentfer if (st->src.state > up->src.state)
83770224baaSJan Lentfer sfail = 5;
83870224baaSJan Lentfer else if (st->dst.state > up->dst.state)
83970224baaSJan Lentfer sfail = 6;
84070224baaSJan Lentfer }
84170224baaSJan Lentfer if (sfail) {
84270224baaSJan Lentfer if (pf_status.debug >= PF_DEBUG_MISC)
843c3c8c553SJan Lentfer kprintf("pfsync: ignoring stale update "
84478775ca5SSascha Wildner "(%d) id: %016" PRIx64 " "
84570224baaSJan Lentfer "creatorid: %08x\n", sfail,
846c3c8c553SJan Lentfer be64toh(st->id),
84770224baaSJan Lentfer ntohl(st->creatorid));
848ed1f0be2SJan Lentfer pfsyncstats.pfsyncs_stale++;
84970224baaSJan Lentfer
85070224baaSJan Lentfer /* we have a better state, send it out */
85170224baaSJan Lentfer if ((!stale || update_requested) &&
85270224baaSJan Lentfer sc->sc_mbuf != NULL) {
85370224baaSJan Lentfer pfsync_sendout(sc);
85470224baaSJan Lentfer update_requested = 0;
85570224baaSJan Lentfer }
85670224baaSJan Lentfer stale++;
85770224baaSJan Lentfer if (!st->sync_flags)
85870224baaSJan Lentfer pfsync_pack_state(PFSYNC_ACT_UPD, st,
85970224baaSJan Lentfer PFSYNC_FLAG_STALE);
86070224baaSJan Lentfer continue;
86170224baaSJan Lentfer }
86270224baaSJan Lentfer pfsync_alloc_scrub_memory(&up->dst, &st->dst);
86302742ec6SJoerg Sonnenberger pf_state_peer_ntoh(&up->src, &st->src);
86402742ec6SJoerg Sonnenberger pf_state_peer_ntoh(&up->dst, &st->dst);
86502742ec6SJoerg Sonnenberger st->expire = ntohl(up->expire) + time_second;
86602742ec6SJoerg Sonnenberger st->timeout = up->timeout;
86702742ec6SJoerg Sonnenberger }
86870224baaSJan Lentfer if ((update_requested || stale) && sc->sc_mbuf)
86902742ec6SJoerg Sonnenberger pfsync_sendout(sc);
870c3c8c553SJan Lentfer crit_exit();
87102742ec6SJoerg Sonnenberger break;
87202742ec6SJoerg Sonnenberger }
87302742ec6SJoerg Sonnenberger case PFSYNC_ACT_DEL_C:
87402742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
87502742ec6SJoerg Sonnenberger count * sizeof(*dp), &offp)) == NULL) {
87602742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
87702742ec6SJoerg Sonnenberger return;
87802742ec6SJoerg Sonnenberger }
87902742ec6SJoerg Sonnenberger
880c3c8c553SJan Lentfer crit_enter();
88102742ec6SJoerg Sonnenberger for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
88202742ec6SJoerg Sonnenberger i < count; i++, dp++) {
883315a7da3SJan Lentfer bcopy(dp->id, &id_key.id, sizeof(id_key.id));
884315a7da3SJan Lentfer id_key.creatorid = dp->creatorid;
88502742ec6SJoerg Sonnenberger
886315a7da3SJan Lentfer st = pf_find_state_byid(&id_key);
88702742ec6SJoerg Sonnenberger if (st == NULL) {
88802742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badstate++;
88902742ec6SJoerg Sonnenberger continue;
89002742ec6SJoerg Sonnenberger }
89102742ec6SJoerg Sonnenberger st->sync_flags |= PFSTATE_FROMSYNC;
89270224baaSJan Lentfer pf_unlink_state(st);
89302742ec6SJoerg Sonnenberger }
894c3c8c553SJan Lentfer crit_exit();
89502742ec6SJoerg Sonnenberger break;
89602742ec6SJoerg Sonnenberger case PFSYNC_ACT_INS_F:
89702742ec6SJoerg Sonnenberger case PFSYNC_ACT_DEL_F:
89802742ec6SJoerg Sonnenberger /* not implemented */
89902742ec6SJoerg Sonnenberger break;
90002742ec6SJoerg Sonnenberger case PFSYNC_ACT_UREQ:
90102742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
90202742ec6SJoerg Sonnenberger count * sizeof(*rup), &offp)) == NULL) {
90302742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
90402742ec6SJoerg Sonnenberger return;
90502742ec6SJoerg Sonnenberger }
90602742ec6SJoerg Sonnenberger
907c3c8c553SJan Lentfer crit_enter();
90802742ec6SJoerg Sonnenberger if (sc->sc_mbuf != NULL)
90902742ec6SJoerg Sonnenberger pfsync_sendout(sc);
91002742ec6SJoerg Sonnenberger for (i = 0,
91102742ec6SJoerg Sonnenberger rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
91202742ec6SJoerg Sonnenberger i < count; i++, rup++) {
913315a7da3SJan Lentfer bcopy(rup->id, &id_key.id, sizeof(id_key.id));
914315a7da3SJan Lentfer id_key.creatorid = rup->creatorid;
91502742ec6SJoerg Sonnenberger
916315a7da3SJan Lentfer if (id_key.id == 0 && id_key.creatorid == 0) {
917c3c8c553SJan Lentfer sc->sc_ureq_received = mycpu->gd_time_seconds;
9183a0038bfSMatthew Dillon if (sc->sc_bulk_send_next == NULL) {
9193a0038bfSMatthew Dillon if (++sc->sc_bulk_send_cpu >= ncpus)
9203a0038bfSMatthew Dillon sc->sc_bulk_send_cpu = 0;
92170224baaSJan Lentfer sc->sc_bulk_send_next =
9223a0038bfSMatthew Dillon TAILQ_FIRST(&state_list[sc->sc_bulk_send_cpu]);
9233a0038bfSMatthew Dillon }
9243a0038bfSMatthew Dillon sc->sc_bulk_terminator =
9253a0038bfSMatthew Dillon sc->sc_bulk_send_next;
9263a0038bfSMatthew Dillon sc->sc_bulk_terminator_cpu =
9273a0038bfSMatthew Dillon sc->sc_bulk_send_cpu;
92802742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
929c3c8c553SJan Lentfer kprintf("pfsync: received "
93002742ec6SJoerg Sonnenberger "bulk update request\n");
93102742ec6SJoerg Sonnenberger pfsync_send_bus(sc, PFSYNC_BUS_START);
9322a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
933ed1f0be2SJan Lentfer callout_init(&sc->sc_bulk_tmo);
9342a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
93502742ec6SJoerg Sonnenberger } else {
936315a7da3SJan Lentfer st = pf_find_state_byid(&id_key);
93702742ec6SJoerg Sonnenberger if (st == NULL) {
93802742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badstate++;
93902742ec6SJoerg Sonnenberger continue;
94002742ec6SJoerg Sonnenberger }
94170224baaSJan Lentfer if (!st->sync_flags)
94270224baaSJan Lentfer pfsync_pack_state(PFSYNC_ACT_UPD,
94370224baaSJan Lentfer st, 0);
94402742ec6SJoerg Sonnenberger }
94502742ec6SJoerg Sonnenberger }
94602742ec6SJoerg Sonnenberger if (sc->sc_mbuf != NULL)
94702742ec6SJoerg Sonnenberger pfsync_sendout(sc);
948c3c8c553SJan Lentfer crit_exit();
94902742ec6SJoerg Sonnenberger break;
95002742ec6SJoerg Sonnenberger case PFSYNC_ACT_BUS:
95102742ec6SJoerg Sonnenberger /* If we're not waiting for a bulk update, who cares. */
95202742ec6SJoerg Sonnenberger if (sc->sc_ureq_sent == 0)
95302742ec6SJoerg Sonnenberger break;
95402742ec6SJoerg Sonnenberger
95502742ec6SJoerg Sonnenberger if ((mp = m_pulldown(m, iplen + sizeof(*ph),
95602742ec6SJoerg Sonnenberger sizeof(*bus), &offp)) == NULL) {
95702742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_badlen++;
95802742ec6SJoerg Sonnenberger return;
95902742ec6SJoerg Sonnenberger }
96002742ec6SJoerg Sonnenberger bus = (struct pfsync_state_bus *)(mp->m_data + offp);
96102742ec6SJoerg Sonnenberger switch (bus->status) {
96202742ec6SJoerg Sonnenberger case PFSYNC_BUS_START:
9632a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
964c3c8c553SJan Lentfer callout_reset(&sc->sc_bulkfail_tmo,
96502742ec6SJoerg Sonnenberger pf_pool_limits[PF_LIMIT_STATES].limit /
966c3c8c553SJan Lentfer (PFSYNC_BULKPACKETS * sc->sc_maxcount),
967c3c8c553SJan Lentfer pfsync_bulkfail, LIST_FIRST(&pfsync_list));
9682a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
96902742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
970c3c8c553SJan Lentfer kprintf("pfsync: received bulk "
97102742ec6SJoerg Sonnenberger "update start\n");
97202742ec6SJoerg Sonnenberger break;
97302742ec6SJoerg Sonnenberger case PFSYNC_BUS_END:
974c3c8c553SJan Lentfer if (mycpu->gd_time_seconds - ntohl(bus->endtime) >=
97502742ec6SJoerg Sonnenberger sc->sc_ureq_sent) {
97602742ec6SJoerg Sonnenberger /* that's it, we're happy */
97702742ec6SJoerg Sonnenberger sc->sc_ureq_sent = 0;
97802742ec6SJoerg Sonnenberger sc->sc_bulk_tries = 0;
9792a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
980c3c8c553SJan Lentfer callout_stop(&sc->sc_bulkfail_tmo);
9812a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
9822b00f643SSascha Wildner #ifdef CARP
9832a7a2b1cSJan Lentfer if (!pfsync_sync_ok) {
9842a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
98570224baaSJan Lentfer carp_group_demote_adj(&sc->sc_if, -1);
9862a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
9872a7a2b1cSJan Lentfer }
98870224baaSJan Lentfer #endif
98902742ec6SJoerg Sonnenberger pfsync_sync_ok = 1;
99002742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
991c3c8c553SJan Lentfer kprintf("pfsync: received valid "
99202742ec6SJoerg Sonnenberger "bulk update end\n");
99302742ec6SJoerg Sonnenberger } else {
99402742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
995c3c8c553SJan Lentfer kprintf("pfsync: received invalid "
99602742ec6SJoerg Sonnenberger "bulk update end: bad timestamp\n");
99702742ec6SJoerg Sonnenberger }
99802742ec6SJoerg Sonnenberger break;
99902742ec6SJoerg Sonnenberger }
100002742ec6SJoerg Sonnenberger break;
100102742ec6SJoerg Sonnenberger }
100202742ec6SJoerg Sonnenberger
100302742ec6SJoerg Sonnenberger done:
100402742ec6SJoerg Sonnenberger if (m)
100502742ec6SJoerg Sonnenberger m_freem(m);
100602742ec6SJoerg Sonnenberger }
100702742ec6SJoerg Sonnenberger
100802742ec6SJoerg Sonnenberger int
pfsyncoutput(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)100902742ec6SJoerg Sonnenberger pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
101002742ec6SJoerg Sonnenberger struct rtentry *rt)
101102742ec6SJoerg Sonnenberger {
101202742ec6SJoerg Sonnenberger m_freem(m);
101302742ec6SJoerg Sonnenberger return (0);
101402742ec6SJoerg Sonnenberger }
101502742ec6SJoerg Sonnenberger
101602742ec6SJoerg Sonnenberger /* ARGSUSED */
101702742ec6SJoerg Sonnenberger int
pfsyncioctl(struct ifnet * ifp,u_long cmd,caddr_t data,struct ucred * cr)1018c3c8c553SJan Lentfer pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
101902742ec6SJoerg Sonnenberger {
102002742ec6SJoerg Sonnenberger struct pfsync_softc *sc = ifp->if_softc;
102102742ec6SJoerg Sonnenberger struct ifreq *ifr = (struct ifreq *)data;
102202742ec6SJoerg Sonnenberger struct ip_moptions *imo = &sc->sc_imo;
102302742ec6SJoerg Sonnenberger struct pfsyncreq pfsyncr;
102402742ec6SJoerg Sonnenberger struct ifnet *sifp;
1025c3c8c553SJan Lentfer int error;
102602742ec6SJoerg Sonnenberger
10272a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
10282a7a2b1cSJan Lentfer
102902742ec6SJoerg Sonnenberger switch (cmd) {
103002742ec6SJoerg Sonnenberger case SIOCSIFADDR:
103102742ec6SJoerg Sonnenberger case SIOCAIFADDR:
103202742ec6SJoerg Sonnenberger case SIOCSIFDSTADDR:
103302742ec6SJoerg Sonnenberger case SIOCSIFFLAGS:
103402742ec6SJoerg Sonnenberger if (ifp->if_flags & IFF_UP)
103502742ec6SJoerg Sonnenberger ifp->if_flags |= IFF_RUNNING;
103602742ec6SJoerg Sonnenberger else
103702742ec6SJoerg Sonnenberger ifp->if_flags &= ~IFF_RUNNING;
103802742ec6SJoerg Sonnenberger break;
103902742ec6SJoerg Sonnenberger case SIOCSIFMTU:
10402a7a2b1cSJan Lentfer if (ifr->ifr_mtu < PFSYNC_MINMTU) {
10412a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
104202742ec6SJoerg Sonnenberger return (EINVAL);
10432a7a2b1cSJan Lentfer }
104402742ec6SJoerg Sonnenberger if (ifr->ifr_mtu > MCLBYTES)
104502742ec6SJoerg Sonnenberger ifr->ifr_mtu = MCLBYTES;
1046c3c8c553SJan Lentfer crit_enter();
104702742ec6SJoerg Sonnenberger if (ifr->ifr_mtu < ifp->if_mtu)
104802742ec6SJoerg Sonnenberger pfsync_sendout(sc);
104902742ec6SJoerg Sonnenberger pfsync_setmtu(sc, ifr->ifr_mtu);
1050c3c8c553SJan Lentfer crit_exit();
105102742ec6SJoerg Sonnenberger break;
105202742ec6SJoerg Sonnenberger case SIOCGETPFSYNC:
105302742ec6SJoerg Sonnenberger bzero(&pfsyncr, sizeof(pfsyncr));
105402742ec6SJoerg Sonnenberger if (sc->sc_sync_ifp)
105570224baaSJan Lentfer strlcpy(pfsyncr.pfsyncr_syncdev,
105602742ec6SJoerg Sonnenberger sc->sc_sync_ifp->if_xname, IFNAMSIZ);
105770224baaSJan Lentfer pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
105802742ec6SJoerg Sonnenberger pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
10592a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
106002742ec6SJoerg Sonnenberger if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
106102742ec6SJoerg Sonnenberger return (error);
10622a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
106302742ec6SJoerg Sonnenberger break;
106402742ec6SJoerg Sonnenberger case SIOCSETPFSYNC:
1065*2b3f93eaSMatthew Dillon error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
1066*2b3f93eaSMatthew Dillon __SYSCAP_NULLCRED);
1067*2b3f93eaSMatthew Dillon if (error) {
10682a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
106902742ec6SJoerg Sonnenberger return (error);
10702a7a2b1cSJan Lentfer }
10712a7a2b1cSJan Lentfer if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) {
10722a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
107302742ec6SJoerg Sonnenberger return (error);
10742a7a2b1cSJan Lentfer }
107502742ec6SJoerg Sonnenberger
107670224baaSJan Lentfer if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
107770224baaSJan Lentfer sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
107870224baaSJan Lentfer else
107970224baaSJan Lentfer sc->sc_sync_peer.s_addr =
108070224baaSJan Lentfer pfsyncr.pfsyncr_syncpeer.s_addr;
108170224baaSJan Lentfer
10822a7a2b1cSJan Lentfer if (pfsyncr.pfsyncr_maxupdates > 255) {
10832a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
108402742ec6SJoerg Sonnenberger return (EINVAL);
10852a7a2b1cSJan Lentfer }
108602742ec6SJoerg Sonnenberger sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
108702742ec6SJoerg Sonnenberger
108870224baaSJan Lentfer if (pfsyncr.pfsyncr_syncdev[0] == 0) {
108902742ec6SJoerg Sonnenberger sc->sc_sync_ifp = NULL;
109002742ec6SJoerg Sonnenberger if (sc->sc_mbuf_net != NULL) {
109102742ec6SJoerg Sonnenberger /* Don't keep stale pfsync packets around. */
1092c3c8c553SJan Lentfer crit_enter();
109302742ec6SJoerg Sonnenberger m_freem(sc->sc_mbuf_net);
109402742ec6SJoerg Sonnenberger sc->sc_mbuf_net = NULL;
109502742ec6SJoerg Sonnenberger sc->sc_statep_net.s = NULL;
1096c3c8c553SJan Lentfer crit_exit();
109770224baaSJan Lentfer }
109870224baaSJan Lentfer if (imo->imo_num_memberships > 0) {
1099ef15d469SSepherosa Ziehau pfsync_in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
110070224baaSJan Lentfer imo->imo_multicast_ifp = NULL;
110102742ec6SJoerg Sonnenberger }
110202742ec6SJoerg Sonnenberger break;
110302742ec6SJoerg Sonnenberger }
110402742ec6SJoerg Sonnenberger
1105b4051e25SSepherosa Ziehau /*
1106b4051e25SSepherosa Ziehau * XXX not that MPSAFE; pfsync needs serious rework
1107b4051e25SSepherosa Ziehau */
1108b4051e25SSepherosa Ziehau ifnet_deserialize_all(ifp);
1109b4051e25SSepherosa Ziehau ifnet_lock();
1110b4051e25SSepherosa Ziehau sifp = ifunit(pfsyncr.pfsyncr_syncdev);
1111b4051e25SSepherosa Ziehau ifnet_unlock();
1112b4051e25SSepherosa Ziehau ifnet_serialize_all(ifp);
1113b4051e25SSepherosa Ziehau
1114b4051e25SSepherosa Ziehau if (sifp == NULL) {
11152a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
111670224baaSJan Lentfer return (EINVAL);
11172a7a2b1cSJan Lentfer }
111870224baaSJan Lentfer
1119c3c8c553SJan Lentfer crit_enter();
112002742ec6SJoerg Sonnenberger if (sifp->if_mtu < sc->sc_if.if_mtu ||
112102742ec6SJoerg Sonnenberger (sc->sc_sync_ifp != NULL &&
112202742ec6SJoerg Sonnenberger sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
112302742ec6SJoerg Sonnenberger sifp->if_mtu < MCLBYTES - sizeof(struct ip))
112402742ec6SJoerg Sonnenberger pfsync_sendout(sc);
112502742ec6SJoerg Sonnenberger sc->sc_sync_ifp = sifp;
112602742ec6SJoerg Sonnenberger
112702742ec6SJoerg Sonnenberger pfsync_setmtu(sc, sc->sc_if.if_mtu);
112802742ec6SJoerg Sonnenberger
112902742ec6SJoerg Sonnenberger if (imo->imo_num_memberships > 0) {
1130ef15d469SSepherosa Ziehau pfsync_in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
113102742ec6SJoerg Sonnenberger imo->imo_multicast_ifp = NULL;
113202742ec6SJoerg Sonnenberger }
113302742ec6SJoerg Sonnenberger
113470224baaSJan Lentfer if (sc->sc_sync_ifp &&
113570224baaSJan Lentfer sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
113670224baaSJan Lentfer if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
113770224baaSJan Lentfer sc->sc_sync_ifp = NULL;
11382a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1139c3c8c553SJan Lentfer crit_exit();
114070224baaSJan Lentfer return (EADDRNOTAVAIL);
114170224baaSJan Lentfer }
114270224baaSJan Lentfer
114302742ec6SJoerg Sonnenberger if ((imo->imo_membership[0] =
1144ef15d469SSepherosa Ziehau pfsync_in_addmulti(sc->sc_sync_ifp)) == NULL) {
114570224baaSJan Lentfer sc->sc_sync_ifp = NULL;
11462a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1147c3c8c553SJan Lentfer crit_exit();
114802742ec6SJoerg Sonnenberger return (ENOBUFS);
114902742ec6SJoerg Sonnenberger }
115002742ec6SJoerg Sonnenberger imo->imo_num_memberships++;
115102742ec6SJoerg Sonnenberger imo->imo_multicast_ifp = sc->sc_sync_ifp;
115202742ec6SJoerg Sonnenberger imo->imo_multicast_ttl = PFSYNC_DFLTTL;
115302742ec6SJoerg Sonnenberger imo->imo_multicast_loop = 0;
115470224baaSJan Lentfer }
115502742ec6SJoerg Sonnenberger
115670224baaSJan Lentfer if (sc->sc_sync_ifp ||
115770224baaSJan Lentfer sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
115802742ec6SJoerg Sonnenberger /* Request a full state table update. */
1159c3c8c553SJan Lentfer sc->sc_ureq_sent = mycpu->gd_time_seconds;
11602b00f643SSascha Wildner #ifdef CARP
116170224baaSJan Lentfer if (pfsync_sync_ok)
116270224baaSJan Lentfer carp_group_demote_adj(&sc->sc_if, 1);
116370224baaSJan Lentfer #endif
116402742ec6SJoerg Sonnenberger pfsync_sync_ok = 0;
116502742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
1166c3c8c553SJan Lentfer kprintf("pfsync: requesting bulk update\n");
11672a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1168c3c8c553SJan Lentfer callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1169c3c8c553SJan Lentfer pfsync_bulkfail, LIST_FIRST(&pfsync_list));
11702a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
117170224baaSJan Lentfer error = pfsync_request_update(NULL, NULL);
117270224baaSJan Lentfer if (error == ENOMEM) {
11732a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1174c3c8c553SJan Lentfer crit_exit();
117570224baaSJan Lentfer return (ENOMEM);
117670224baaSJan Lentfer }
117702742ec6SJoerg Sonnenberger pfsync_sendout(sc);
117802742ec6SJoerg Sonnenberger }
1179c3c8c553SJan Lentfer crit_exit();
118002742ec6SJoerg Sonnenberger
118102742ec6SJoerg Sonnenberger break;
118202742ec6SJoerg Sonnenberger
118302742ec6SJoerg Sonnenberger default:
11842a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
118502742ec6SJoerg Sonnenberger return (ENOTTY);
118602742ec6SJoerg Sonnenberger }
118702742ec6SJoerg Sonnenberger
11882a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
118902742ec6SJoerg Sonnenberger return (0);
119002742ec6SJoerg Sonnenberger }
119102742ec6SJoerg Sonnenberger
119202742ec6SJoerg Sonnenberger void
pfsync_setmtu(struct pfsync_softc * sc,int mtu_req)119302742ec6SJoerg Sonnenberger pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
119402742ec6SJoerg Sonnenberger {
119502742ec6SJoerg Sonnenberger int mtu;
119602742ec6SJoerg Sonnenberger
119702742ec6SJoerg Sonnenberger if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
119802742ec6SJoerg Sonnenberger mtu = sc->sc_sync_ifp->if_mtu;
119902742ec6SJoerg Sonnenberger else
120002742ec6SJoerg Sonnenberger mtu = mtu_req;
120102742ec6SJoerg Sonnenberger
120202742ec6SJoerg Sonnenberger sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
120302742ec6SJoerg Sonnenberger sizeof(struct pfsync_state);
120402742ec6SJoerg Sonnenberger if (sc->sc_maxcount > 254)
120502742ec6SJoerg Sonnenberger sc->sc_maxcount = 254;
120602742ec6SJoerg Sonnenberger sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
120702742ec6SJoerg Sonnenberger sc->sc_maxcount * sizeof(struct pfsync_state);
120802742ec6SJoerg Sonnenberger }
120902742ec6SJoerg Sonnenberger
121002742ec6SJoerg Sonnenberger struct mbuf *
pfsync_get_mbuf(struct pfsync_softc * sc,u_int8_t action,void ** sp)121102742ec6SJoerg Sonnenberger pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
121202742ec6SJoerg Sonnenberger {
121302742ec6SJoerg Sonnenberger struct pfsync_header *h;
121402742ec6SJoerg Sonnenberger struct mbuf *m;
121502742ec6SJoerg Sonnenberger int len;
121602742ec6SJoerg Sonnenberger
12172a7a2b1cSJan Lentfer ASSERT_LWKT_TOKEN_HELD(&pf_token);
12182a7a2b1cSJan Lentfer
1219c3c8c553SJan Lentfer MGETHDR(m, M_WAITOK, MT_DATA);
122002742ec6SJoerg Sonnenberger
122102742ec6SJoerg Sonnenberger switch (action) {
122202742ec6SJoerg Sonnenberger case PFSYNC_ACT_CLR:
122302742ec6SJoerg Sonnenberger len = sizeof(struct pfsync_header) +
122402742ec6SJoerg Sonnenberger sizeof(struct pfsync_state_clr);
122502742ec6SJoerg Sonnenberger break;
122602742ec6SJoerg Sonnenberger case PFSYNC_ACT_UPD_C:
122702742ec6SJoerg Sonnenberger len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
122802742ec6SJoerg Sonnenberger sizeof(struct pfsync_header);
122902742ec6SJoerg Sonnenberger break;
123002742ec6SJoerg Sonnenberger case PFSYNC_ACT_DEL_C:
123102742ec6SJoerg Sonnenberger len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
123202742ec6SJoerg Sonnenberger sizeof(struct pfsync_header);
123302742ec6SJoerg Sonnenberger break;
123402742ec6SJoerg Sonnenberger case PFSYNC_ACT_UREQ:
123502742ec6SJoerg Sonnenberger len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
123602742ec6SJoerg Sonnenberger sizeof(struct pfsync_header);
123702742ec6SJoerg Sonnenberger break;
123802742ec6SJoerg Sonnenberger case PFSYNC_ACT_BUS:
123902742ec6SJoerg Sonnenberger len = sizeof(struct pfsync_header) +
124002742ec6SJoerg Sonnenberger sizeof(struct pfsync_state_bus);
124102742ec6SJoerg Sonnenberger break;
1242315a7da3SJan Lentfer case PFSYNC_ACT_TDB_UPD:
1243315a7da3SJan Lentfer len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
1244315a7da3SJan Lentfer sizeof(struct pfsync_header);
1245315a7da3SJan Lentfer break;
124602742ec6SJoerg Sonnenberger default:
124702742ec6SJoerg Sonnenberger len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
124802742ec6SJoerg Sonnenberger sizeof(struct pfsync_header);
124902742ec6SJoerg Sonnenberger break;
125002742ec6SJoerg Sonnenberger }
125102742ec6SJoerg Sonnenberger
125202742ec6SJoerg Sonnenberger if (len > MHLEN) {
1253c3c8c553SJan Lentfer MCLGET(m, M_WAITOK);
12543f7b7260SSascha Wildner m->m_data += rounddown2(MCLBYTES - len, sizeof(long));
125502742ec6SJoerg Sonnenberger } else
125602742ec6SJoerg Sonnenberger MH_ALIGN(m, len);
125702742ec6SJoerg Sonnenberger
125802742ec6SJoerg Sonnenberger m->m_pkthdr.rcvif = NULL;
125902742ec6SJoerg Sonnenberger m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
126002742ec6SJoerg Sonnenberger h = mtod(m, struct pfsync_header *);
126102742ec6SJoerg Sonnenberger h->version = PFSYNC_VERSION;
126202742ec6SJoerg Sonnenberger h->af = 0;
126302742ec6SJoerg Sonnenberger h->count = 0;
126402742ec6SJoerg Sonnenberger h->action = action;
126502742ec6SJoerg Sonnenberger
126602742ec6SJoerg Sonnenberger *sp = (void *)((char *)h + PFSYNC_HDRLEN);
12672a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1268c3c8c553SJan Lentfer callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1269c3c8c553SJan Lentfer LIST_FIRST(&pfsync_list));
12702a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
127102742ec6SJoerg Sonnenberger return (m);
127202742ec6SJoerg Sonnenberger }
127302742ec6SJoerg Sonnenberger
127402742ec6SJoerg Sonnenberger int
pfsync_pack_state(u_int8_t action,struct pf_state * st,int flags)127570224baaSJan Lentfer pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
127602742ec6SJoerg Sonnenberger {
127770224baaSJan Lentfer struct ifnet *ifp = NULL;
127870224baaSJan Lentfer struct pfsync_softc *sc = pfsyncif;
127902742ec6SJoerg Sonnenberger struct pfsync_header *h, *h_net;
128002742ec6SJoerg Sonnenberger struct pfsync_state *sp = NULL;
128102742ec6SJoerg Sonnenberger struct pfsync_state_upd *up = NULL;
128202742ec6SJoerg Sonnenberger struct pfsync_state_del *dp = NULL;
1283c3c8c553SJan Lentfer int ret = 0;
128402742ec6SJoerg Sonnenberger u_int8_t i = 255, newaction = 0;
128502742ec6SJoerg Sonnenberger
128670224baaSJan Lentfer if (sc == NULL)
128770224baaSJan Lentfer return (0);
128870224baaSJan Lentfer ifp = &sc->sc_if;
128970224baaSJan Lentfer
129002742ec6SJoerg Sonnenberger /*
129102742ec6SJoerg Sonnenberger * If a packet falls in the forest and there's nobody around to
129202742ec6SJoerg Sonnenberger * hear, does it make a sound?
129302742ec6SJoerg Sonnenberger */
129470224baaSJan Lentfer if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
129570224baaSJan Lentfer sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
129602742ec6SJoerg Sonnenberger /* Don't leave any stale pfsync packets hanging around. */
129702742ec6SJoerg Sonnenberger if (sc->sc_mbuf != NULL) {
129802742ec6SJoerg Sonnenberger m_freem(sc->sc_mbuf);
129902742ec6SJoerg Sonnenberger sc->sc_mbuf = NULL;
130002742ec6SJoerg Sonnenberger sc->sc_statep.s = NULL;
130102742ec6SJoerg Sonnenberger }
130202742ec6SJoerg Sonnenberger return (0);
130302742ec6SJoerg Sonnenberger }
130402742ec6SJoerg Sonnenberger
130502742ec6SJoerg Sonnenberger if (action >= PFSYNC_ACT_MAX)
130602742ec6SJoerg Sonnenberger return (EINVAL);
130702742ec6SJoerg Sonnenberger
1308c3c8c553SJan Lentfer crit_enter();
130902742ec6SJoerg Sonnenberger if (sc->sc_mbuf == NULL) {
131002742ec6SJoerg Sonnenberger if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
131102742ec6SJoerg Sonnenberger (void *)&sc->sc_statep.s)) == NULL) {
1312c3c8c553SJan Lentfer crit_exit();
131302742ec6SJoerg Sonnenberger return (ENOMEM);
131402742ec6SJoerg Sonnenberger }
131502742ec6SJoerg Sonnenberger h = mtod(sc->sc_mbuf, struct pfsync_header *);
131602742ec6SJoerg Sonnenberger } else {
131702742ec6SJoerg Sonnenberger h = mtod(sc->sc_mbuf, struct pfsync_header *);
131802742ec6SJoerg Sonnenberger if (h->action != action) {
131902742ec6SJoerg Sonnenberger pfsync_sendout(sc);
132002742ec6SJoerg Sonnenberger if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
132102742ec6SJoerg Sonnenberger (void *)&sc->sc_statep.s)) == NULL) {
1322c3c8c553SJan Lentfer crit_exit();
132302742ec6SJoerg Sonnenberger return (ENOMEM);
132402742ec6SJoerg Sonnenberger }
132502742ec6SJoerg Sonnenberger h = mtod(sc->sc_mbuf, struct pfsync_header *);
132602742ec6SJoerg Sonnenberger } else {
132702742ec6SJoerg Sonnenberger /*
132802742ec6SJoerg Sonnenberger * If it's an update, look in the packet to see if
132902742ec6SJoerg Sonnenberger * we already have an update for the state.
133002742ec6SJoerg Sonnenberger */
133102742ec6SJoerg Sonnenberger if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
133202742ec6SJoerg Sonnenberger struct pfsync_state *usp =
133302742ec6SJoerg Sonnenberger (void *)((char *)h + PFSYNC_HDRLEN);
133402742ec6SJoerg Sonnenberger
133502742ec6SJoerg Sonnenberger for (i = 0; i < h->count; i++) {
133602742ec6SJoerg Sonnenberger if (!memcmp(usp->id, &st->id,
133702742ec6SJoerg Sonnenberger PFSYNC_ID_LEN) &&
133802742ec6SJoerg Sonnenberger usp->creatorid == st->creatorid) {
133902742ec6SJoerg Sonnenberger sp = usp;
134002742ec6SJoerg Sonnenberger sp->updates++;
134102742ec6SJoerg Sonnenberger break;
134202742ec6SJoerg Sonnenberger }
134302742ec6SJoerg Sonnenberger usp++;
134402742ec6SJoerg Sonnenberger }
134502742ec6SJoerg Sonnenberger }
134602742ec6SJoerg Sonnenberger }
134702742ec6SJoerg Sonnenberger }
134802742ec6SJoerg Sonnenberger
13493598cc14SSascha Wildner st->pfsync_time = mycpu->gd_time_seconds;
135002742ec6SJoerg Sonnenberger
135102742ec6SJoerg Sonnenberger if (sp == NULL) {
135202742ec6SJoerg Sonnenberger /* not a "duplicate" update */
135302742ec6SJoerg Sonnenberger i = 255;
135402742ec6SJoerg Sonnenberger sp = sc->sc_statep.s++;
135502742ec6SJoerg Sonnenberger sc->sc_mbuf->m_pkthdr.len =
135602742ec6SJoerg Sonnenberger sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
135702742ec6SJoerg Sonnenberger h->count++;
135802742ec6SJoerg Sonnenberger bzero(sp, sizeof(*sp));
135902742ec6SJoerg Sonnenberger
1360ed1f0be2SJan Lentfer pfsync_state_export(sp, st);
136102742ec6SJoerg Sonnenberger
136270224baaSJan Lentfer if (flags & PFSYNC_FLAG_STALE)
136370224baaSJan Lentfer sp->sync_flags |= PFSTATE_STALE;
1364ed1f0be2SJan Lentfer } else {
136502742ec6SJoerg Sonnenberger pf_state_peer_hton(&st->src, &sp->src);
136602742ec6SJoerg Sonnenberger pf_state_peer_hton(&st->dst, &sp->dst);
136702742ec6SJoerg Sonnenberger
1368ed1f0be2SJan Lentfer if (st->expire <= time_second)
136902742ec6SJoerg Sonnenberger sp->expire = htonl(0);
137002742ec6SJoerg Sonnenberger else
1371ed1f0be2SJan Lentfer sp->expire = htonl(st->expire - time_second);
1372ed1f0be2SJan Lentfer }
137302742ec6SJoerg Sonnenberger
137402742ec6SJoerg Sonnenberger /* do we need to build "compressed" actions for network transfer? */
137570224baaSJan Lentfer if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
137602742ec6SJoerg Sonnenberger switch (action) {
137702742ec6SJoerg Sonnenberger case PFSYNC_ACT_UPD:
137802742ec6SJoerg Sonnenberger newaction = PFSYNC_ACT_UPD_C;
137902742ec6SJoerg Sonnenberger break;
138002742ec6SJoerg Sonnenberger case PFSYNC_ACT_DEL:
138102742ec6SJoerg Sonnenberger newaction = PFSYNC_ACT_DEL_C;
138202742ec6SJoerg Sonnenberger break;
138302742ec6SJoerg Sonnenberger default:
138402742ec6SJoerg Sonnenberger /* by default we just send the uncompressed states */
138502742ec6SJoerg Sonnenberger break;
138602742ec6SJoerg Sonnenberger }
138702742ec6SJoerg Sonnenberger }
138802742ec6SJoerg Sonnenberger
138902742ec6SJoerg Sonnenberger if (newaction) {
139002742ec6SJoerg Sonnenberger if (sc->sc_mbuf_net == NULL) {
139102742ec6SJoerg Sonnenberger if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
139202742ec6SJoerg Sonnenberger (void *)&sc->sc_statep_net.s)) == NULL) {
1393c3c8c553SJan Lentfer crit_exit();
139402742ec6SJoerg Sonnenberger return (ENOMEM);
139502742ec6SJoerg Sonnenberger }
139602742ec6SJoerg Sonnenberger }
139702742ec6SJoerg Sonnenberger h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
139802742ec6SJoerg Sonnenberger
139902742ec6SJoerg Sonnenberger switch (newaction) {
140002742ec6SJoerg Sonnenberger case PFSYNC_ACT_UPD_C:
140102742ec6SJoerg Sonnenberger if (i != 255) {
140202742ec6SJoerg Sonnenberger up = (void *)((char *)h_net +
140302742ec6SJoerg Sonnenberger PFSYNC_HDRLEN + (i * sizeof(*up)));
140402742ec6SJoerg Sonnenberger up->updates++;
140502742ec6SJoerg Sonnenberger } else {
140602742ec6SJoerg Sonnenberger h_net->count++;
140702742ec6SJoerg Sonnenberger sc->sc_mbuf_net->m_pkthdr.len =
140802742ec6SJoerg Sonnenberger sc->sc_mbuf_net->m_len += sizeof(*up);
140902742ec6SJoerg Sonnenberger up = sc->sc_statep_net.u++;
141002742ec6SJoerg Sonnenberger
141102742ec6SJoerg Sonnenberger bzero(up, sizeof(*up));
141202742ec6SJoerg Sonnenberger bcopy(&st->id, up->id, sizeof(up->id));
141302742ec6SJoerg Sonnenberger up->creatorid = st->creatorid;
141402742ec6SJoerg Sonnenberger }
141502742ec6SJoerg Sonnenberger up->timeout = st->timeout;
141602742ec6SJoerg Sonnenberger up->expire = sp->expire;
141702742ec6SJoerg Sonnenberger up->src = sp->src;
141802742ec6SJoerg Sonnenberger up->dst = sp->dst;
141902742ec6SJoerg Sonnenberger break;
142002742ec6SJoerg Sonnenberger case PFSYNC_ACT_DEL_C:
142102742ec6SJoerg Sonnenberger sc->sc_mbuf_net->m_pkthdr.len =
142202742ec6SJoerg Sonnenberger sc->sc_mbuf_net->m_len += sizeof(*dp);
142302742ec6SJoerg Sonnenberger dp = sc->sc_statep_net.d++;
142402742ec6SJoerg Sonnenberger h_net->count++;
142502742ec6SJoerg Sonnenberger
142602742ec6SJoerg Sonnenberger bzero(dp, sizeof(*dp));
142702742ec6SJoerg Sonnenberger bcopy(&st->id, dp->id, sizeof(dp->id));
142802742ec6SJoerg Sonnenberger dp->creatorid = st->creatorid;
142902742ec6SJoerg Sonnenberger break;
143002742ec6SJoerg Sonnenberger }
143102742ec6SJoerg Sonnenberger }
143202742ec6SJoerg Sonnenberger
143302742ec6SJoerg Sonnenberger if (h->count == sc->sc_maxcount ||
143402742ec6SJoerg Sonnenberger (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
143502742ec6SJoerg Sonnenberger ret = pfsync_sendout(sc);
143602742ec6SJoerg Sonnenberger
1437c3c8c553SJan Lentfer crit_exit();
143802742ec6SJoerg Sonnenberger return (ret);
143902742ec6SJoerg Sonnenberger }
144002742ec6SJoerg Sonnenberger
144102742ec6SJoerg Sonnenberger int
pfsync_request_update(struct pfsync_state_upd * up,struct in_addr * src)144202742ec6SJoerg Sonnenberger pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
144302742ec6SJoerg Sonnenberger {
144402742ec6SJoerg Sonnenberger struct pfsync_header *h;
144570224baaSJan Lentfer struct pfsync_softc *sc = pfsyncif;
144602742ec6SJoerg Sonnenberger struct pfsync_state_upd_req *rup;
1447cc6e5672SJoerg Sonnenberger int ret = 0;
144802742ec6SJoerg Sonnenberger
144970224baaSJan Lentfer if (sc == NULL)
145070224baaSJan Lentfer return (0);
145170224baaSJan Lentfer
145202742ec6SJoerg Sonnenberger if (sc->sc_mbuf == NULL) {
145302742ec6SJoerg Sonnenberger if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
145470224baaSJan Lentfer (void *)&sc->sc_statep.s)) == NULL)
145502742ec6SJoerg Sonnenberger return (ENOMEM);
145602742ec6SJoerg Sonnenberger h = mtod(sc->sc_mbuf, struct pfsync_header *);
145702742ec6SJoerg Sonnenberger } else {
145802742ec6SJoerg Sonnenberger h = mtod(sc->sc_mbuf, struct pfsync_header *);
145902742ec6SJoerg Sonnenberger if (h->action != PFSYNC_ACT_UREQ) {
146002742ec6SJoerg Sonnenberger pfsync_sendout(sc);
146102742ec6SJoerg Sonnenberger if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
146270224baaSJan Lentfer (void *)&sc->sc_statep.s)) == NULL)
146302742ec6SJoerg Sonnenberger return (ENOMEM);
146402742ec6SJoerg Sonnenberger h = mtod(sc->sc_mbuf, struct pfsync_header *);
146502742ec6SJoerg Sonnenberger }
146602742ec6SJoerg Sonnenberger }
146702742ec6SJoerg Sonnenberger
146802742ec6SJoerg Sonnenberger if (src != NULL)
146902742ec6SJoerg Sonnenberger sc->sc_sendaddr = *src;
147002742ec6SJoerg Sonnenberger sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
147102742ec6SJoerg Sonnenberger h->count++;
147202742ec6SJoerg Sonnenberger rup = sc->sc_statep.r++;
147302742ec6SJoerg Sonnenberger bzero(rup, sizeof(*rup));
147402742ec6SJoerg Sonnenberger if (up != NULL) {
147502742ec6SJoerg Sonnenberger bcopy(up->id, rup->id, sizeof(rup->id));
147602742ec6SJoerg Sonnenberger rup->creatorid = up->creatorid;
147702742ec6SJoerg Sonnenberger }
147802742ec6SJoerg Sonnenberger
147902742ec6SJoerg Sonnenberger if (h->count == sc->sc_maxcount)
148002742ec6SJoerg Sonnenberger ret = pfsync_sendout(sc);
148102742ec6SJoerg Sonnenberger
148202742ec6SJoerg Sonnenberger return (ret);
148302742ec6SJoerg Sonnenberger }
148402742ec6SJoerg Sonnenberger
148502742ec6SJoerg Sonnenberger int
pfsync_clear_states(u_int32_t creatorid,char * ifname)148602742ec6SJoerg Sonnenberger pfsync_clear_states(u_int32_t creatorid, char *ifname)
148702742ec6SJoerg Sonnenberger {
148870224baaSJan Lentfer struct pfsync_softc *sc = pfsyncif;
148902742ec6SJoerg Sonnenberger struct pfsync_state_clr *cp;
1490c3c8c553SJan Lentfer int ret;
149102742ec6SJoerg Sonnenberger
149270224baaSJan Lentfer if (sc == NULL)
149370224baaSJan Lentfer return (0);
149470224baaSJan Lentfer
1495c3c8c553SJan Lentfer crit_enter();
149602742ec6SJoerg Sonnenberger if (sc->sc_mbuf != NULL)
149702742ec6SJoerg Sonnenberger pfsync_sendout(sc);
149802742ec6SJoerg Sonnenberger if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
149902742ec6SJoerg Sonnenberger (void *)&sc->sc_statep.c)) == NULL) {
1500c3c8c553SJan Lentfer crit_exit();
150102742ec6SJoerg Sonnenberger return (ENOMEM);
150202742ec6SJoerg Sonnenberger }
150302742ec6SJoerg Sonnenberger sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
150402742ec6SJoerg Sonnenberger cp = sc->sc_statep.c;
150502742ec6SJoerg Sonnenberger cp->creatorid = creatorid;
150602742ec6SJoerg Sonnenberger if (ifname != NULL)
150702742ec6SJoerg Sonnenberger strlcpy(cp->ifname, ifname, IFNAMSIZ);
150802742ec6SJoerg Sonnenberger
150902742ec6SJoerg Sonnenberger ret = (pfsync_sendout(sc));
1510c3c8c553SJan Lentfer crit_exit();
151102742ec6SJoerg Sonnenberger return (ret);
151202742ec6SJoerg Sonnenberger }
151302742ec6SJoerg Sonnenberger
151402742ec6SJoerg Sonnenberger void
pfsync_timeout(void * v)151502742ec6SJoerg Sonnenberger pfsync_timeout(void *v)
151602742ec6SJoerg Sonnenberger {
151702742ec6SJoerg Sonnenberger struct pfsync_softc *sc = v;
151802742ec6SJoerg Sonnenberger
1519c3c8c553SJan Lentfer crit_enter();
152002742ec6SJoerg Sonnenberger pfsync_sendout(sc);
1521c3c8c553SJan Lentfer crit_exit();
152202742ec6SJoerg Sonnenberger }
152302742ec6SJoerg Sonnenberger
152402742ec6SJoerg Sonnenberger void
pfsync_send_bus(struct pfsync_softc * sc,u_int8_t status)152502742ec6SJoerg Sonnenberger pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
152602742ec6SJoerg Sonnenberger {
152702742ec6SJoerg Sonnenberger struct pfsync_state_bus *bus;
152802742ec6SJoerg Sonnenberger
152902742ec6SJoerg Sonnenberger if (sc->sc_mbuf != NULL)
153002742ec6SJoerg Sonnenberger pfsync_sendout(sc);
153102742ec6SJoerg Sonnenberger
153202742ec6SJoerg Sonnenberger if (pfsync_sync_ok &&
153302742ec6SJoerg Sonnenberger (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
153402742ec6SJoerg Sonnenberger (void *)&sc->sc_statep.b)) != NULL) {
153502742ec6SJoerg Sonnenberger sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
153602742ec6SJoerg Sonnenberger bus = sc->sc_statep.b;
153702742ec6SJoerg Sonnenberger bus->creatorid = pf_status.hostid;
153802742ec6SJoerg Sonnenberger bus->status = status;
1539c3c8c553SJan Lentfer bus->endtime = htonl(mycpu->gd_time_seconds - sc->sc_ureq_received);
154002742ec6SJoerg Sonnenberger pfsync_sendout(sc);
154102742ec6SJoerg Sonnenberger }
154202742ec6SJoerg Sonnenberger }
154302742ec6SJoerg Sonnenberger
154402742ec6SJoerg Sonnenberger void
pfsync_bulk_update(void * v)154502742ec6SJoerg Sonnenberger pfsync_bulk_update(void *v)
154602742ec6SJoerg Sonnenberger {
154702742ec6SJoerg Sonnenberger struct pfsync_softc *sc = v;
1548c3c8c553SJan Lentfer int i = 0;
15493a0038bfSMatthew Dillon int cpu;
155002742ec6SJoerg Sonnenberger struct pf_state *state;
155102742ec6SJoerg Sonnenberger
15522a7a2b1cSJan Lentfer ASSERT_LWKT_TOKEN_HELD(&pf_token);
15532a7a2b1cSJan Lentfer
1554c3c8c553SJan Lentfer crit_enter();
155502742ec6SJoerg Sonnenberger if (sc->sc_mbuf != NULL)
155602742ec6SJoerg Sonnenberger pfsync_sendout(sc);
155702742ec6SJoerg Sonnenberger
155802742ec6SJoerg Sonnenberger /*
155902742ec6SJoerg Sonnenberger * Grab at most PFSYNC_BULKPACKETS worth of states which have not
156002742ec6SJoerg Sonnenberger * been sent since the latest request was made.
156102742ec6SJoerg Sonnenberger */
156270224baaSJan Lentfer state = sc->sc_bulk_send_next;
15633a0038bfSMatthew Dillon cpu = sc->sc_bulk_send_cpu;
156470224baaSJan Lentfer if (state)
156570224baaSJan Lentfer do {
156670224baaSJan Lentfer /* send state update if syncable and not already sent */
156770224baaSJan Lentfer if (!state->sync_flags
156870224baaSJan Lentfer && state->timeout < PFTM_MAX
156970224baaSJan Lentfer && state->pfsync_time <= sc->sc_ureq_received) {
157070224baaSJan Lentfer pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
157170224baaSJan Lentfer i++;
157270224baaSJan Lentfer }
157370224baaSJan Lentfer
157470224baaSJan Lentfer /* figure next state to send */
1575315a7da3SJan Lentfer state = TAILQ_NEXT(state, entry_list);
157670224baaSJan Lentfer
157770224baaSJan Lentfer /* wrap to start of list if we hit the end */
15783a0038bfSMatthew Dillon if (state == NULL) {
15793a0038bfSMatthew Dillon if (++cpu >= ncpus)
15803a0038bfSMatthew Dillon cpu = 0;
15813a0038bfSMatthew Dillon state = TAILQ_FIRST(&state_list[cpu]);
15823a0038bfSMatthew Dillon }
158370224baaSJan Lentfer } while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS &&
15843a0038bfSMatthew Dillon cpu != sc->sc_bulk_terminator_cpu &&
158570224baaSJan Lentfer state != sc->sc_bulk_terminator);
158670224baaSJan Lentfer
15873a0038bfSMatthew Dillon if (state == NULL || (cpu == sc->sc_bulk_terminator_cpu &&
15883a0038bfSMatthew Dillon state == sc->sc_bulk_terminator)) {
158902742ec6SJoerg Sonnenberger /* we're done */
159002742ec6SJoerg Sonnenberger pfsync_send_bus(sc, PFSYNC_BUS_END);
159102742ec6SJoerg Sonnenberger sc->sc_ureq_received = 0;
159270224baaSJan Lentfer sc->sc_bulk_send_next = NULL;
159370224baaSJan Lentfer sc->sc_bulk_terminator = NULL;
15943a0038bfSMatthew Dillon sc->sc_bulk_send_cpu = 0;
15953a0038bfSMatthew Dillon sc->sc_bulk_terminator_cpu = 0;
15962a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1597c3c8c553SJan Lentfer callout_stop(&sc->sc_bulk_tmo);
15982a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
159902742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
1600c3c8c553SJan Lentfer kprintf("pfsync: bulk update complete\n");
160102742ec6SJoerg Sonnenberger } else {
160202742ec6SJoerg Sonnenberger /* look again for more in a bit */
16032a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1604c3c8c553SJan Lentfer callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1605c3c8c553SJan Lentfer LIST_FIRST(&pfsync_list));
16062a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
160770224baaSJan Lentfer sc->sc_bulk_send_next = state;
16083a0038bfSMatthew Dillon sc->sc_bulk_send_cpu = cpu;
160902742ec6SJoerg Sonnenberger }
161002742ec6SJoerg Sonnenberger if (sc->sc_mbuf != NULL)
161102742ec6SJoerg Sonnenberger pfsync_sendout(sc);
1612c3c8c553SJan Lentfer crit_exit();
161302742ec6SJoerg Sonnenberger }
161402742ec6SJoerg Sonnenberger
161502742ec6SJoerg Sonnenberger void
pfsync_bulkfail(void * v)161602742ec6SJoerg Sonnenberger pfsync_bulkfail(void *v)
161702742ec6SJoerg Sonnenberger {
161802742ec6SJoerg Sonnenberger struct pfsync_softc *sc = v;
1619c3c8c553SJan Lentfer int error;
162002742ec6SJoerg Sonnenberger
16212a7a2b1cSJan Lentfer ASSERT_LWKT_TOKEN_HELD(&pf_token);
16222a7a2b1cSJan Lentfer
162302742ec6SJoerg Sonnenberger if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
162402742ec6SJoerg Sonnenberger /* Try again in a bit */
16252a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1626c3c8c553SJan Lentfer callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1627c3c8c553SJan Lentfer LIST_FIRST(&pfsync_list));
16282a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
1629c3c8c553SJan Lentfer crit_enter();
163070224baaSJan Lentfer error = pfsync_request_update(NULL, NULL);
163170224baaSJan Lentfer if (error == ENOMEM) {
163270224baaSJan Lentfer if (pf_status.debug >= PF_DEBUG_MISC)
1633c3c8c553SJan Lentfer kprintf("pfsync: cannot allocate mbufs for "
163470224baaSJan Lentfer "bulk update\n");
163570224baaSJan Lentfer } else
163602742ec6SJoerg Sonnenberger pfsync_sendout(sc);
1637c3c8c553SJan Lentfer crit_exit();
163802742ec6SJoerg Sonnenberger } else {
163902742ec6SJoerg Sonnenberger /* Pretend like the transfer was ok */
164002742ec6SJoerg Sonnenberger sc->sc_ureq_sent = 0;
164102742ec6SJoerg Sonnenberger sc->sc_bulk_tries = 0;
16422b00f643SSascha Wildner #ifdef CARP
164370224baaSJan Lentfer if (!pfsync_sync_ok)
164470224baaSJan Lentfer carp_group_demote_adj(&sc->sc_if, -1);
164570224baaSJan Lentfer #endif
164602742ec6SJoerg Sonnenberger pfsync_sync_ok = 1;
164702742ec6SJoerg Sonnenberger if (pf_status.debug >= PF_DEBUG_MISC)
1648c3c8c553SJan Lentfer kprintf("pfsync: failed to receive "
164902742ec6SJoerg Sonnenberger "bulk update status\n");
16502a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1651c3c8c553SJan Lentfer callout_stop(&sc->sc_bulkfail_tmo);
16522a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
165302742ec6SJoerg Sonnenberger }
165402742ec6SJoerg Sonnenberger }
165502742ec6SJoerg Sonnenberger
1656c4705c47SSepherosa Ziehau static void
pfsync_sendout_handler(netmsg_t nmsg)1657c4705c47SSepherosa Ziehau pfsync_sendout_handler(netmsg_t nmsg)
1658c4705c47SSepherosa Ziehau {
1659c4705c47SSepherosa Ziehau struct netmsg_genpkt *msg = (struct netmsg_genpkt *)nmsg;
1660c4705c47SSepherosa Ziehau
1661c4705c47SSepherosa Ziehau pfsync_sendout_mbuf(msg->arg1, msg->m);
1662c4705c47SSepherosa Ziehau }
1663c4705c47SSepherosa Ziehau
166402742ec6SJoerg Sonnenberger int
pfsync_sendout(struct pfsync_softc * sc)16653bf25ce1SSascha Wildner pfsync_sendout(struct pfsync_softc *sc)
166602742ec6SJoerg Sonnenberger {
16672b00f643SSascha Wildner #if NBPF > 0
166802742ec6SJoerg Sonnenberger struct ifnet *ifp = &sc->sc_if;
166970224baaSJan Lentfer #endif
167002742ec6SJoerg Sonnenberger struct mbuf *m;
1671c4705c47SSepherosa Ziehau struct netmsg_genpkt *msg;
167202742ec6SJoerg Sonnenberger
16732a7a2b1cSJan Lentfer ASSERT_LWKT_TOKEN_HELD(&pf_token);
16742a7a2b1cSJan Lentfer
16752a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
1676c3c8c553SJan Lentfer callout_stop(&sc->sc_tmo);
16772a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
167802742ec6SJoerg Sonnenberger
167902742ec6SJoerg Sonnenberger if (sc->sc_mbuf == NULL)
168002742ec6SJoerg Sonnenberger return (0);
168102742ec6SJoerg Sonnenberger m = sc->sc_mbuf;
168202742ec6SJoerg Sonnenberger sc->sc_mbuf = NULL;
168302742ec6SJoerg Sonnenberger sc->sc_statep.s = NULL;
168402742ec6SJoerg Sonnenberger
16852b00f643SSascha Wildner #if NBPF > 0
16862a7a2b1cSJan Lentfer if (ifp->if_bpf) {
1687fda7d388SSepherosa Ziehau bpf_gettoken();
1688fda7d388SSepherosa Ziehau if (ifp->if_bpf)
16892b00f643SSascha Wildner bpf_mtap(ifp->if_bpf, m);
1690fda7d388SSepherosa Ziehau bpf_reltoken();
16912a7a2b1cSJan Lentfer }
169270224baaSJan Lentfer #endif
169302742ec6SJoerg Sonnenberger
169402742ec6SJoerg Sonnenberger if (sc->sc_mbuf_net) {
169502742ec6SJoerg Sonnenberger m_freem(m);
169602742ec6SJoerg Sonnenberger m = sc->sc_mbuf_net;
169702742ec6SJoerg Sonnenberger sc->sc_mbuf_net = NULL;
169802742ec6SJoerg Sonnenberger sc->sc_statep_net.s = NULL;
169902742ec6SJoerg Sonnenberger }
170002742ec6SJoerg Sonnenberger
1701c4705c47SSepherosa Ziehau msg = &m->m_hdr.mh_genmsg;
1702c4705c47SSepherosa Ziehau netmsg_init(&msg->base, NULL, &netisr_apanic_rport, 0,
1703c4705c47SSepherosa Ziehau pfsync_sendout_handler);
1704c4705c47SSepherosa Ziehau msg->m = m;
1705c4705c47SSepherosa Ziehau msg->arg1 = sc;
1706c4705c47SSepherosa Ziehau netisr_sendmsg(&msg->base, 0);
1707c4705c47SSepherosa Ziehau
1708c4705c47SSepherosa Ziehau return (0);
170970224baaSJan Lentfer }
171002742ec6SJoerg Sonnenberger
171170224baaSJan Lentfer int
pfsync_sendout_mbuf(struct pfsync_softc * sc,struct mbuf * m)171270224baaSJan Lentfer pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
171370224baaSJan Lentfer {
171470224baaSJan Lentfer struct sockaddr sa;
171570224baaSJan Lentfer struct ip *ip;
171670224baaSJan Lentfer
171770224baaSJan Lentfer if (sc->sc_sync_ifp ||
171870224baaSJan Lentfer sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
1719c3c8c553SJan Lentfer M_PREPEND(m, sizeof(struct ip), M_WAITOK);
172002742ec6SJoerg Sonnenberger ip = mtod(m, struct ip *);
172102742ec6SJoerg Sonnenberger ip->ip_v = IPVERSION;
172202742ec6SJoerg Sonnenberger ip->ip_hl = sizeof(*ip) >> 2;
172302742ec6SJoerg Sonnenberger ip->ip_tos = IPTOS_LOWDELAY;
172470224baaSJan Lentfer ip->ip_len = htons(m->m_pkthdr.len);
172570224baaSJan Lentfer ip->ip_id = htons(ip_randomid());
172670224baaSJan Lentfer ip->ip_off = htons(IP_DF);
172702742ec6SJoerg Sonnenberger ip->ip_ttl = PFSYNC_DFLTTL;
172802742ec6SJoerg Sonnenberger ip->ip_p = IPPROTO_PFSYNC;
172902742ec6SJoerg Sonnenberger ip->ip_sum = 0;
173002742ec6SJoerg Sonnenberger
173102742ec6SJoerg Sonnenberger bzero(&sa, sizeof(sa));
173270224baaSJan Lentfer ip->ip_src.s_addr = INADDR_ANY;
173302742ec6SJoerg Sonnenberger
173470224baaSJan Lentfer if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
173502742ec6SJoerg Sonnenberger m->m_flags |= M_MCAST;
173602742ec6SJoerg Sonnenberger ip->ip_dst = sc->sc_sendaddr;
173770224baaSJan Lentfer sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
173802742ec6SJoerg Sonnenberger
173902742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_opackets++;
174002742ec6SJoerg Sonnenberger
174102742ec6SJoerg Sonnenberger if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
174202742ec6SJoerg Sonnenberger pfsyncstats.pfsyncs_oerrors++;
174302742ec6SJoerg Sonnenberger } else
174402742ec6SJoerg Sonnenberger m_freem(m);
174502742ec6SJoerg Sonnenberger
174602742ec6SJoerg Sonnenberger return (0);
174702742ec6SJoerg Sonnenberger }
174802742ec6SJoerg Sonnenberger
17492a7a2b1cSJan Lentfer static int
pfsync_modevent(module_t mod,int type,void * data)17502a7a2b1cSJan Lentfer pfsync_modevent(module_t mod, int type, void *data)
17512a7a2b1cSJan Lentfer {
17522a7a2b1cSJan Lentfer int error = 0;
17532a7a2b1cSJan Lentfer
1754ed1f0be2SJan Lentfer struct pfsync_softc *pfs_if, *tmp;
1755ed1f0be2SJan Lentfer
17562a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
17572a7a2b1cSJan Lentfer
17582a7a2b1cSJan Lentfer switch (type) {
17592a7a2b1cSJan Lentfer case MOD_LOAD:
17602a7a2b1cSJan Lentfer LIST_INIT(&pfsync_list);
17612a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
17622a7a2b1cSJan Lentfer if_clone_attach(&pfsync_cloner);
17632a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
1764ed1f0be2SJan Lentfer /* Override the function pointer for pf_ioctl.c */
17652a7a2b1cSJan Lentfer break;
17662a7a2b1cSJan Lentfer
17672a7a2b1cSJan Lentfer case MOD_UNLOAD:
17682a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
17692a7a2b1cSJan Lentfer if_clone_detach(&pfsync_cloner);
17702a7a2b1cSJan Lentfer lwkt_gettoken(&pf_token);
1771ed1f0be2SJan Lentfer LIST_FOREACH_MUTABLE(pfs_if, &pfsync_list, sc_next, tmp) {
1772ed1f0be2SJan Lentfer pfsync_clone_destroy(&pfs_if->sc_if);
1773ed1f0be2SJan Lentfer }
17742a7a2b1cSJan Lentfer break;
17752a7a2b1cSJan Lentfer
17762a7a2b1cSJan Lentfer default:
17772a7a2b1cSJan Lentfer error = EINVAL;
17782a7a2b1cSJan Lentfer break;
17792a7a2b1cSJan Lentfer }
17802a7a2b1cSJan Lentfer
17812a7a2b1cSJan Lentfer lwkt_reltoken(&pf_token);
17822a7a2b1cSJan Lentfer return error;
17832a7a2b1cSJan Lentfer }
17842a7a2b1cSJan Lentfer
17852a7a2b1cSJan Lentfer static moduledata_t pfsync_mod = {
17862a7a2b1cSJan Lentfer "pfsync",
17872a7a2b1cSJan Lentfer pfsync_modevent,
17882a7a2b1cSJan Lentfer 0
17892a7a2b1cSJan Lentfer };
17902a7a2b1cSJan Lentfer
1791ed1f0be2SJan Lentfer #define PFSYNC_MODVER 44
17922a7a2b1cSJan Lentfer
17932a7a2b1cSJan Lentfer DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
17942a7a2b1cSJan Lentfer MODULE_VERSION(pfsync, PFSYNC_MODVER);
1795c8f430baSAaron LI MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER);
17962a7a2b1cSJan Lentfer
1797ef15d469SSepherosa Ziehau static void
pfsync_in_addmulti_dispatch(netmsg_t nmsg)1798ef15d469SSepherosa Ziehau pfsync_in_addmulti_dispatch(netmsg_t nmsg)
1799ef15d469SSepherosa Ziehau {
1800ef15d469SSepherosa Ziehau struct lwkt_msg *lmsg = &nmsg->lmsg;
1801ef15d469SSepherosa Ziehau struct ifnet *ifp = lmsg->u.ms_resultp;
1802ef15d469SSepherosa Ziehau struct in_addr addr;
180302742ec6SJoerg Sonnenberger
1804ef15d469SSepherosa Ziehau addr.s_addr = INADDR_PFSYNC_GROUP;
1805ef15d469SSepherosa Ziehau lmsg->u.ms_resultp = in_addmulti(&addr, ifp);
180602742ec6SJoerg Sonnenberger
1807ef15d469SSepherosa Ziehau lwkt_replymsg(lmsg, 0);
1808ef15d469SSepherosa Ziehau }
1809ef15d469SSepherosa Ziehau
1810ef15d469SSepherosa Ziehau static struct in_multi *
pfsync_in_addmulti(struct ifnet * ifp)1811ef15d469SSepherosa Ziehau pfsync_in_addmulti(struct ifnet *ifp)
1812ef15d469SSepherosa Ziehau {
1813ef15d469SSepherosa Ziehau struct netmsg_base nmsg;
1814ef15d469SSepherosa Ziehau struct lwkt_msg *lmsg = &nmsg.lmsg;
1815ef15d469SSepherosa Ziehau
1816ef15d469SSepherosa Ziehau netmsg_init(&nmsg, NULL, &curthread->td_msgport, 0,
1817ef15d469SSepherosa Ziehau pfsync_in_addmulti_dispatch);
1818ef15d469SSepherosa Ziehau lmsg->u.ms_resultp = ifp;
1819ef15d469SSepherosa Ziehau
1820ef15d469SSepherosa Ziehau lwkt_domsg(netisr_cpuport(0), lmsg, 0);
1821ef15d469SSepherosa Ziehau return lmsg->u.ms_resultp;
1822ef15d469SSepherosa Ziehau }
1823ef15d469SSepherosa Ziehau
1824ef15d469SSepherosa Ziehau static void
pfsync_in_delmulti_dispatch(netmsg_t nmsg)1825ef15d469SSepherosa Ziehau pfsync_in_delmulti_dispatch(netmsg_t nmsg)
1826ef15d469SSepherosa Ziehau {
1827ef15d469SSepherosa Ziehau struct lwkt_msg *lmsg = &nmsg->lmsg;
1828ef15d469SSepherosa Ziehau
1829ef15d469SSepherosa Ziehau in_delmulti(lmsg->u.ms_resultp);
1830ef15d469SSepherosa Ziehau lwkt_replymsg(lmsg, 0);
1831ef15d469SSepherosa Ziehau }
1832ef15d469SSepherosa Ziehau
1833ef15d469SSepherosa Ziehau static void
pfsync_in_delmulti(struct in_multi * inm)1834ef15d469SSepherosa Ziehau pfsync_in_delmulti(struct in_multi *inm)
1835ef15d469SSepherosa Ziehau {
1836ef15d469SSepherosa Ziehau struct netmsg_base nmsg;
1837ef15d469SSepherosa Ziehau struct lwkt_msg *lmsg = &nmsg.lmsg;
1838ef15d469SSepherosa Ziehau
1839ef15d469SSepherosa Ziehau netmsg_init(&nmsg, NULL, &curthread->td_msgport, 0,
1840ef15d469SSepherosa Ziehau pfsync_in_delmulti_dispatch);
1841ef15d469SSepherosa Ziehau lmsg->u.ms_resultp = inm;
1842ef15d469SSepherosa Ziehau
1843ef15d469SSepherosa Ziehau lwkt_domsg(netisr_cpuport(0), lmsg, 0);
1844ef15d469SSepherosa Ziehau }
1845