Deleted Added
full compact
if_pfsync.c (130613) if_pfsync.c (130933)
1/* $FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 130613 2004-06-16 23:24:02Z mlaier $ */
1/* $FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 130933 2004-06-22 20:13:25Z brooks $ */
2/* $OpenBSD: if_pfsync.c,v 1.26 2004/03/28 18:14:20 mcbride Exp $ */
3
4/*
5 * Copyright (c) 2002 Michael Shalayeff
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#ifdef __FreeBSD__
31#include "opt_inet.h"
32#include "opt_inet6.h"
33#include "opt_random_ip_id.h"
34#endif
35
36#ifndef __FreeBSD__
37#include "bpfilter.h"
38#include "pfsync.h"
39#elif __FreeBSD__ >= 5
40#include "opt_bpf.h"
41#include "opt_pf.h"
42#define NBPFILTER DEV_BPF
43#define NPFSYNC DEV_PFSYNC
44#endif
45
46#include <sys/param.h>
47#include <sys/proc.h>
48#include <sys/systm.h>
49#include <sys/time.h>
50#include <sys/mbuf.h>
51#include <sys/socket.h>
52#ifdef __FreeBSD__
53#include <sys/kernel.h>
54#include <sys/malloc.h>
55#include <sys/module.h>
56#include <sys/sockio.h>
57#include <sys/lock.h>
58#include <sys/mutex.h>
59#else
60#include <sys/ioctl.h>
61#include <sys/timeout.h>
62#endif
63
64#include <net/if.h>
2/* $OpenBSD: if_pfsync.c,v 1.26 2004/03/28 18:14:20 mcbride Exp $ */
3
4/*
5 * Copyright (c) 2002 Michael Shalayeff
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#ifdef __FreeBSD__
31#include "opt_inet.h"
32#include "opt_inet6.h"
33#include "opt_random_ip_id.h"
34#endif
35
36#ifndef __FreeBSD__
37#include "bpfilter.h"
38#include "pfsync.h"
39#elif __FreeBSD__ >= 5
40#include "opt_bpf.h"
41#include "opt_pf.h"
42#define NBPFILTER DEV_BPF
43#define NPFSYNC DEV_PFSYNC
44#endif
45
46#include <sys/param.h>
47#include <sys/proc.h>
48#include <sys/systm.h>
49#include <sys/time.h>
50#include <sys/mbuf.h>
51#include <sys/socket.h>
52#ifdef __FreeBSD__
53#include <sys/kernel.h>
54#include <sys/malloc.h>
55#include <sys/module.h>
56#include <sys/sockio.h>
57#include <sys/lock.h>
58#include <sys/mutex.h>
59#else
60#include <sys/ioctl.h>
61#include <sys/timeout.h>
62#endif
63
64#include <net/if.h>
65#if defined(__FreeBSD__)
66#include <net/if_clone.h>
67#endif
65#include <net/if_types.h>
66#include <net/route.h>
67#include <net/bpf.h>
68
69#ifdef INET
70#include <netinet/in.h>
71#include <netinet/in_systm.h>
72#include <netinet/in_var.h>
73#include <netinet/ip.h>
74#include <netinet/ip_var.h>
75#endif
76
77#ifdef INET6
78#ifndef INET
79#include <netinet/in.h>
80#endif
81#include <netinet6/nd6.h>
82#endif /* INET6 */
83
84#include <net/pfvar.h>
85#include <net/if_pfsync.h>
86
87#ifdef __FreeBSD__
88#define PFSYNCNAME "pfsync"
89#endif
90
91#define PFSYNC_MINMTU \
92 (sizeof(struct pfsync_header) + sizeof(struct pf_state))
93
94#ifdef PFSYNCDEBUG
95#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0)
96int pfsyncdebug;
97#else
98#define DPRINTF(x)
99#endif
100
101#ifndef __FreeBSD__
102struct pfsync_softc pfsyncif;
103#endif
104int pfsync_sync_ok;
105struct pfsyncstats pfsyncstats;
106
107#ifndef RANDOM_IP_ID
108extern u_int16_t ip_randomid(void);
109#endif
110
111#ifdef __FreeBSD__
112
113/*
114 * Locking notes:
115 * Whenever we really touch/look at the state table we have to hold the
116 * PF_LOCK. Functions that do just the interface handling, grab the per
117 * softc lock instead.
118 *
119 */
120
121static void pfsync_clone_destroy(struct ifnet *);
122static int pfsync_clone_create(struct if_clone *, int);
123#else
124void pfsyncattach(int);
125#endif
126void pfsync_setmtu(struct pfsync_softc *, int);
127int pfsync_insert_net_state(struct pfsync_state *);
128int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
129 struct rtentry *);
130int pfsyncioctl(struct ifnet *, u_long, caddr_t);
131void pfsyncstart(struct ifnet *);
132
133struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
134int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
135int pfsync_sendout(struct pfsync_softc *);
136void pfsync_timeout(void *);
137void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
138void pfsync_bulk_update(void *);
139void pfsync_bulkfail(void *);
140
141#ifndef __FreeBSD__
142extern int ifqmaxlen;
143extern struct timeval time;
144extern struct timeval mono_time;
145extern int hz;
146#endif
147
148#ifdef __FreeBSD__
149static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
150static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
68#include <net/if_types.h>
69#include <net/route.h>
70#include <net/bpf.h>
71
72#ifdef INET
73#include <netinet/in.h>
74#include <netinet/in_systm.h>
75#include <netinet/in_var.h>
76#include <netinet/ip.h>
77#include <netinet/ip_var.h>
78#endif
79
80#ifdef INET6
81#ifndef INET
82#include <netinet/in.h>
83#endif
84#include <netinet6/nd6.h>
85#endif /* INET6 */
86
87#include <net/pfvar.h>
88#include <net/if_pfsync.h>
89
90#ifdef __FreeBSD__
91#define PFSYNCNAME "pfsync"
92#endif
93
94#define PFSYNC_MINMTU \
95 (sizeof(struct pfsync_header) + sizeof(struct pf_state))
96
97#ifdef PFSYNCDEBUG
98#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0)
99int pfsyncdebug;
100#else
101#define DPRINTF(x)
102#endif
103
104#ifndef __FreeBSD__
105struct pfsync_softc pfsyncif;
106#endif
107int pfsync_sync_ok;
108struct pfsyncstats pfsyncstats;
109
110#ifndef RANDOM_IP_ID
111extern u_int16_t ip_randomid(void);
112#endif
113
114#ifdef __FreeBSD__
115
116/*
117 * Locking notes:
118 * Whenever we really touch/look at the state table we have to hold the
119 * PF_LOCK. Functions that do just the interface handling, grab the per
120 * softc lock instead.
121 *
122 */
123
124static void pfsync_clone_destroy(struct ifnet *);
125static int pfsync_clone_create(struct if_clone *, int);
126#else
127void pfsyncattach(int);
128#endif
129void pfsync_setmtu(struct pfsync_softc *, int);
130int pfsync_insert_net_state(struct pfsync_state *);
131int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
132 struct rtentry *);
133int pfsyncioctl(struct ifnet *, u_long, caddr_t);
134void pfsyncstart(struct ifnet *);
135
136struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
137int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
138int pfsync_sendout(struct pfsync_softc *);
139void pfsync_timeout(void *);
140void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
141void pfsync_bulk_update(void *);
142void pfsync_bulkfail(void *);
143
144#ifndef __FreeBSD__
145extern int ifqmaxlen;
146extern struct timeval time;
147extern struct timeval mono_time;
148extern int hz;
149#endif
150
151#ifdef __FreeBSD__
152static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
153static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
151struct if_clone pfsync_cloner = IF_CLONE_INITIALIZER(PFSYNCNAME,
152 pfsync_clone_create, pfsync_clone_destroy, 1, IF_MAXUNIT);
154IFC_SIMPLE_DECLARE(pfsync, 1);
153
154static void
155pfsync_clone_destroy(struct ifnet *ifp)
156{
157 struct pfsync_softc *sc;
158
159 sc = ifp->if_softc;
160 callout_stop(&sc->sc_tmo);
161 callout_stop(&sc->sc_bulk_tmo);
162 callout_stop(&sc->sc_bulkfail_tmo);
163
164#if NBPFILTER > 0
165 bpfdetach(ifp);
166#endif
167 if_detach(ifp);
168 LIST_REMOVE(sc, sc_next);
169 free(sc, M_PFSYNC);
170}
171
172static int
173pfsync_clone_create(struct if_clone *ifc, int unit)
174{
175 struct pfsync_softc *sc;
176 struct ifnet *ifp;
177
178 MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
179 M_WAITOK|M_ZERO);
180
181 pfsync_sync_ok = 1;
182 sc->sc_mbuf = NULL;
183 sc->sc_mbuf_net = NULL;
184 sc->sc_statep.s = NULL;
185 sc->sc_statep_net.s = NULL;
186 sc->sc_maxupdates = 128;
187 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
188 sc->sc_ureq_received = 0;
189 sc->sc_ureq_sent = 0;
190
191 ifp = &sc->sc_if;
192 if_initname(ifp, ifc->ifc_name, unit);
193 ifp->if_ioctl = pfsyncioctl;
194 ifp->if_output = pfsyncoutput;
195 ifp->if_start = pfsyncstart;
196 ifp->if_type = IFT_PFSYNC;
197 ifp->if_snd.ifq_maxlen = ifqmaxlen;
198 ifp->if_hdrlen = PFSYNC_HDRLEN;
199 ifp->if_baudrate = IF_Mbps(100);
200 ifp->if_softc = sc;
201 pfsync_setmtu(sc, MCLBYTES);
202 /*
203 * XXX
204 * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
205 * if Gaint lock is removed from the network stack.
206 */
207 callout_init(&sc->sc_tmo, 0);
208 callout_init(&sc->sc_bulk_tmo, 0);
209 callout_init(&sc->sc_bulkfail_tmo, 0);
210 if_attach(&sc->sc_if);
211
212 LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
213#if NBPFILTER > 0
214 bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
215#endif
216
217 return (0);
218}
219#else /* !__FreeBSD__ */
220void
221pfsyncattach(int npfsync)
222{
223 struct ifnet *ifp;
224
225 pfsync_sync_ok = 1;
226 bzero(&pfsyncif, sizeof(pfsyncif));
227 pfsyncif.sc_mbuf = NULL;
228 pfsyncif.sc_mbuf_net = NULL;
229 pfsyncif.sc_statep.s = NULL;
230 pfsyncif.sc_statep_net.s = NULL;
231 pfsyncif.sc_maxupdates = 128;
232 pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
233 pfsyncif.sc_ureq_received = 0;
234 pfsyncif.sc_ureq_sent = 0;
235 ifp = &pfsyncif.sc_if;
236 strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
237 ifp->if_softc = &pfsyncif;
238 ifp->if_ioctl = pfsyncioctl;
239 ifp->if_output = pfsyncoutput;
240 ifp->if_start = pfsyncstart;
241 ifp->if_type = IFT_PFSYNC;
242 ifp->if_snd.ifq_maxlen = ifqmaxlen;
243 ifp->if_hdrlen = PFSYNC_HDRLEN;
244 pfsync_setmtu(&pfsyncif, MCLBYTES);
245 timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
246 timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
247 timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
248 if_attach(ifp);
249 if_alloc_sadl(ifp);
250
251#if NBPFILTER > 0
252 bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
253#endif
254}
255#endif
256
257/*
258 * Start output on the pfsync interface.
259 */
260void
261pfsyncstart(struct ifnet *ifp)
262{
263#ifdef __FreeBSD__
264 IF_LOCK(&ifp->if_snd);
265 _IF_DROP(&ifp->if_snd);
266 _IF_DRAIN(&ifp->if_snd);
267 IF_UNLOCK(&ifp->if_snd);
268#else
269 struct mbuf *m;
270 int s;
271
272 for (;;) {
273 s = splimp();
274 IF_DROP(&ifp->if_snd);
275 IF_DEQUEUE(&ifp->if_snd, m);
276 splx(s);
277
278 if (m == NULL)
279 return;
280 else
281 m_freem(m);
282 }
283#endif
284}
285
286int
287pfsync_insert_net_state(struct pfsync_state *sp)
288{
289 struct pf_state *st = NULL;
290 struct pf_rule *r = NULL;
291 struct pfi_kif *kif;
292
293#ifdef __FreeBSD__
294 PF_ASSERT(MA_OWNED);
295#endif
296 if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
297 printf("pfsync_insert_net_state: invalid creator id:"
298 " %08x\n", ntohl(sp->creatorid));
299 return (EINVAL);
300 }
301
302 kif = pfi_lookup_create(sp->ifname);
303 if (kif == NULL) {
304 if (pf_status.debug >= PF_DEBUG_MISC)
305 printf("pfsync_insert_net_state: "
306 "unknown interface: %s\n", sp->ifname);
307 /* skip this state */
308 return (0);
309 }
310
311 /*
312 * Just use the default rule until we have infrastructure to find the
313 * best matching rule.
314 */
315 r = &pf_default_rule;
316
317 if (!r->max_states || r->states < r->max_states)
318 st = pool_get(&pf_state_pl, PR_NOWAIT);
319 if (st == NULL) {
320 pfi_maybe_destroy(kif);
321 return (ENOMEM);
322 }
323 bzero(st, sizeof(*st));
324
325 st->rule.ptr = r;
326 /* XXX get pointers to nat_rule and anchor */
327
328 /* fill in the rest of the state entry */
329 pf_state_host_ntoh(&sp->lan, &st->lan);
330 pf_state_host_ntoh(&sp->gwy, &st->gwy);
331 pf_state_host_ntoh(&sp->ext, &st->ext);
332
333 pf_state_peer_ntoh(&sp->src, &st->src);
334 pf_state_peer_ntoh(&sp->dst, &st->dst);
335
336 bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
337#ifdef __FreeBSD__
338 st->creation = ntohl(sp->creation) + time_second;
339 st->expire = ntohl(sp->expire) + time_second;
340#else
341 st->creation = ntohl(sp->creation) + time.tv_sec;
342 st->expire = ntohl(sp->expire) + time.tv_sec;
343#endif
344
345 st->af = sp->af;
346 st->proto = sp->proto;
347 st->direction = sp->direction;
348 st->log = sp->log;
349 st->timeout = sp->timeout;
350 st->allow_opts = sp->allow_opts;
351
352 bcopy(sp->id, &st->id, sizeof(st->id));
353 st->creatorid = sp->creatorid;
354 st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC;
355
356
357 if (pf_insert_state(kif, st)) {
358 pfi_maybe_destroy(kif);
359 pool_put(&pf_state_pl, st);
360 return (EINVAL);
361 }
362
363 return (0);
364}
365
366void
367#ifdef __FreeBSD__
368pfsync_input(struct mbuf *m, __unused int off)
369#else
370pfsync_input(struct mbuf *m, ...)
371#endif
372{
373 struct ip *ip = mtod(m, struct ip *);
374 struct pfsync_header *ph;
375#ifdef __FreeBSD__
376 struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
377#else
378 struct pfsync_softc *sc = &pfsyncif;
379#endif
380 struct pf_state *st, key;
381 struct pfsync_state *sp;
382 struct pfsync_state_upd *up;
383 struct pfsync_state_del *dp;
384 struct pfsync_state_clr *cp;
385 struct pfsync_state_upd_req *rup;
386 struct pfsync_state_bus *bus;
387 struct in_addr src;
388 struct mbuf *mp;
389 int iplen, action, error, i, s, count, offp;
390
391 pfsyncstats.pfsyncs_ipackets++;
392
393 /* verify that we have a sync interface configured */
394 if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
395 goto done;
396
397 /* verify that the packet came in on the right interface */
398 if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
399 pfsyncstats.pfsyncs_badif++;
400 goto done;
401 }
402
403 /* verify that the IP TTL is 255. */
404 if (ip->ip_ttl != PFSYNC_DFLTTL) {
405 pfsyncstats.pfsyncs_badttl++;
406 goto done;
407 }
408
409 iplen = ip->ip_hl << 2;
410
411 if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
412 pfsyncstats.pfsyncs_hdrops++;
413 goto done;
414 }
415
416 if (iplen + sizeof(*ph) > m->m_len) {
417 if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
418 pfsyncstats.pfsyncs_hdrops++;
419 goto done;
420 }
421 ip = mtod(m, struct ip *);
422 }
423 ph = (struct pfsync_header *)((char *)ip + iplen);
424
425 /* verify the version */
426 if (ph->version != PFSYNC_VERSION) {
427 pfsyncstats.pfsyncs_badver++;
428 goto done;
429 }
430
431 action = ph->action;
432 count = ph->count;
433
434 /* make sure it's a valid action code */
435 if (action >= PFSYNC_ACT_MAX) {
436 pfsyncstats.pfsyncs_badact++;
437 goto done;
438 }
439
440 /* Cheaper to grab this now than having to mess with mbufs later */
441 src = ip->ip_src;
442
443 switch (action) {
444 case PFSYNC_ACT_CLR: {
445 struct pfi_kif *kif;
446 u_int32_t creatorid;
447 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
448 sizeof(*cp), &offp)) == NULL) {
449 pfsyncstats.pfsyncs_badlen++;
450 return;
451 }
452 cp = (struct pfsync_state_clr *)(mp->m_data + offp);
453 creatorid = cp->creatorid;
454
455 s = splsoftnet();
456#ifdef __FreeBSD__
457 PF_LOCK();
458#endif
459 if (cp->ifname[0] == '\0') {
460 RB_FOREACH(st, pf_state_tree_id, &tree_id) {
461 if (st->creatorid == creatorid)
462 st->timeout = PFTM_PURGE;
463 }
464 } else {
465 kif = pfi_lookup_if(cp->ifname);
466 if (kif == NULL) {
467 if (pf_status.debug >= PF_DEBUG_MISC)
468 printf("pfsync_input: PFSYNC_ACT_CLR "
469 "bad interface: %s\n", cp->ifname);
470 splx(s);
471#ifdef __FreeBSD__
472 PF_UNLOCK();
473#endif
474 goto done;
475 }
476 RB_FOREACH(st, pf_state_tree_lan_ext,
477 &kif->pfik_lan_ext) {
478 if (st->creatorid == creatorid)
479 st->timeout = PFTM_PURGE;
480 }
481 }
482 pf_purge_expired_states();
483#ifdef __FreeBSD__
484 PF_UNLOCK();
485#endif
486 splx(s);
487
488 break;
489 }
490 case PFSYNC_ACT_INS:
491 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
492 count * sizeof(*sp), &offp)) == NULL) {
493 pfsyncstats.pfsyncs_badlen++;
494 return;
495 }
496
497 s = splsoftnet();
498#ifdef __FreeBSD__
499 PF_LOCK();
500#endif
501 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
502 i < count; i++, sp++) {
503 /* check for invalid values */
504 if (sp->timeout >= PFTM_MAX ||
505 sp->src.state > PF_TCPS_PROXY_DST ||
506 sp->dst.state > PF_TCPS_PROXY_DST ||
507 sp->direction > PF_OUT ||
508 (sp->af != AF_INET && sp->af != AF_INET6)) {
509 if (pf_status.debug >= PF_DEBUG_MISC)
510 printf("pfsync_insert: PFSYNC_ACT_INS: "
511 "invalid value\n");
512 pfsyncstats.pfsyncs_badstate++;
513 continue;
514 }
515
516 if ((error = pfsync_insert_net_state(sp))) {
517 if (error == ENOMEM) {
518 splx(s);
519#ifdef __FreeBSD__
520 PF_UNLOCK();
521#endif
522 goto done;
523 }
524 continue;
525 }
526 }
527#ifdef __FreeBSD__
528 PF_UNLOCK();
529#endif
530 splx(s);
531 break;
532 case PFSYNC_ACT_UPD:
533 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
534 count * sizeof(*sp), &offp)) == NULL) {
535 pfsyncstats.pfsyncs_badlen++;
536 return;
537 }
538
539 s = splsoftnet();
540#ifdef __FreeBSD__
541 PF_LOCK();
542#endif
543 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
544 i < count; i++, sp++) {
545 /* check for invalid values */
546 if (sp->timeout >= PFTM_MAX ||
547 sp->src.state > PF_TCPS_PROXY_DST ||
548 sp->dst.state > PF_TCPS_PROXY_DST) {
549 if (pf_status.debug >= PF_DEBUG_MISC)
550 printf("pfsync_insert: PFSYNC_ACT_UPD: "
551 "invalid value\n");
552 pfsyncstats.pfsyncs_badstate++;
553 continue;
554 }
555
556 bcopy(sp->id, &key.id, sizeof(key.id));
557 key.creatorid = sp->creatorid;
558
559 st = pf_find_state_byid(&key);
560 if (st == NULL) {
561 /* insert the update */
562 if (pfsync_insert_net_state(sp))
563 pfsyncstats.pfsyncs_badstate++;
564 continue;
565 }
566 pf_state_peer_ntoh(&sp->src, &st->src);
567 pf_state_peer_ntoh(&sp->dst, &st->dst);
568#ifdef __FreeBSD__
569 st->expire = ntohl(sp->expire) + time_second;
570#else
571 st->expire = ntohl(sp->expire) + time.tv_sec;
572#endif
573 st->timeout = sp->timeout;
574
575 }
576#ifdef __FreeBSD__
577 PF_UNLOCK();
578#endif
579 splx(s);
580 break;
581 /*
582 * It's not strictly necessary for us to support the "uncompressed"
583 * delete action, but it's relatively simple and maintains consistency.
584 */
585 case PFSYNC_ACT_DEL:
586 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
587 count * sizeof(*sp), &offp)) == NULL) {
588 pfsyncstats.pfsyncs_badlen++;
589 return;
590 }
591
592 s = splsoftnet();
593#ifdef __FreeBSD__
594 PF_LOCK();
595#endif
596 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
597 i < count; i++, sp++) {
598 bcopy(sp->id, &key.id, sizeof(key.id));
599 key.creatorid = sp->creatorid;
600
601 st = pf_find_state_byid(&key);
602 if (st == NULL) {
603 pfsyncstats.pfsyncs_badstate++;
604 continue;
605 }
606 /*
607 * XXX
608 * pf_purge_expired_states() is expensive,
609 * we really want to purge the state directly.
610 */
611 st->timeout = PFTM_PURGE;
612 st->sync_flags |= PFSTATE_FROMSYNC;
613 }
614 pf_purge_expired_states();
615#ifdef __FreeBSD__
616 PF_UNLOCK();
617#endif
618 splx(s);
619 break;
620 case PFSYNC_ACT_UPD_C: {
621 int update_requested = 0;
622
623 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
624 count * sizeof(*up), &offp)) == NULL) {
625 pfsyncstats.pfsyncs_badlen++;
626 return;
627 }
628
629 s = splsoftnet();
630#ifdef __FreeBSD__
631 PF_LOCK();
632#endif
633 for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
634 i < count; i++, up++) {
635 /* check for invalid values */
636 if (up->timeout >= PFTM_MAX ||
637 up->src.state > PF_TCPS_PROXY_DST ||
638 up->dst.state > PF_TCPS_PROXY_DST) {
639 if (pf_status.debug >= PF_DEBUG_MISC)
640 printf("pfsync_insert: "
641 "PFSYNC_ACT_UPD_C: "
642 "invalid value\n");
643 pfsyncstats.pfsyncs_badstate++;
644 continue;
645 }
646
647 bcopy(up->id, &key.id, sizeof(key.id));
648 key.creatorid = up->creatorid;
649
650 st = pf_find_state_byid(&key);
651 if (st == NULL) {
652 /* We don't have this state. Ask for it. */
653 pfsync_request_update(up, &src);
654 update_requested = 1;
655 pfsyncstats.pfsyncs_badstate++;
656 continue;
657 }
658 pf_state_peer_ntoh(&up->src, &st->src);
659 pf_state_peer_ntoh(&up->dst, &st->dst);
660#ifdef __FreeBSD__
661 st->expire = ntohl(up->expire) + time_second;
662#else
663 st->expire = ntohl(up->expire) + time.tv_sec;
664#endif
665 st->timeout = up->timeout;
666 }
667 if (update_requested)
668 pfsync_sendout(sc);
669#ifdef __FreeBSD__
670 PF_UNLOCK();
671#endif
672 splx(s);
673 break;
674 }
675 case PFSYNC_ACT_DEL_C:
676 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
677 count * sizeof(*dp), &offp)) == NULL) {
678 pfsyncstats.pfsyncs_badlen++;
679 return;
680 }
681
682 s = splsoftnet();
683#ifdef __FreeBSD__
684 PF_LOCK();
685#endif
686 for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
687 i < count; i++, dp++) {
688 bcopy(dp->id, &key.id, sizeof(key.id));
689 key.creatorid = dp->creatorid;
690
691 st = pf_find_state_byid(&key);
692 if (st == NULL) {
693 pfsyncstats.pfsyncs_badstate++;
694 continue;
695 }
696 /*
697 * XXX
698 * pf_purge_expired_states() is expensive,
699 * we really want to purge the state directly.
700 */
701 st->timeout = PFTM_PURGE;
702 st->sync_flags |= PFSTATE_FROMSYNC;
703 }
704 pf_purge_expired_states();
705#ifdef __FreeBSD__
706 PF_UNLOCK();
707#endif
708 splx(s);
709 break;
710 case PFSYNC_ACT_INS_F:
711 case PFSYNC_ACT_DEL_F:
712 /* not implemented */
713 break;
714 case PFSYNC_ACT_UREQ:
715 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
716 count * sizeof(*rup), &offp)) == NULL) {
717 pfsyncstats.pfsyncs_badlen++;
718 return;
719 }
720
721 s = splsoftnet();
722 /* XXX send existing. pfsync_pack_state should handle this. */
723#ifdef __FreeBSD__
724 PF_LOCK();
725#endif
726 if (sc->sc_mbuf != NULL)
727 pfsync_sendout(sc);
728 for (i = 0,
729 rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
730 i < count; i++, rup++) {
731 bcopy(rup->id, &key.id, sizeof(key.id));
732 key.creatorid = rup->creatorid;
733
734 if (key.id == 0 && key.creatorid == 0) {
735#ifdef __FreeBSD__
736 sc->sc_ureq_received = time_uptime;
737#else
738 sc->sc_ureq_received = mono_time.tv_sec;
739#endif
740 if (pf_status.debug >= PF_DEBUG_MISC)
741 printf("pfsync: received "
742 "bulk update request\n");
743 pfsync_send_bus(sc, PFSYNC_BUS_START);
744#ifdef __FreeBSD__
745 callout_reset(&sc->sc_bulk_tmo, 1 * hz,
746 pfsync_bulk_update,
747 LIST_FIRST(&pfsync_list));
748#else
749 timeout_add(&sc->sc_bulk_tmo, 1 * hz);
750#endif
751 } else {
752 st = pf_find_state_byid(&key);
753 if (st == NULL) {
754 pfsyncstats.pfsyncs_badstate++;
755 continue;
756 }
757 pfsync_pack_state(PFSYNC_ACT_UPD, st, 0);
758 }
759 }
760 if (sc->sc_mbuf != NULL)
761 pfsync_sendout(sc);
762#ifdef __FreeBSD__
763 PF_UNLOCK();
764#endif
765 splx(s);
766 break;
767 case PFSYNC_ACT_BUS:
768 /* If we're not waiting for a bulk update, who cares. */
769 if (sc->sc_ureq_sent == 0)
770 break;
771
772 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
773 sizeof(*bus), &offp)) == NULL) {
774 pfsyncstats.pfsyncs_badlen++;
775 return;
776 }
777 bus = (struct pfsync_state_bus *)(mp->m_data + offp);
778 switch (bus->status) {
779 case PFSYNC_BUS_START:
780#ifdef __FreeBSD__
781 callout_reset(&sc->sc_bulkfail_tmo,
782 pf_pool_limits[PF_LIMIT_STATES].limit /
783 (PFSYNC_BULKPACKETS * sc->sc_maxcount),
784 pfsync_bulkfail, LIST_FIRST(&pfsync_list));
785#else
786 timeout_add(&sc->sc_bulkfail_tmo,
787 pf_pool_limits[PF_LIMIT_STATES].limit /
788 (PFSYNC_BULKPACKETS * sc->sc_maxcount));
789#endif
790 if (pf_status.debug >= PF_DEBUG_MISC)
791 printf("pfsync: received bulk "
792 "update start\n");
793 break;
794 case PFSYNC_BUS_END:
795#ifdef __FreeBSD__
796 if (time_uptime - ntohl(bus->endtime) >=
797#else
798 if (mono_time.tv_sec - ntohl(bus->endtime) >=
799#endif
800 sc->sc_ureq_sent) {
801 /* that's it, we're happy */
802 sc->sc_ureq_sent = 0;
803 sc->sc_bulk_tries = 0;
804#ifdef __FreeBSD__
805 callout_stop(&sc->sc_bulkfail_tmo);
806#else
807 timeout_del(&sc->sc_bulkfail_tmo);
808#endif
809 pfsync_sync_ok = 1;
810 if (pf_status.debug >= PF_DEBUG_MISC)
811 printf("pfsync: received valid "
812 "bulk update end\n");
813 } else {
814 if (pf_status.debug >= PF_DEBUG_MISC)
815 printf("pfsync: received invalid "
816 "bulk update end: bad timestamp\n");
817 }
818 break;
819 }
820 break;
821 }
822
823done:
824 if (m)
825 m_freem(m);
826}
827
828int
829pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
830 struct rtentry *rt)
831{
832 m_freem(m);
833 return (0);
834}
835
836/* ARGSUSED */
837int
838pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
839{
840#ifndef __FreeBSD__
841 struct proc *p = curproc;
842#endif
843 struct pfsync_softc *sc = ifp->if_softc;
844 struct ifreq *ifr = (struct ifreq *)data;
845 struct ip_moptions *imo = &sc->sc_imo;
846 struct pfsyncreq pfsyncr;
847 struct ifnet *sifp;
848 int s, error;
849
850 switch (cmd) {
851 case SIOCSIFADDR:
852 case SIOCAIFADDR:
853 case SIOCSIFDSTADDR:
854 case SIOCSIFFLAGS:
855 if (ifp->if_flags & IFF_UP)
856 ifp->if_flags |= IFF_RUNNING;
857 else
858 ifp->if_flags &= ~IFF_RUNNING;
859 break;
860 case SIOCSIFMTU:
861 if (ifr->ifr_mtu < PFSYNC_MINMTU)
862 return (EINVAL);
863 if (ifr->ifr_mtu > MCLBYTES)
864 ifr->ifr_mtu = MCLBYTES;
865 s = splnet();
866#ifdef __FreeBSD__
867 PF_LOCK();
868#endif
869 if (ifr->ifr_mtu < ifp->if_mtu) {
870 pfsync_sendout(sc);
871 }
872 pfsync_setmtu(sc, ifr->ifr_mtu);
873#ifdef __FreeBSD__
874 PF_UNLOCK();
875#endif
876 splx(s);
877 break;
878 case SIOCGETPFSYNC:
879#ifdef __FreeBSD__
880 /* XXX: read unlocked */
881#endif
882 bzero(&pfsyncr, sizeof(pfsyncr));
883 if (sc->sc_sync_ifp)
884 strlcpy(pfsyncr.pfsyncr_syncif,
885 sc->sc_sync_ifp->if_xname, IFNAMSIZ);
886 pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
887 if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
888 return (error);
889 break;
890 case SIOCSETPFSYNC:
891#ifdef __FreeBSD__
892 if ((error = suser(curthread)) != 0)
893#else
894 if ((error = suser(p, p->p_acflag)) != 0)
895#endif
896 return (error);
897 if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
898 return (error);
899
900 if (pfsyncr.pfsyncr_maxupdates > 255)
901 return (EINVAL);
902#ifdef __FreeBSD__
903 PF_LOCK();
904#endif
905 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
906
907 if (pfsyncr.pfsyncr_syncif[0] == 0) {
908 sc->sc_sync_ifp = NULL;
909 if (sc->sc_mbuf_net != NULL) {
910 /* Don't keep stale pfsync packets around. */
911 s = splnet();
912 m_freem(sc->sc_mbuf_net);
913 sc->sc_mbuf_net = NULL;
914 sc->sc_statep_net.s = NULL;
915 splx(s);
916 }
917#ifdef __FreeBSD__
918 PF_UNLOCK();
919#endif
920 break;
921 }
922 if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL) {
923#ifdef __FreeBSD__
924 PF_UNLOCK();
925#endif
926 return (EINVAL);
927 }
928 else if (sifp == sc->sc_sync_ifp) {
929#ifdef __FreeBSD__
930 PF_UNLOCK();
931#endif
932 break;
933 }
934
935 s = splnet();
936 if (sifp->if_mtu < sc->sc_if.if_mtu ||
937 (sc->sc_sync_ifp != NULL &&
938 sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
939 sifp->if_mtu < MCLBYTES - sizeof(struct ip))
940 pfsync_sendout(sc);
941 sc->sc_sync_ifp = sifp;
942
943 pfsync_setmtu(sc, sc->sc_if.if_mtu);
944
945 if (imo->imo_num_memberships > 0) {
946 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
947 imo->imo_multicast_ifp = NULL;
948 }
949
950 if (sc->sc_sync_ifp) {
951 struct in_addr addr;
952
953#ifdef __FreeBSD__
954 PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */
955 addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
956#else
957 addr.s_addr = INADDR_PFSYNC_GROUP;
958#endif
959 if ((imo->imo_membership[0] =
960 in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
961 splx(s);
962 return (ENOBUFS);
963 }
964 imo->imo_num_memberships++;
965 imo->imo_multicast_ifp = sc->sc_sync_ifp;
966 imo->imo_multicast_ttl = PFSYNC_DFLTTL;
967 imo->imo_multicast_loop = 0;
968
969 /* Request a full state table update. */
970#ifdef __FreeBSD__
971 PF_LOCK();
972 sc->sc_ureq_sent = time_uptime;
973#else
974 sc->sc_ureq_sent = mono_time.tv_sec;
975#endif
976 pfsync_sync_ok = 0;
977 if (pf_status.debug >= PF_DEBUG_MISC)
978 printf("pfsync: requesting bulk update\n");
979#ifdef __FreeBSD__
980 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
981 pfsync_bulkfail, LIST_FIRST(&pfsync_list));
982#else
983 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
984#endif
985 pfsync_request_update(NULL, NULL);
986 pfsync_sendout(sc);
987 }
988#ifdef __FreeBSD__
989 PF_UNLOCK();
990#endif
991 splx(s);
992
993 break;
994
995 default:
996 return (ENOTTY);
997 }
998
999 return (0);
1000}
1001
1002void
1003pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
1004{
1005 int mtu;
1006
1007 if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
1008 mtu = sc->sc_sync_ifp->if_mtu;
1009 else
1010 mtu = mtu_req;
1011
1012 sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
1013 sizeof(struct pfsync_state);
1014 if (sc->sc_maxcount > 254)
1015 sc->sc_maxcount = 254;
1016 sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
1017 sc->sc_maxcount * sizeof(struct pfsync_state);
1018}
1019
1020struct mbuf *
1021pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
1022{
1023 struct pfsync_header *h;
1024 struct mbuf *m;
1025 int len;
1026
1027#ifdef __FreeBSD__
1028 PF_ASSERT(MA_OWNED);
1029#endif
1030 MGETHDR(m, M_DONTWAIT, MT_DATA);
1031 if (m == NULL) {
1032 sc->sc_if.if_oerrors++;
1033 return (NULL);
1034 }
1035
1036 switch (action) {
1037 case PFSYNC_ACT_CLR:
1038 len = sizeof(struct pfsync_header) +
1039 sizeof(struct pfsync_state_clr);
1040 break;
1041 case PFSYNC_ACT_UPD_C:
1042 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
1043 sizeof(struct pfsync_header);
1044 break;
1045 case PFSYNC_ACT_DEL_C:
1046 len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
1047 sizeof(struct pfsync_header);
1048 break;
1049 case PFSYNC_ACT_UREQ:
1050 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
1051 sizeof(struct pfsync_header);
1052 break;
1053 case PFSYNC_ACT_BUS:
1054 len = sizeof(struct pfsync_header) +
1055 sizeof(struct pfsync_state_bus);
1056 break;
1057 default:
1058 len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
1059 sizeof(struct pfsync_header);
1060 break;
1061 }
1062
1063 if (len > MHLEN) {
1064 MCLGET(m, M_DONTWAIT);
1065 if ((m->m_flags & M_EXT) == 0) {
1066 m_free(m);
1067 sc->sc_if.if_oerrors++;
1068 return (NULL);
1069 }
1070 m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
1071 } else
1072 MH_ALIGN(m, len);
1073
1074 m->m_pkthdr.rcvif = NULL;
1075 m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
1076 h = mtod(m, struct pfsync_header *);
1077 h->version = PFSYNC_VERSION;
1078 h->af = 0;
1079 h->count = 0;
1080 h->action = action;
1081
1082 *sp = (void *)((char *)h + PFSYNC_HDRLEN);
1083#ifdef __FreeBSD__
1084 callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1085 LIST_FIRST(&pfsync_list));
1086#else
1087 timeout_add(&sc->sc_tmo, hz);
1088#endif
1089 return (m);
1090}
1091
1092int
1093pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
1094{
1095#ifdef __FreeBSD__
1096 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1097#else
1098 struct ifnet *ifp = &pfsyncif.sc_if;
1099#endif
1100 struct pfsync_softc *sc = ifp->if_softc;
1101 struct pfsync_header *h, *h_net;
1102 struct pfsync_state *sp = NULL;
1103 struct pfsync_state_upd *up = NULL;
1104 struct pfsync_state_del *dp = NULL;
1105 struct pf_rule *r;
1106 u_long secs;
1107 int s, ret = 0;
1108 u_int8_t i = 255, newaction = 0;
1109
1110#ifdef __FreeBSD__
1111 PF_ASSERT(MA_OWNED);
1112#endif
1113 /*
1114 * If a packet falls in the forest and there's nobody around to
1115 * hear, does it make a sound?
1116 */
1117 if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL) {
1118 /* Don't leave any stale pfsync packets hanging around. */
1119 if (sc->sc_mbuf != NULL) {
1120 m_freem(sc->sc_mbuf);
1121 sc->sc_mbuf = NULL;
1122 sc->sc_statep.s = NULL;
1123 }
1124 return (0);
1125 }
1126
1127 if (action >= PFSYNC_ACT_MAX)
1128 return (EINVAL);
1129
1130 s = splnet();
1131 if (sc->sc_mbuf == NULL) {
1132 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1133 (void *)&sc->sc_statep.s)) == NULL) {
1134 splx(s);
1135 return (ENOMEM);
1136 }
1137 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1138 } else {
1139 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1140 if (h->action != action) {
1141 pfsync_sendout(sc);
1142 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1143 (void *)&sc->sc_statep.s)) == NULL) {
1144 splx(s);
1145 return (ENOMEM);
1146 }
1147 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1148 } else {
1149 /*
1150 * If it's an update, look in the packet to see if
1151 * we already have an update for the state.
1152 */
1153 if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
1154 struct pfsync_state *usp =
1155 (void *)((char *)h + PFSYNC_HDRLEN);
1156
1157 for (i = 0; i < h->count; i++) {
1158 if (!memcmp(usp->id, &st->id,
1159 PFSYNC_ID_LEN) &&
1160 usp->creatorid == st->creatorid) {
1161 sp = usp;
1162 sp->updates++;
1163 break;
1164 }
1165 usp++;
1166 }
1167 }
1168 }
1169 }
1170
1171#ifdef __FreeBSD__
1172 secs = time_second;
1173
1174 st->pfsync_time = time_uptime;
1175#else
1176 secs = time.tv_sec;
1177
1178 st->pfsync_time = mono_time.tv_sec;
1179#endif
1180 TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
1181 TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
1182
1183 if (sp == NULL) {
1184 /* not a "duplicate" update */
1185 i = 255;
1186 sp = sc->sc_statep.s++;
1187 sc->sc_mbuf->m_pkthdr.len =
1188 sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
1189 h->count++;
1190 bzero(sp, sizeof(*sp));
1191
1192 bcopy(&st->id, sp->id, sizeof(sp->id));
1193 sp->creatorid = st->creatorid;
1194
1195 strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
1196 pf_state_host_hton(&st->lan, &sp->lan);
1197 pf_state_host_hton(&st->gwy, &sp->gwy);
1198 pf_state_host_hton(&st->ext, &sp->ext);
1199
1200 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
1201
1202 sp->creation = htonl(secs - st->creation);
1203 sp->packets[0] = htonl(st->packets[0]);
1204 sp->packets[1] = htonl(st->packets[1]);
1205 sp->bytes[0] = htonl(st->bytes[0]);
1206 sp->bytes[1] = htonl(st->bytes[1]);
1207 if ((r = st->rule.ptr) == NULL)
1208 sp->rule = htonl(-1);
1209 else
1210 sp->rule = htonl(r->nr);
1211 if ((r = st->anchor.ptr) == NULL)
1212 sp->anchor = htonl(-1);
1213 else
1214 sp->anchor = htonl(r->nr);
1215 sp->af = st->af;
1216 sp->proto = st->proto;
1217 sp->direction = st->direction;
1218 sp->log = st->log;
1219 sp->allow_opts = st->allow_opts;
1220 sp->timeout = st->timeout;
1221
1222 sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC;
1223 }
1224
1225 pf_state_peer_hton(&st->src, &sp->src);
1226 pf_state_peer_hton(&st->dst, &sp->dst);
1227
1228 if (st->expire <= secs)
1229 sp->expire = htonl(0);
1230 else
1231 sp->expire = htonl(st->expire - secs);
1232
1233 /* do we need to build "compressed" actions for network transfer? */
1234 if (sc->sc_sync_ifp && compress) {
1235 switch (action) {
1236 case PFSYNC_ACT_UPD:
1237 newaction = PFSYNC_ACT_UPD_C;
1238 break;
1239 case PFSYNC_ACT_DEL:
1240 newaction = PFSYNC_ACT_DEL_C;
1241 break;
1242 default:
1243 /* by default we just send the uncompressed states */
1244 break;
1245 }
1246 }
1247
1248 if (newaction) {
1249 if (sc->sc_mbuf_net == NULL) {
1250 if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
1251 (void *)&sc->sc_statep_net.s)) == NULL) {
1252 splx(s);
1253 return (ENOMEM);
1254 }
1255 }
1256 h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
1257
1258 switch (newaction) {
1259 case PFSYNC_ACT_UPD_C:
1260 if (i != 255) {
1261 up = (void *)((char *)h_net +
1262 PFSYNC_HDRLEN + (i * sizeof(*up)));
1263 up->updates++;
1264 } else {
1265 h_net->count++;
1266 sc->sc_mbuf_net->m_pkthdr.len =
1267 sc->sc_mbuf_net->m_len += sizeof(*up);
1268 up = sc->sc_statep_net.u++;
1269
1270 bzero(up, sizeof(*up));
1271 bcopy(&st->id, up->id, sizeof(up->id));
1272 up->creatorid = st->creatorid;
1273 }
1274 up->timeout = st->timeout;
1275 up->expire = sp->expire;
1276 up->src = sp->src;
1277 up->dst = sp->dst;
1278 break;
1279 case PFSYNC_ACT_DEL_C:
1280 sc->sc_mbuf_net->m_pkthdr.len =
1281 sc->sc_mbuf_net->m_len += sizeof(*dp);
1282 dp = sc->sc_statep_net.d++;
1283 h_net->count++;
1284
1285 bzero(dp, sizeof(*dp));
1286 bcopy(&st->id, dp->id, sizeof(dp->id));
1287 dp->creatorid = st->creatorid;
1288 break;
1289 }
1290 }
1291
1292 if (h->count == sc->sc_maxcount ||
1293 (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1294 ret = pfsync_sendout(sc);
1295
1296 splx(s);
1297 return (ret);
1298}
1299
1300/* This must be called in splnet() */
1301int
1302pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1303{
1304#ifdef __FreeBSD__
1305 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1306#else
1307 struct ifnet *ifp = &pfsyncif.sc_if;
1308#endif
1309 struct pfsync_header *h;
1310 struct pfsync_softc *sc = ifp->if_softc;
1311 struct pfsync_state_upd_req *rup;
1312 int s, ret = 0; /* make the compiler happy */
1313
1314#ifdef __FreeBSD__
1315 PF_ASSERT(MA_OWNED);
1316#endif
1317 if (sc->sc_mbuf == NULL) {
1318 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1319 (void *)&sc->sc_statep.s)) == NULL) {
1320 splx(s);
1321 return (ENOMEM);
1322 }
1323 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1324 } else {
1325 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1326 if (h->action != PFSYNC_ACT_UREQ) {
1327 pfsync_sendout(sc);
1328 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1329 (void *)&sc->sc_statep.s)) == NULL) {
1330 splx(s);
1331 return (ENOMEM);
1332 }
1333 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1334 }
1335 }
1336
1337 if (src != NULL)
1338 sc->sc_sendaddr = *src;
1339 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1340 h->count++;
1341 rup = sc->sc_statep.r++;
1342 bzero(rup, sizeof(*rup));
1343 if (up != NULL) {
1344 bcopy(up->id, rup->id, sizeof(rup->id));
1345 rup->creatorid = up->creatorid;
1346 }
1347
1348 if (h->count == sc->sc_maxcount)
1349 ret = pfsync_sendout(sc);
1350
1351 return (ret);
1352}
1353
1354int
1355pfsync_clear_states(u_int32_t creatorid, char *ifname)
1356{
1357#ifdef __FreeBSD__
1358 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1359#else
1360 struct ifnet *ifp = &pfsyncif.sc_if;
1361#endif
1362 struct pfsync_softc *sc = ifp->if_softc;
1363 struct pfsync_state_clr *cp;
1364 int s, ret;
1365
1366 s = splnet();
1367#ifdef __FreeBSD__
1368 PF_ASSERT(MA_OWNED);
1369#endif
1370 if (sc->sc_mbuf != NULL)
1371 pfsync_sendout(sc);
1372 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1373 (void *)&sc->sc_statep.c)) == NULL) {
1374 splx(s);
1375 return (ENOMEM);
1376 }
1377 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1378 cp = sc->sc_statep.c;
1379 cp->creatorid = creatorid;
1380 if (ifname != NULL)
1381 strlcpy(cp->ifname, ifname, IFNAMSIZ);
1382
1383 ret = (pfsync_sendout(sc));
1384 splx(s);
1385 return (ret);
1386}
1387
1388void
1389pfsync_timeout(void *v)
1390{
1391 struct pfsync_softc *sc = v;
1392 int s;
1393
1394 s = splnet();
1395#ifdef __FreeBSD__
1396 PF_LOCK();
1397#endif
1398 pfsync_sendout(sc);
1399#ifdef __FreeBSD__
1400 PF_UNLOCK();
1401#endif
1402 splx(s);
1403}
1404
1405void
1406pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1407{
1408 struct pfsync_state_bus *bus;
1409
1410#ifdef __FreeBSD__
1411 PF_ASSERT(MA_OWNED);
1412#endif
1413 if (sc->sc_mbuf != NULL)
1414 pfsync_sendout(sc);
1415
1416 if (pfsync_sync_ok &&
1417 (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1418 (void *)&sc->sc_statep.b)) != NULL) {
1419 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1420 bus = sc->sc_statep.b;
1421 bus->creatorid = pf_status.hostid;
1422 bus->status = status;
1423#ifdef __FreeBSD__
1424 bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
1425#else
1426 bus->endtime = htonl(mono_time.tv_sec - sc->sc_ureq_received);
1427#endif
1428 pfsync_sendout(sc);
1429 }
1430}
1431
1432void
1433pfsync_bulk_update(void *v)
1434{
1435 struct pfsync_softc *sc = v;
1436 int s, i = 0;
1437 struct pf_state *state;
1438
1439#ifdef __FreeBSD__
1440 PF_LOCK();
1441#endif
1442 s = splnet();
1443 if (sc->sc_mbuf != NULL)
1444 pfsync_sendout(sc);
1445
1446 /*
1447 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1448 * been sent since the latest request was made.
1449 */
1450 while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1451 ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1452 if (state->pfsync_time > sc->sc_ureq_received) {
1453 /* we're done */
1454 pfsync_send_bus(sc, PFSYNC_BUS_END);
1455 sc->sc_ureq_received = 0;
1456#ifdef __FreeBSD__
1457 callout_stop(&sc->sc_bulk_tmo);
1458#else
1459 timeout_del(&sc->sc_bulk_tmo);
1460#endif
1461 if (pf_status.debug >= PF_DEBUG_MISC)
1462 printf("pfsync: bulk update complete\n");
1463 break;
1464 } else {
1465 /* send an update and move to end of list */
1466 if (!state->sync_flags)
1467 pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1468#ifdef __FreeBSD__
1469 state->pfsync_time = time_uptime;
1470#else
1471 state->pfsync_time = mono_time.tv_sec;
1472#endif
1473 TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1474 TAILQ_INSERT_TAIL(&state_updates, state,
1475 u.s.entry_updates);
1476
1477 /* look again for more in a bit */
1478#ifdef __FreeBSD__
1479 callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1480 LIST_FIRST(&pfsync_list));
1481#else
1482 timeout_add(&sc->sc_bulk_tmo, 1);
1483#endif
1484 }
1485 }
1486 if (sc->sc_mbuf != NULL)
1487 pfsync_sendout(sc);
1488 splx(s);
1489#ifdef __FreeBSD__
1490 PF_UNLOCK();
1491#endif
1492}
1493
1494void
1495pfsync_bulkfail(void *v)
1496{
1497 struct pfsync_softc *sc = v;
1498
1499#ifdef __FreeBSD__
1500 PF_LOCK();
1501#endif
1502 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1503 /* Try again in a bit */
1504#ifdef __FreeBSD__
1505 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1506 LIST_FIRST(&pfsync_list));
1507#else
1508 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1509#endif
1510 pfsync_request_update(NULL, NULL);
1511 pfsync_sendout(sc);
1512 } else {
1513 /* Pretend like the transfer was ok */
1514 sc->sc_ureq_sent = 0;
1515 sc->sc_bulk_tries = 0;
1516 pfsync_sync_ok = 1;
1517 if (pf_status.debug >= PF_DEBUG_MISC)
1518 printf("pfsync: failed to receive "
1519 "bulk update status\n");
1520#ifdef __FreeBSD__
1521 callout_stop(&sc->sc_bulkfail_tmo);
1522#else
1523 timeout_del(&sc->sc_bulkfail_tmo);
1524#endif
1525 }
1526#ifdef __FreeBSD__
1527 PF_UNLOCK();
1528#endif
1529}
1530
1531int
1532pfsync_sendout(sc)
1533 struct pfsync_softc *sc;
1534{
1535 struct ifnet *ifp = &sc->sc_if;
1536 struct mbuf *m;
1537
1538#ifdef __FreeBSD__
1539 PF_ASSERT(MA_OWNED);
1540 callout_stop(&sc->sc_tmo);
1541#else
1542 timeout_del(&sc->sc_tmo);
1543#endif
1544
1545 if (sc->sc_mbuf == NULL)
1546 return (0);
1547 m = sc->sc_mbuf;
1548 sc->sc_mbuf = NULL;
1549 sc->sc_statep.s = NULL;
1550
1551#ifdef __FreeBSD__
1552 KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1553#endif
1554#if NBPFILTER > 0
1555 if (ifp->if_bpf)
1556 bpf_mtap(ifp->if_bpf, m);
1557#endif
1558
1559 if (sc->sc_mbuf_net) {
1560 m_freem(m);
1561 m = sc->sc_mbuf_net;
1562 sc->sc_mbuf_net = NULL;
1563 sc->sc_statep_net.s = NULL;
1564 }
1565
1566 if (sc->sc_sync_ifp) {
1567 struct ip *ip;
1568 struct ifaddr *ifa;
1569 struct sockaddr sa;
1570
1571 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
1572 if (m == NULL) {
1573 pfsyncstats.pfsyncs_onomem++;
1574 return (0);
1575 }
1576 ip = mtod(m, struct ip *);
1577 ip->ip_v = IPVERSION;
1578 ip->ip_hl = sizeof(*ip) >> 2;
1579 ip->ip_tos = IPTOS_LOWDELAY;
1580#ifdef __FreeBSD__
1581 ip->ip_len = m->m_pkthdr.len;
1582#else
1583 ip->ip_len = htons(m->m_pkthdr.len);
1584#endif
1585 ip->ip_id = htons(ip_randomid());
1586#ifdef __FreeBSD__
1587 ip->ip_off = IP_DF;
1588#else
1589 ip->ip_off = htons(IP_DF);
1590#endif
1591 ip->ip_ttl = PFSYNC_DFLTTL;
1592 ip->ip_p = IPPROTO_PFSYNC;
1593 ip->ip_sum = 0;
1594
1595 bzero(&sa, sizeof(sa));
1596 sa.sa_family = AF_INET;
1597 ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp);
1598 if (ifa == NULL)
1599 return (0);
1600 ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
1601
1602#ifdef __FreeBSD__
1603 if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1604#else
1605 if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
1606#endif
1607 m->m_flags |= M_MCAST;
1608 ip->ip_dst = sc->sc_sendaddr;
1609#ifdef __FreeBSD__
1610 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1611#else
1612 sc->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
1613#endif
1614
1615 pfsyncstats.pfsyncs_opackets++;
1616
1617#ifdef __FreeBSD__
1618 PF_UNLOCK();
1619#endif
1620 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1621 pfsyncstats.pfsyncs_oerrors++;
1622
1623#ifdef __FreeBSD__
1624 PF_LOCK();
1625#endif
1626 } else
1627 m_freem(m);
1628
1629 return (0);
1630}
1631
1632
1633#ifdef __FreeBSD__
1634static int
1635pfsync_modevent(module_t mod, int type, void *data)
1636{
1637 int error = 0;
1638
1639 switch (type) {
1640 case MOD_LOAD:
1641 LIST_INIT(&pfsync_list);
1642 if_clone_attach(&pfsync_cloner);
1643 break;
1644
1645 case MOD_UNLOAD:
1646 if_clone_detach(&pfsync_cloner);
1647 while (!LIST_EMPTY(&pfsync_list))
1648 pfsync_clone_destroy(
1649 &LIST_FIRST(&pfsync_list)->sc_if);
1650 break;
1651
1652 default:
1653 error = EINVAL;
1654 break;
1655 }
1656
1657 return error;
1658}
1659
1660static moduledata_t pfsync_mod = {
1661 "pfsync",
1662 pfsync_modevent,
1663 0
1664};
1665
1666#define PFSYNC_MODVER 1
1667
1668DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
1669MODULE_VERSION(pfsync, PFSYNC_MODVER);
1670#endif /* __FreeBSD__ */
155
156static void
157pfsync_clone_destroy(struct ifnet *ifp)
158{
159 struct pfsync_softc *sc;
160
161 sc = ifp->if_softc;
162 callout_stop(&sc->sc_tmo);
163 callout_stop(&sc->sc_bulk_tmo);
164 callout_stop(&sc->sc_bulkfail_tmo);
165
166#if NBPFILTER > 0
167 bpfdetach(ifp);
168#endif
169 if_detach(ifp);
170 LIST_REMOVE(sc, sc_next);
171 free(sc, M_PFSYNC);
172}
173
174static int
175pfsync_clone_create(struct if_clone *ifc, int unit)
176{
177 struct pfsync_softc *sc;
178 struct ifnet *ifp;
179
180 MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
181 M_WAITOK|M_ZERO);
182
183 pfsync_sync_ok = 1;
184 sc->sc_mbuf = NULL;
185 sc->sc_mbuf_net = NULL;
186 sc->sc_statep.s = NULL;
187 sc->sc_statep_net.s = NULL;
188 sc->sc_maxupdates = 128;
189 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
190 sc->sc_ureq_received = 0;
191 sc->sc_ureq_sent = 0;
192
193 ifp = &sc->sc_if;
194 if_initname(ifp, ifc->ifc_name, unit);
195 ifp->if_ioctl = pfsyncioctl;
196 ifp->if_output = pfsyncoutput;
197 ifp->if_start = pfsyncstart;
198 ifp->if_type = IFT_PFSYNC;
199 ifp->if_snd.ifq_maxlen = ifqmaxlen;
200 ifp->if_hdrlen = PFSYNC_HDRLEN;
201 ifp->if_baudrate = IF_Mbps(100);
202 ifp->if_softc = sc;
203 pfsync_setmtu(sc, MCLBYTES);
204 /*
205 * XXX
206 * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
207 * if Gaint lock is removed from the network stack.
208 */
209 callout_init(&sc->sc_tmo, 0);
210 callout_init(&sc->sc_bulk_tmo, 0);
211 callout_init(&sc->sc_bulkfail_tmo, 0);
212 if_attach(&sc->sc_if);
213
214 LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
215#if NBPFILTER > 0
216 bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
217#endif
218
219 return (0);
220}
221#else /* !__FreeBSD__ */
222void
223pfsyncattach(int npfsync)
224{
225 struct ifnet *ifp;
226
227 pfsync_sync_ok = 1;
228 bzero(&pfsyncif, sizeof(pfsyncif));
229 pfsyncif.sc_mbuf = NULL;
230 pfsyncif.sc_mbuf_net = NULL;
231 pfsyncif.sc_statep.s = NULL;
232 pfsyncif.sc_statep_net.s = NULL;
233 pfsyncif.sc_maxupdates = 128;
234 pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
235 pfsyncif.sc_ureq_received = 0;
236 pfsyncif.sc_ureq_sent = 0;
237 ifp = &pfsyncif.sc_if;
238 strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
239 ifp->if_softc = &pfsyncif;
240 ifp->if_ioctl = pfsyncioctl;
241 ifp->if_output = pfsyncoutput;
242 ifp->if_start = pfsyncstart;
243 ifp->if_type = IFT_PFSYNC;
244 ifp->if_snd.ifq_maxlen = ifqmaxlen;
245 ifp->if_hdrlen = PFSYNC_HDRLEN;
246 pfsync_setmtu(&pfsyncif, MCLBYTES);
247 timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
248 timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
249 timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
250 if_attach(ifp);
251 if_alloc_sadl(ifp);
252
253#if NBPFILTER > 0
254 bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
255#endif
256}
257#endif
258
259/*
260 * Start output on the pfsync interface.
261 */
262void
263pfsyncstart(struct ifnet *ifp)
264{
265#ifdef __FreeBSD__
266 IF_LOCK(&ifp->if_snd);
267 _IF_DROP(&ifp->if_snd);
268 _IF_DRAIN(&ifp->if_snd);
269 IF_UNLOCK(&ifp->if_snd);
270#else
271 struct mbuf *m;
272 int s;
273
274 for (;;) {
275 s = splimp();
276 IF_DROP(&ifp->if_snd);
277 IF_DEQUEUE(&ifp->if_snd, m);
278 splx(s);
279
280 if (m == NULL)
281 return;
282 else
283 m_freem(m);
284 }
285#endif
286}
287
288int
289pfsync_insert_net_state(struct pfsync_state *sp)
290{
291 struct pf_state *st = NULL;
292 struct pf_rule *r = NULL;
293 struct pfi_kif *kif;
294
295#ifdef __FreeBSD__
296 PF_ASSERT(MA_OWNED);
297#endif
298 if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
299 printf("pfsync_insert_net_state: invalid creator id:"
300 " %08x\n", ntohl(sp->creatorid));
301 return (EINVAL);
302 }
303
304 kif = pfi_lookup_create(sp->ifname);
305 if (kif == NULL) {
306 if (pf_status.debug >= PF_DEBUG_MISC)
307 printf("pfsync_insert_net_state: "
308 "unknown interface: %s\n", sp->ifname);
309 /* skip this state */
310 return (0);
311 }
312
313 /*
314 * Just use the default rule until we have infrastructure to find the
315 * best matching rule.
316 */
317 r = &pf_default_rule;
318
319 if (!r->max_states || r->states < r->max_states)
320 st = pool_get(&pf_state_pl, PR_NOWAIT);
321 if (st == NULL) {
322 pfi_maybe_destroy(kif);
323 return (ENOMEM);
324 }
325 bzero(st, sizeof(*st));
326
327 st->rule.ptr = r;
328 /* XXX get pointers to nat_rule and anchor */
329
330 /* fill in the rest of the state entry */
331 pf_state_host_ntoh(&sp->lan, &st->lan);
332 pf_state_host_ntoh(&sp->gwy, &st->gwy);
333 pf_state_host_ntoh(&sp->ext, &st->ext);
334
335 pf_state_peer_ntoh(&sp->src, &st->src);
336 pf_state_peer_ntoh(&sp->dst, &st->dst);
337
338 bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
339#ifdef __FreeBSD__
340 st->creation = ntohl(sp->creation) + time_second;
341 st->expire = ntohl(sp->expire) + time_second;
342#else
343 st->creation = ntohl(sp->creation) + time.tv_sec;
344 st->expire = ntohl(sp->expire) + time.tv_sec;
345#endif
346
347 st->af = sp->af;
348 st->proto = sp->proto;
349 st->direction = sp->direction;
350 st->log = sp->log;
351 st->timeout = sp->timeout;
352 st->allow_opts = sp->allow_opts;
353
354 bcopy(sp->id, &st->id, sizeof(st->id));
355 st->creatorid = sp->creatorid;
356 st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC;
357
358
359 if (pf_insert_state(kif, st)) {
360 pfi_maybe_destroy(kif);
361 pool_put(&pf_state_pl, st);
362 return (EINVAL);
363 }
364
365 return (0);
366}
367
368void
369#ifdef __FreeBSD__
370pfsync_input(struct mbuf *m, __unused int off)
371#else
372pfsync_input(struct mbuf *m, ...)
373#endif
374{
375 struct ip *ip = mtod(m, struct ip *);
376 struct pfsync_header *ph;
377#ifdef __FreeBSD__
378 struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
379#else
380 struct pfsync_softc *sc = &pfsyncif;
381#endif
382 struct pf_state *st, key;
383 struct pfsync_state *sp;
384 struct pfsync_state_upd *up;
385 struct pfsync_state_del *dp;
386 struct pfsync_state_clr *cp;
387 struct pfsync_state_upd_req *rup;
388 struct pfsync_state_bus *bus;
389 struct in_addr src;
390 struct mbuf *mp;
391 int iplen, action, error, i, s, count, offp;
392
393 pfsyncstats.pfsyncs_ipackets++;
394
395 /* verify that we have a sync interface configured */
396 if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
397 goto done;
398
399 /* verify that the packet came in on the right interface */
400 if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
401 pfsyncstats.pfsyncs_badif++;
402 goto done;
403 }
404
405 /* verify that the IP TTL is 255. */
406 if (ip->ip_ttl != PFSYNC_DFLTTL) {
407 pfsyncstats.pfsyncs_badttl++;
408 goto done;
409 }
410
411 iplen = ip->ip_hl << 2;
412
413 if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
414 pfsyncstats.pfsyncs_hdrops++;
415 goto done;
416 }
417
418 if (iplen + sizeof(*ph) > m->m_len) {
419 if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
420 pfsyncstats.pfsyncs_hdrops++;
421 goto done;
422 }
423 ip = mtod(m, struct ip *);
424 }
425 ph = (struct pfsync_header *)((char *)ip + iplen);
426
427 /* verify the version */
428 if (ph->version != PFSYNC_VERSION) {
429 pfsyncstats.pfsyncs_badver++;
430 goto done;
431 }
432
433 action = ph->action;
434 count = ph->count;
435
436 /* make sure it's a valid action code */
437 if (action >= PFSYNC_ACT_MAX) {
438 pfsyncstats.pfsyncs_badact++;
439 goto done;
440 }
441
442 /* Cheaper to grab this now than having to mess with mbufs later */
443 src = ip->ip_src;
444
445 switch (action) {
446 case PFSYNC_ACT_CLR: {
447 struct pfi_kif *kif;
448 u_int32_t creatorid;
449 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
450 sizeof(*cp), &offp)) == NULL) {
451 pfsyncstats.pfsyncs_badlen++;
452 return;
453 }
454 cp = (struct pfsync_state_clr *)(mp->m_data + offp);
455 creatorid = cp->creatorid;
456
457 s = splsoftnet();
458#ifdef __FreeBSD__
459 PF_LOCK();
460#endif
461 if (cp->ifname[0] == '\0') {
462 RB_FOREACH(st, pf_state_tree_id, &tree_id) {
463 if (st->creatorid == creatorid)
464 st->timeout = PFTM_PURGE;
465 }
466 } else {
467 kif = pfi_lookup_if(cp->ifname);
468 if (kif == NULL) {
469 if (pf_status.debug >= PF_DEBUG_MISC)
470 printf("pfsync_input: PFSYNC_ACT_CLR "
471 "bad interface: %s\n", cp->ifname);
472 splx(s);
473#ifdef __FreeBSD__
474 PF_UNLOCK();
475#endif
476 goto done;
477 }
478 RB_FOREACH(st, pf_state_tree_lan_ext,
479 &kif->pfik_lan_ext) {
480 if (st->creatorid == creatorid)
481 st->timeout = PFTM_PURGE;
482 }
483 }
484 pf_purge_expired_states();
485#ifdef __FreeBSD__
486 PF_UNLOCK();
487#endif
488 splx(s);
489
490 break;
491 }
492 case PFSYNC_ACT_INS:
493 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
494 count * sizeof(*sp), &offp)) == NULL) {
495 pfsyncstats.pfsyncs_badlen++;
496 return;
497 }
498
499 s = splsoftnet();
500#ifdef __FreeBSD__
501 PF_LOCK();
502#endif
503 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
504 i < count; i++, sp++) {
505 /* check for invalid values */
506 if (sp->timeout >= PFTM_MAX ||
507 sp->src.state > PF_TCPS_PROXY_DST ||
508 sp->dst.state > PF_TCPS_PROXY_DST ||
509 sp->direction > PF_OUT ||
510 (sp->af != AF_INET && sp->af != AF_INET6)) {
511 if (pf_status.debug >= PF_DEBUG_MISC)
512 printf("pfsync_insert: PFSYNC_ACT_INS: "
513 "invalid value\n");
514 pfsyncstats.pfsyncs_badstate++;
515 continue;
516 }
517
518 if ((error = pfsync_insert_net_state(sp))) {
519 if (error == ENOMEM) {
520 splx(s);
521#ifdef __FreeBSD__
522 PF_UNLOCK();
523#endif
524 goto done;
525 }
526 continue;
527 }
528 }
529#ifdef __FreeBSD__
530 PF_UNLOCK();
531#endif
532 splx(s);
533 break;
534 case PFSYNC_ACT_UPD:
535 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
536 count * sizeof(*sp), &offp)) == NULL) {
537 pfsyncstats.pfsyncs_badlen++;
538 return;
539 }
540
541 s = splsoftnet();
542#ifdef __FreeBSD__
543 PF_LOCK();
544#endif
545 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
546 i < count; i++, sp++) {
547 /* check for invalid values */
548 if (sp->timeout >= PFTM_MAX ||
549 sp->src.state > PF_TCPS_PROXY_DST ||
550 sp->dst.state > PF_TCPS_PROXY_DST) {
551 if (pf_status.debug >= PF_DEBUG_MISC)
552 printf("pfsync_insert: PFSYNC_ACT_UPD: "
553 "invalid value\n");
554 pfsyncstats.pfsyncs_badstate++;
555 continue;
556 }
557
558 bcopy(sp->id, &key.id, sizeof(key.id));
559 key.creatorid = sp->creatorid;
560
561 st = pf_find_state_byid(&key);
562 if (st == NULL) {
563 /* insert the update */
564 if (pfsync_insert_net_state(sp))
565 pfsyncstats.pfsyncs_badstate++;
566 continue;
567 }
568 pf_state_peer_ntoh(&sp->src, &st->src);
569 pf_state_peer_ntoh(&sp->dst, &st->dst);
570#ifdef __FreeBSD__
571 st->expire = ntohl(sp->expire) + time_second;
572#else
573 st->expire = ntohl(sp->expire) + time.tv_sec;
574#endif
575 st->timeout = sp->timeout;
576
577 }
578#ifdef __FreeBSD__
579 PF_UNLOCK();
580#endif
581 splx(s);
582 break;
583 /*
584 * It's not strictly necessary for us to support the "uncompressed"
585 * delete action, but it's relatively simple and maintains consistency.
586 */
587 case PFSYNC_ACT_DEL:
588 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
589 count * sizeof(*sp), &offp)) == NULL) {
590 pfsyncstats.pfsyncs_badlen++;
591 return;
592 }
593
594 s = splsoftnet();
595#ifdef __FreeBSD__
596 PF_LOCK();
597#endif
598 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
599 i < count; i++, sp++) {
600 bcopy(sp->id, &key.id, sizeof(key.id));
601 key.creatorid = sp->creatorid;
602
603 st = pf_find_state_byid(&key);
604 if (st == NULL) {
605 pfsyncstats.pfsyncs_badstate++;
606 continue;
607 }
608 /*
609 * XXX
610 * pf_purge_expired_states() is expensive,
611 * we really want to purge the state directly.
612 */
613 st->timeout = PFTM_PURGE;
614 st->sync_flags |= PFSTATE_FROMSYNC;
615 }
616 pf_purge_expired_states();
617#ifdef __FreeBSD__
618 PF_UNLOCK();
619#endif
620 splx(s);
621 break;
622 case PFSYNC_ACT_UPD_C: {
623 int update_requested = 0;
624
625 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
626 count * sizeof(*up), &offp)) == NULL) {
627 pfsyncstats.pfsyncs_badlen++;
628 return;
629 }
630
631 s = splsoftnet();
632#ifdef __FreeBSD__
633 PF_LOCK();
634#endif
635 for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
636 i < count; i++, up++) {
637 /* check for invalid values */
638 if (up->timeout >= PFTM_MAX ||
639 up->src.state > PF_TCPS_PROXY_DST ||
640 up->dst.state > PF_TCPS_PROXY_DST) {
641 if (pf_status.debug >= PF_DEBUG_MISC)
642 printf("pfsync_insert: "
643 "PFSYNC_ACT_UPD_C: "
644 "invalid value\n");
645 pfsyncstats.pfsyncs_badstate++;
646 continue;
647 }
648
649 bcopy(up->id, &key.id, sizeof(key.id));
650 key.creatorid = up->creatorid;
651
652 st = pf_find_state_byid(&key);
653 if (st == NULL) {
654 /* We don't have this state. Ask for it. */
655 pfsync_request_update(up, &src);
656 update_requested = 1;
657 pfsyncstats.pfsyncs_badstate++;
658 continue;
659 }
660 pf_state_peer_ntoh(&up->src, &st->src);
661 pf_state_peer_ntoh(&up->dst, &st->dst);
662#ifdef __FreeBSD__
663 st->expire = ntohl(up->expire) + time_second;
664#else
665 st->expire = ntohl(up->expire) + time.tv_sec;
666#endif
667 st->timeout = up->timeout;
668 }
669 if (update_requested)
670 pfsync_sendout(sc);
671#ifdef __FreeBSD__
672 PF_UNLOCK();
673#endif
674 splx(s);
675 break;
676 }
677 case PFSYNC_ACT_DEL_C:
678 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
679 count * sizeof(*dp), &offp)) == NULL) {
680 pfsyncstats.pfsyncs_badlen++;
681 return;
682 }
683
684 s = splsoftnet();
685#ifdef __FreeBSD__
686 PF_LOCK();
687#endif
688 for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
689 i < count; i++, dp++) {
690 bcopy(dp->id, &key.id, sizeof(key.id));
691 key.creatorid = dp->creatorid;
692
693 st = pf_find_state_byid(&key);
694 if (st == NULL) {
695 pfsyncstats.pfsyncs_badstate++;
696 continue;
697 }
698 /*
699 * XXX
700 * pf_purge_expired_states() is expensive,
701 * we really want to purge the state directly.
702 */
703 st->timeout = PFTM_PURGE;
704 st->sync_flags |= PFSTATE_FROMSYNC;
705 }
706 pf_purge_expired_states();
707#ifdef __FreeBSD__
708 PF_UNLOCK();
709#endif
710 splx(s);
711 break;
712 case PFSYNC_ACT_INS_F:
713 case PFSYNC_ACT_DEL_F:
714 /* not implemented */
715 break;
716 case PFSYNC_ACT_UREQ:
717 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
718 count * sizeof(*rup), &offp)) == NULL) {
719 pfsyncstats.pfsyncs_badlen++;
720 return;
721 }
722
723 s = splsoftnet();
724 /* XXX send existing. pfsync_pack_state should handle this. */
725#ifdef __FreeBSD__
726 PF_LOCK();
727#endif
728 if (sc->sc_mbuf != NULL)
729 pfsync_sendout(sc);
730 for (i = 0,
731 rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
732 i < count; i++, rup++) {
733 bcopy(rup->id, &key.id, sizeof(key.id));
734 key.creatorid = rup->creatorid;
735
736 if (key.id == 0 && key.creatorid == 0) {
737#ifdef __FreeBSD__
738 sc->sc_ureq_received = time_uptime;
739#else
740 sc->sc_ureq_received = mono_time.tv_sec;
741#endif
742 if (pf_status.debug >= PF_DEBUG_MISC)
743 printf("pfsync: received "
744 "bulk update request\n");
745 pfsync_send_bus(sc, PFSYNC_BUS_START);
746#ifdef __FreeBSD__
747 callout_reset(&sc->sc_bulk_tmo, 1 * hz,
748 pfsync_bulk_update,
749 LIST_FIRST(&pfsync_list));
750#else
751 timeout_add(&sc->sc_bulk_tmo, 1 * hz);
752#endif
753 } else {
754 st = pf_find_state_byid(&key);
755 if (st == NULL) {
756 pfsyncstats.pfsyncs_badstate++;
757 continue;
758 }
759 pfsync_pack_state(PFSYNC_ACT_UPD, st, 0);
760 }
761 }
762 if (sc->sc_mbuf != NULL)
763 pfsync_sendout(sc);
764#ifdef __FreeBSD__
765 PF_UNLOCK();
766#endif
767 splx(s);
768 break;
769 case PFSYNC_ACT_BUS:
770 /* If we're not waiting for a bulk update, who cares. */
771 if (sc->sc_ureq_sent == 0)
772 break;
773
774 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
775 sizeof(*bus), &offp)) == NULL) {
776 pfsyncstats.pfsyncs_badlen++;
777 return;
778 }
779 bus = (struct pfsync_state_bus *)(mp->m_data + offp);
780 switch (bus->status) {
781 case PFSYNC_BUS_START:
782#ifdef __FreeBSD__
783 callout_reset(&sc->sc_bulkfail_tmo,
784 pf_pool_limits[PF_LIMIT_STATES].limit /
785 (PFSYNC_BULKPACKETS * sc->sc_maxcount),
786 pfsync_bulkfail, LIST_FIRST(&pfsync_list));
787#else
788 timeout_add(&sc->sc_bulkfail_tmo,
789 pf_pool_limits[PF_LIMIT_STATES].limit /
790 (PFSYNC_BULKPACKETS * sc->sc_maxcount));
791#endif
792 if (pf_status.debug >= PF_DEBUG_MISC)
793 printf("pfsync: received bulk "
794 "update start\n");
795 break;
796 case PFSYNC_BUS_END:
797#ifdef __FreeBSD__
798 if (time_uptime - ntohl(bus->endtime) >=
799#else
800 if (mono_time.tv_sec - ntohl(bus->endtime) >=
801#endif
802 sc->sc_ureq_sent) {
803 /* that's it, we're happy */
804 sc->sc_ureq_sent = 0;
805 sc->sc_bulk_tries = 0;
806#ifdef __FreeBSD__
807 callout_stop(&sc->sc_bulkfail_tmo);
808#else
809 timeout_del(&sc->sc_bulkfail_tmo);
810#endif
811 pfsync_sync_ok = 1;
812 if (pf_status.debug >= PF_DEBUG_MISC)
813 printf("pfsync: received valid "
814 "bulk update end\n");
815 } else {
816 if (pf_status.debug >= PF_DEBUG_MISC)
817 printf("pfsync: received invalid "
818 "bulk update end: bad timestamp\n");
819 }
820 break;
821 }
822 break;
823 }
824
825done:
826 if (m)
827 m_freem(m);
828}
829
830int
831pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
832 struct rtentry *rt)
833{
834 m_freem(m);
835 return (0);
836}
837
838/* ARGSUSED */
839int
840pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
841{
842#ifndef __FreeBSD__
843 struct proc *p = curproc;
844#endif
845 struct pfsync_softc *sc = ifp->if_softc;
846 struct ifreq *ifr = (struct ifreq *)data;
847 struct ip_moptions *imo = &sc->sc_imo;
848 struct pfsyncreq pfsyncr;
849 struct ifnet *sifp;
850 int s, error;
851
852 switch (cmd) {
853 case SIOCSIFADDR:
854 case SIOCAIFADDR:
855 case SIOCSIFDSTADDR:
856 case SIOCSIFFLAGS:
857 if (ifp->if_flags & IFF_UP)
858 ifp->if_flags |= IFF_RUNNING;
859 else
860 ifp->if_flags &= ~IFF_RUNNING;
861 break;
862 case SIOCSIFMTU:
863 if (ifr->ifr_mtu < PFSYNC_MINMTU)
864 return (EINVAL);
865 if (ifr->ifr_mtu > MCLBYTES)
866 ifr->ifr_mtu = MCLBYTES;
867 s = splnet();
868#ifdef __FreeBSD__
869 PF_LOCK();
870#endif
871 if (ifr->ifr_mtu < ifp->if_mtu) {
872 pfsync_sendout(sc);
873 }
874 pfsync_setmtu(sc, ifr->ifr_mtu);
875#ifdef __FreeBSD__
876 PF_UNLOCK();
877#endif
878 splx(s);
879 break;
880 case SIOCGETPFSYNC:
881#ifdef __FreeBSD__
882 /* XXX: read unlocked */
883#endif
884 bzero(&pfsyncr, sizeof(pfsyncr));
885 if (sc->sc_sync_ifp)
886 strlcpy(pfsyncr.pfsyncr_syncif,
887 sc->sc_sync_ifp->if_xname, IFNAMSIZ);
888 pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
889 if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
890 return (error);
891 break;
892 case SIOCSETPFSYNC:
893#ifdef __FreeBSD__
894 if ((error = suser(curthread)) != 0)
895#else
896 if ((error = suser(p, p->p_acflag)) != 0)
897#endif
898 return (error);
899 if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
900 return (error);
901
902 if (pfsyncr.pfsyncr_maxupdates > 255)
903 return (EINVAL);
904#ifdef __FreeBSD__
905 PF_LOCK();
906#endif
907 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
908
909 if (pfsyncr.pfsyncr_syncif[0] == 0) {
910 sc->sc_sync_ifp = NULL;
911 if (sc->sc_mbuf_net != NULL) {
912 /* Don't keep stale pfsync packets around. */
913 s = splnet();
914 m_freem(sc->sc_mbuf_net);
915 sc->sc_mbuf_net = NULL;
916 sc->sc_statep_net.s = NULL;
917 splx(s);
918 }
919#ifdef __FreeBSD__
920 PF_UNLOCK();
921#endif
922 break;
923 }
924 if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL) {
925#ifdef __FreeBSD__
926 PF_UNLOCK();
927#endif
928 return (EINVAL);
929 }
930 else if (sifp == sc->sc_sync_ifp) {
931#ifdef __FreeBSD__
932 PF_UNLOCK();
933#endif
934 break;
935 }
936
937 s = splnet();
938 if (sifp->if_mtu < sc->sc_if.if_mtu ||
939 (sc->sc_sync_ifp != NULL &&
940 sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
941 sifp->if_mtu < MCLBYTES - sizeof(struct ip))
942 pfsync_sendout(sc);
943 sc->sc_sync_ifp = sifp;
944
945 pfsync_setmtu(sc, sc->sc_if.if_mtu);
946
947 if (imo->imo_num_memberships > 0) {
948 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
949 imo->imo_multicast_ifp = NULL;
950 }
951
952 if (sc->sc_sync_ifp) {
953 struct in_addr addr;
954
955#ifdef __FreeBSD__
956 PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */
957 addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
958#else
959 addr.s_addr = INADDR_PFSYNC_GROUP;
960#endif
961 if ((imo->imo_membership[0] =
962 in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
963 splx(s);
964 return (ENOBUFS);
965 }
966 imo->imo_num_memberships++;
967 imo->imo_multicast_ifp = sc->sc_sync_ifp;
968 imo->imo_multicast_ttl = PFSYNC_DFLTTL;
969 imo->imo_multicast_loop = 0;
970
971 /* Request a full state table update. */
972#ifdef __FreeBSD__
973 PF_LOCK();
974 sc->sc_ureq_sent = time_uptime;
975#else
976 sc->sc_ureq_sent = mono_time.tv_sec;
977#endif
978 pfsync_sync_ok = 0;
979 if (pf_status.debug >= PF_DEBUG_MISC)
980 printf("pfsync: requesting bulk update\n");
981#ifdef __FreeBSD__
982 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
983 pfsync_bulkfail, LIST_FIRST(&pfsync_list));
984#else
985 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
986#endif
987 pfsync_request_update(NULL, NULL);
988 pfsync_sendout(sc);
989 }
990#ifdef __FreeBSD__
991 PF_UNLOCK();
992#endif
993 splx(s);
994
995 break;
996
997 default:
998 return (ENOTTY);
999 }
1000
1001 return (0);
1002}
1003
1004void
1005pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
1006{
1007 int mtu;
1008
1009 if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
1010 mtu = sc->sc_sync_ifp->if_mtu;
1011 else
1012 mtu = mtu_req;
1013
1014 sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
1015 sizeof(struct pfsync_state);
1016 if (sc->sc_maxcount > 254)
1017 sc->sc_maxcount = 254;
1018 sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
1019 sc->sc_maxcount * sizeof(struct pfsync_state);
1020}
1021
1022struct mbuf *
1023pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
1024{
1025 struct pfsync_header *h;
1026 struct mbuf *m;
1027 int len;
1028
1029#ifdef __FreeBSD__
1030 PF_ASSERT(MA_OWNED);
1031#endif
1032 MGETHDR(m, M_DONTWAIT, MT_DATA);
1033 if (m == NULL) {
1034 sc->sc_if.if_oerrors++;
1035 return (NULL);
1036 }
1037
1038 switch (action) {
1039 case PFSYNC_ACT_CLR:
1040 len = sizeof(struct pfsync_header) +
1041 sizeof(struct pfsync_state_clr);
1042 break;
1043 case PFSYNC_ACT_UPD_C:
1044 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
1045 sizeof(struct pfsync_header);
1046 break;
1047 case PFSYNC_ACT_DEL_C:
1048 len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
1049 sizeof(struct pfsync_header);
1050 break;
1051 case PFSYNC_ACT_UREQ:
1052 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
1053 sizeof(struct pfsync_header);
1054 break;
1055 case PFSYNC_ACT_BUS:
1056 len = sizeof(struct pfsync_header) +
1057 sizeof(struct pfsync_state_bus);
1058 break;
1059 default:
1060 len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
1061 sizeof(struct pfsync_header);
1062 break;
1063 }
1064
1065 if (len > MHLEN) {
1066 MCLGET(m, M_DONTWAIT);
1067 if ((m->m_flags & M_EXT) == 0) {
1068 m_free(m);
1069 sc->sc_if.if_oerrors++;
1070 return (NULL);
1071 }
1072 m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
1073 } else
1074 MH_ALIGN(m, len);
1075
1076 m->m_pkthdr.rcvif = NULL;
1077 m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
1078 h = mtod(m, struct pfsync_header *);
1079 h->version = PFSYNC_VERSION;
1080 h->af = 0;
1081 h->count = 0;
1082 h->action = action;
1083
1084 *sp = (void *)((char *)h + PFSYNC_HDRLEN);
1085#ifdef __FreeBSD__
1086 callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1087 LIST_FIRST(&pfsync_list));
1088#else
1089 timeout_add(&sc->sc_tmo, hz);
1090#endif
1091 return (m);
1092}
1093
1094int
1095pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
1096{
1097#ifdef __FreeBSD__
1098 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1099#else
1100 struct ifnet *ifp = &pfsyncif.sc_if;
1101#endif
1102 struct pfsync_softc *sc = ifp->if_softc;
1103 struct pfsync_header *h, *h_net;
1104 struct pfsync_state *sp = NULL;
1105 struct pfsync_state_upd *up = NULL;
1106 struct pfsync_state_del *dp = NULL;
1107 struct pf_rule *r;
1108 u_long secs;
1109 int s, ret = 0;
1110 u_int8_t i = 255, newaction = 0;
1111
1112#ifdef __FreeBSD__
1113 PF_ASSERT(MA_OWNED);
1114#endif
1115 /*
1116 * If a packet falls in the forest and there's nobody around to
1117 * hear, does it make a sound?
1118 */
1119 if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL) {
1120 /* Don't leave any stale pfsync packets hanging around. */
1121 if (sc->sc_mbuf != NULL) {
1122 m_freem(sc->sc_mbuf);
1123 sc->sc_mbuf = NULL;
1124 sc->sc_statep.s = NULL;
1125 }
1126 return (0);
1127 }
1128
1129 if (action >= PFSYNC_ACT_MAX)
1130 return (EINVAL);
1131
1132 s = splnet();
1133 if (sc->sc_mbuf == NULL) {
1134 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1135 (void *)&sc->sc_statep.s)) == NULL) {
1136 splx(s);
1137 return (ENOMEM);
1138 }
1139 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1140 } else {
1141 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1142 if (h->action != action) {
1143 pfsync_sendout(sc);
1144 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1145 (void *)&sc->sc_statep.s)) == NULL) {
1146 splx(s);
1147 return (ENOMEM);
1148 }
1149 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1150 } else {
1151 /*
1152 * If it's an update, look in the packet to see if
1153 * we already have an update for the state.
1154 */
1155 if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
1156 struct pfsync_state *usp =
1157 (void *)((char *)h + PFSYNC_HDRLEN);
1158
1159 for (i = 0; i < h->count; i++) {
1160 if (!memcmp(usp->id, &st->id,
1161 PFSYNC_ID_LEN) &&
1162 usp->creatorid == st->creatorid) {
1163 sp = usp;
1164 sp->updates++;
1165 break;
1166 }
1167 usp++;
1168 }
1169 }
1170 }
1171 }
1172
1173#ifdef __FreeBSD__
1174 secs = time_second;
1175
1176 st->pfsync_time = time_uptime;
1177#else
1178 secs = time.tv_sec;
1179
1180 st->pfsync_time = mono_time.tv_sec;
1181#endif
1182 TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
1183 TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
1184
1185 if (sp == NULL) {
1186 /* not a "duplicate" update */
1187 i = 255;
1188 sp = sc->sc_statep.s++;
1189 sc->sc_mbuf->m_pkthdr.len =
1190 sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
1191 h->count++;
1192 bzero(sp, sizeof(*sp));
1193
1194 bcopy(&st->id, sp->id, sizeof(sp->id));
1195 sp->creatorid = st->creatorid;
1196
1197 strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
1198 pf_state_host_hton(&st->lan, &sp->lan);
1199 pf_state_host_hton(&st->gwy, &sp->gwy);
1200 pf_state_host_hton(&st->ext, &sp->ext);
1201
1202 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
1203
1204 sp->creation = htonl(secs - st->creation);
1205 sp->packets[0] = htonl(st->packets[0]);
1206 sp->packets[1] = htonl(st->packets[1]);
1207 sp->bytes[0] = htonl(st->bytes[0]);
1208 sp->bytes[1] = htonl(st->bytes[1]);
1209 if ((r = st->rule.ptr) == NULL)
1210 sp->rule = htonl(-1);
1211 else
1212 sp->rule = htonl(r->nr);
1213 if ((r = st->anchor.ptr) == NULL)
1214 sp->anchor = htonl(-1);
1215 else
1216 sp->anchor = htonl(r->nr);
1217 sp->af = st->af;
1218 sp->proto = st->proto;
1219 sp->direction = st->direction;
1220 sp->log = st->log;
1221 sp->allow_opts = st->allow_opts;
1222 sp->timeout = st->timeout;
1223
1224 sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC;
1225 }
1226
1227 pf_state_peer_hton(&st->src, &sp->src);
1228 pf_state_peer_hton(&st->dst, &sp->dst);
1229
1230 if (st->expire <= secs)
1231 sp->expire = htonl(0);
1232 else
1233 sp->expire = htonl(st->expire - secs);
1234
1235 /* do we need to build "compressed" actions for network transfer? */
1236 if (sc->sc_sync_ifp && compress) {
1237 switch (action) {
1238 case PFSYNC_ACT_UPD:
1239 newaction = PFSYNC_ACT_UPD_C;
1240 break;
1241 case PFSYNC_ACT_DEL:
1242 newaction = PFSYNC_ACT_DEL_C;
1243 break;
1244 default:
1245 /* by default we just send the uncompressed states */
1246 break;
1247 }
1248 }
1249
1250 if (newaction) {
1251 if (sc->sc_mbuf_net == NULL) {
1252 if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
1253 (void *)&sc->sc_statep_net.s)) == NULL) {
1254 splx(s);
1255 return (ENOMEM);
1256 }
1257 }
1258 h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
1259
1260 switch (newaction) {
1261 case PFSYNC_ACT_UPD_C:
1262 if (i != 255) {
1263 up = (void *)((char *)h_net +
1264 PFSYNC_HDRLEN + (i * sizeof(*up)));
1265 up->updates++;
1266 } else {
1267 h_net->count++;
1268 sc->sc_mbuf_net->m_pkthdr.len =
1269 sc->sc_mbuf_net->m_len += sizeof(*up);
1270 up = sc->sc_statep_net.u++;
1271
1272 bzero(up, sizeof(*up));
1273 bcopy(&st->id, up->id, sizeof(up->id));
1274 up->creatorid = st->creatorid;
1275 }
1276 up->timeout = st->timeout;
1277 up->expire = sp->expire;
1278 up->src = sp->src;
1279 up->dst = sp->dst;
1280 break;
1281 case PFSYNC_ACT_DEL_C:
1282 sc->sc_mbuf_net->m_pkthdr.len =
1283 sc->sc_mbuf_net->m_len += sizeof(*dp);
1284 dp = sc->sc_statep_net.d++;
1285 h_net->count++;
1286
1287 bzero(dp, sizeof(*dp));
1288 bcopy(&st->id, dp->id, sizeof(dp->id));
1289 dp->creatorid = st->creatorid;
1290 break;
1291 }
1292 }
1293
1294 if (h->count == sc->sc_maxcount ||
1295 (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1296 ret = pfsync_sendout(sc);
1297
1298 splx(s);
1299 return (ret);
1300}
1301
1302/* This must be called in splnet() */
1303int
1304pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1305{
1306#ifdef __FreeBSD__
1307 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1308#else
1309 struct ifnet *ifp = &pfsyncif.sc_if;
1310#endif
1311 struct pfsync_header *h;
1312 struct pfsync_softc *sc = ifp->if_softc;
1313 struct pfsync_state_upd_req *rup;
1314 int s, ret = 0; /* make the compiler happy */
1315
1316#ifdef __FreeBSD__
1317 PF_ASSERT(MA_OWNED);
1318#endif
1319 if (sc->sc_mbuf == NULL) {
1320 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1321 (void *)&sc->sc_statep.s)) == NULL) {
1322 splx(s);
1323 return (ENOMEM);
1324 }
1325 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1326 } else {
1327 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1328 if (h->action != PFSYNC_ACT_UREQ) {
1329 pfsync_sendout(sc);
1330 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1331 (void *)&sc->sc_statep.s)) == NULL) {
1332 splx(s);
1333 return (ENOMEM);
1334 }
1335 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1336 }
1337 }
1338
1339 if (src != NULL)
1340 sc->sc_sendaddr = *src;
1341 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1342 h->count++;
1343 rup = sc->sc_statep.r++;
1344 bzero(rup, sizeof(*rup));
1345 if (up != NULL) {
1346 bcopy(up->id, rup->id, sizeof(rup->id));
1347 rup->creatorid = up->creatorid;
1348 }
1349
1350 if (h->count == sc->sc_maxcount)
1351 ret = pfsync_sendout(sc);
1352
1353 return (ret);
1354}
1355
1356int
1357pfsync_clear_states(u_int32_t creatorid, char *ifname)
1358{
1359#ifdef __FreeBSD__
1360 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1361#else
1362 struct ifnet *ifp = &pfsyncif.sc_if;
1363#endif
1364 struct pfsync_softc *sc = ifp->if_softc;
1365 struct pfsync_state_clr *cp;
1366 int s, ret;
1367
1368 s = splnet();
1369#ifdef __FreeBSD__
1370 PF_ASSERT(MA_OWNED);
1371#endif
1372 if (sc->sc_mbuf != NULL)
1373 pfsync_sendout(sc);
1374 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1375 (void *)&sc->sc_statep.c)) == NULL) {
1376 splx(s);
1377 return (ENOMEM);
1378 }
1379 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1380 cp = sc->sc_statep.c;
1381 cp->creatorid = creatorid;
1382 if (ifname != NULL)
1383 strlcpy(cp->ifname, ifname, IFNAMSIZ);
1384
1385 ret = (pfsync_sendout(sc));
1386 splx(s);
1387 return (ret);
1388}
1389
1390void
1391pfsync_timeout(void *v)
1392{
1393 struct pfsync_softc *sc = v;
1394 int s;
1395
1396 s = splnet();
1397#ifdef __FreeBSD__
1398 PF_LOCK();
1399#endif
1400 pfsync_sendout(sc);
1401#ifdef __FreeBSD__
1402 PF_UNLOCK();
1403#endif
1404 splx(s);
1405}
1406
1407void
1408pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1409{
1410 struct pfsync_state_bus *bus;
1411
1412#ifdef __FreeBSD__
1413 PF_ASSERT(MA_OWNED);
1414#endif
1415 if (sc->sc_mbuf != NULL)
1416 pfsync_sendout(sc);
1417
1418 if (pfsync_sync_ok &&
1419 (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1420 (void *)&sc->sc_statep.b)) != NULL) {
1421 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1422 bus = sc->sc_statep.b;
1423 bus->creatorid = pf_status.hostid;
1424 bus->status = status;
1425#ifdef __FreeBSD__
1426 bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
1427#else
1428 bus->endtime = htonl(mono_time.tv_sec - sc->sc_ureq_received);
1429#endif
1430 pfsync_sendout(sc);
1431 }
1432}
1433
1434void
1435pfsync_bulk_update(void *v)
1436{
1437 struct pfsync_softc *sc = v;
1438 int s, i = 0;
1439 struct pf_state *state;
1440
1441#ifdef __FreeBSD__
1442 PF_LOCK();
1443#endif
1444 s = splnet();
1445 if (sc->sc_mbuf != NULL)
1446 pfsync_sendout(sc);
1447
1448 /*
1449 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1450 * been sent since the latest request was made.
1451 */
1452 while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1453 ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1454 if (state->pfsync_time > sc->sc_ureq_received) {
1455 /* we're done */
1456 pfsync_send_bus(sc, PFSYNC_BUS_END);
1457 sc->sc_ureq_received = 0;
1458#ifdef __FreeBSD__
1459 callout_stop(&sc->sc_bulk_tmo);
1460#else
1461 timeout_del(&sc->sc_bulk_tmo);
1462#endif
1463 if (pf_status.debug >= PF_DEBUG_MISC)
1464 printf("pfsync: bulk update complete\n");
1465 break;
1466 } else {
1467 /* send an update and move to end of list */
1468 if (!state->sync_flags)
1469 pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1470#ifdef __FreeBSD__
1471 state->pfsync_time = time_uptime;
1472#else
1473 state->pfsync_time = mono_time.tv_sec;
1474#endif
1475 TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1476 TAILQ_INSERT_TAIL(&state_updates, state,
1477 u.s.entry_updates);
1478
1479 /* look again for more in a bit */
1480#ifdef __FreeBSD__
1481 callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1482 LIST_FIRST(&pfsync_list));
1483#else
1484 timeout_add(&sc->sc_bulk_tmo, 1);
1485#endif
1486 }
1487 }
1488 if (sc->sc_mbuf != NULL)
1489 pfsync_sendout(sc);
1490 splx(s);
1491#ifdef __FreeBSD__
1492 PF_UNLOCK();
1493#endif
1494}
1495
1496void
1497pfsync_bulkfail(void *v)
1498{
1499 struct pfsync_softc *sc = v;
1500
1501#ifdef __FreeBSD__
1502 PF_LOCK();
1503#endif
1504 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1505 /* Try again in a bit */
1506#ifdef __FreeBSD__
1507 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1508 LIST_FIRST(&pfsync_list));
1509#else
1510 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1511#endif
1512 pfsync_request_update(NULL, NULL);
1513 pfsync_sendout(sc);
1514 } else {
1515 /* Pretend like the transfer was ok */
1516 sc->sc_ureq_sent = 0;
1517 sc->sc_bulk_tries = 0;
1518 pfsync_sync_ok = 1;
1519 if (pf_status.debug >= PF_DEBUG_MISC)
1520 printf("pfsync: failed to receive "
1521 "bulk update status\n");
1522#ifdef __FreeBSD__
1523 callout_stop(&sc->sc_bulkfail_tmo);
1524#else
1525 timeout_del(&sc->sc_bulkfail_tmo);
1526#endif
1527 }
1528#ifdef __FreeBSD__
1529 PF_UNLOCK();
1530#endif
1531}
1532
1533int
1534pfsync_sendout(sc)
1535 struct pfsync_softc *sc;
1536{
1537 struct ifnet *ifp = &sc->sc_if;
1538 struct mbuf *m;
1539
1540#ifdef __FreeBSD__
1541 PF_ASSERT(MA_OWNED);
1542 callout_stop(&sc->sc_tmo);
1543#else
1544 timeout_del(&sc->sc_tmo);
1545#endif
1546
1547 if (sc->sc_mbuf == NULL)
1548 return (0);
1549 m = sc->sc_mbuf;
1550 sc->sc_mbuf = NULL;
1551 sc->sc_statep.s = NULL;
1552
1553#ifdef __FreeBSD__
1554 KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1555#endif
1556#if NBPFILTER > 0
1557 if (ifp->if_bpf)
1558 bpf_mtap(ifp->if_bpf, m);
1559#endif
1560
1561 if (sc->sc_mbuf_net) {
1562 m_freem(m);
1563 m = sc->sc_mbuf_net;
1564 sc->sc_mbuf_net = NULL;
1565 sc->sc_statep_net.s = NULL;
1566 }
1567
1568 if (sc->sc_sync_ifp) {
1569 struct ip *ip;
1570 struct ifaddr *ifa;
1571 struct sockaddr sa;
1572
1573 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
1574 if (m == NULL) {
1575 pfsyncstats.pfsyncs_onomem++;
1576 return (0);
1577 }
1578 ip = mtod(m, struct ip *);
1579 ip->ip_v = IPVERSION;
1580 ip->ip_hl = sizeof(*ip) >> 2;
1581 ip->ip_tos = IPTOS_LOWDELAY;
1582#ifdef __FreeBSD__
1583 ip->ip_len = m->m_pkthdr.len;
1584#else
1585 ip->ip_len = htons(m->m_pkthdr.len);
1586#endif
1587 ip->ip_id = htons(ip_randomid());
1588#ifdef __FreeBSD__
1589 ip->ip_off = IP_DF;
1590#else
1591 ip->ip_off = htons(IP_DF);
1592#endif
1593 ip->ip_ttl = PFSYNC_DFLTTL;
1594 ip->ip_p = IPPROTO_PFSYNC;
1595 ip->ip_sum = 0;
1596
1597 bzero(&sa, sizeof(sa));
1598 sa.sa_family = AF_INET;
1599 ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp);
1600 if (ifa == NULL)
1601 return (0);
1602 ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
1603
1604#ifdef __FreeBSD__
1605 if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1606#else
1607 if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
1608#endif
1609 m->m_flags |= M_MCAST;
1610 ip->ip_dst = sc->sc_sendaddr;
1611#ifdef __FreeBSD__
1612 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1613#else
1614 sc->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
1615#endif
1616
1617 pfsyncstats.pfsyncs_opackets++;
1618
1619#ifdef __FreeBSD__
1620 PF_UNLOCK();
1621#endif
1622 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1623 pfsyncstats.pfsyncs_oerrors++;
1624
1625#ifdef __FreeBSD__
1626 PF_LOCK();
1627#endif
1628 } else
1629 m_freem(m);
1630
1631 return (0);
1632}
1633
1634
1635#ifdef __FreeBSD__
1636static int
1637pfsync_modevent(module_t mod, int type, void *data)
1638{
1639 int error = 0;
1640
1641 switch (type) {
1642 case MOD_LOAD:
1643 LIST_INIT(&pfsync_list);
1644 if_clone_attach(&pfsync_cloner);
1645 break;
1646
1647 case MOD_UNLOAD:
1648 if_clone_detach(&pfsync_cloner);
1649 while (!LIST_EMPTY(&pfsync_list))
1650 pfsync_clone_destroy(
1651 &LIST_FIRST(&pfsync_list)->sc_if);
1652 break;
1653
1654 default:
1655 error = EINVAL;
1656 break;
1657 }
1658
1659 return error;
1660}
1661
1662static moduledata_t pfsync_mod = {
1663 "pfsync",
1664 pfsync_modevent,
1665 0
1666};
1667
1668#define PFSYNC_MODVER 1
1669
1670DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
1671MODULE_VERSION(pfsync, PFSYNC_MODVER);
1672#endif /* __FreeBSD__ */