4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * STREAMS Packet Filter Module
29 * This module applies a filter to messages arriving on its read
30 * queue, passing on messages that the filter accepts adn discarding
31 * the others. It supports ioctls for setting the filter.
33 * On the write side, the module simply passes everything through
36 * Based on SunOS 4.x version. This version has minor changes:
37 * - general SVR4 porting stuff
38 * - change name and prefixes from "nit" buffer to streams buffer
39 * - multithreading assumes configured as D_MTQPAIR
42 #include <sys/types.h>
43 #include <sys/sysmacros.h>
44 #include <sys/errno.h>
45 #include <sys/debug.h>
47 #include <sys/stropts.h>
48 #include <sys/stream.h>
51 #include <sys/sunddi.h>
53 #include <sys/strsun.h>
54 #include <sys/pfmod.h>
55 #include <sys/modctl.h>
58 * Expanded version of the Packetfilt structure that includes
59 * some additional fields that aid filter execution efficiency.
62 struct Pf_ext_packetfilt pf
;
63 #define pf_Priority pf.Pf_Priority
64 #define pf_FilterLen pf.Pf_FilterLen
65 #define pf_Filter pf.Pf_Filter
66 /* pointer to word immediately past end of filter */
67 ushort_t
*pf_FilterEnd
;
68 /* length in bytes of packet prefix the filter examines */
73 * (Internal) packet descriptor for FilterPacket
76 ushort_t
*pd_hdr
; /* header starting address */
77 uint_t pd_hdrlen
; /* header length in shorts */
78 ushort_t
*pd_body
; /* body starting address */
79 uint_t pd_bodylen
; /* body length in shorts */
84 * Function prototypes.
86 static int pfopen(queue_t
*, dev_t
*, int, int, cred_t
*);
87 static int pfclose(queue_t
*, int, cred_t
*);
88 static void pfioctl(queue_t
*wq
, mblk_t
*mp
);
89 static int FilterPacket(struct packdesc
*, struct epacketfilt
*);
90 static int pfwput(queue_t
*, mblk_t
*);
91 static int pfrput(queue_t
*, mblk_t
*);
93 static struct module_info pf_minfo
= {
95 "pfmod", /* mi_idname */
97 INFPSZ
, /* mi_maxpsz */
102 static struct qinit pf_rinit
= {
103 pfrput
, /* qi_putp */
105 pfopen
, /* qi_qopen */
106 pfclose
, /* qi_qclose */
107 NULL
, /* qi_qadmin */
108 &pf_minfo
, /* qi_minfo */
112 static struct qinit pf_winit
= {
113 pfwput
, /* qi_putp */
116 NULL
, /* qi_qclose */
117 NULL
, /* qi_qadmin */
118 &pf_minfo
, /* qi_minfo */
122 static struct streamtab pf_info
= {
123 &pf_rinit
, /* st_rdinit */
124 &pf_winit
, /* st_wrinit */
125 NULL
, /* st_muxrinit */
126 NULL
/* st_muxwinit */
129 static struct fmodsw fsw
= {
135 static struct modlstrmod modlstrmod
= {
136 &mod_strmodops
, "streams packet filter module", &fsw
139 static struct modlinkage modlinkage
= {
140 MODREV_1
, &modlstrmod
, NULL
146 return (mod_install(&modlinkage
));
152 return (mod_remove(&modlinkage
));
156 _info(struct modinfo
*modinfop
)
158 return (mod_info(&modlinkage
, modinfop
));
163 pfopen(queue_t
*rq
, dev_t
*dev
, int oflag
, int sflag
, cred_t
*crp
)
165 struct epacketfilt
*pfp
;
169 if (sflag
!= MODOPEN
)
176 * Allocate and initialize per-Stream structure.
178 pfp
= kmem_alloc(sizeof (struct epacketfilt
), KM_SLEEP
);
179 rq
->q_ptr
= WR(rq
)->q_ptr
= (char *)pfp
;
188 pfclose(queue_t
*rq
, int flags __unused
, cred_t
*credp __unused
)
190 struct epacketfilt
*pfp
= (struct epacketfilt
*)rq
->q_ptr
;
196 kmem_free(pfp
, sizeof (struct epacketfilt
));
197 rq
->q_ptr
= WR(rq
)->q_ptr
= NULL
;
203 * Write-side put procedure. Its main task is to detect ioctls.
204 * Other message types are passed on through.
207 pfwput(queue_t
*wq
, mblk_t
*mp
)
209 switch (mp
->b_datap
->db_type
) {
222 * Read-side put procedure. It's responsible for applying the
223 * packet filter and passing upstream message on or discarding it
224 * depending upon the results.
226 * Upstream messages can start with zero or more M_PROTO mblks
227 * which are skipped over before executing the packet filter
228 * on any remaining M_DATA mblks.
231 pfrput(queue_t
*rq
, mblk_t
*mp
)
233 struct epacketfilt
*pfp
= (struct epacketfilt
*)rq
->q_ptr
;
240 switch (DB_TYPE(mp
)) {
244 * Skip over protocol information and find the start
245 * of the message body, saving the overall message
248 for (mpp
= mp
; mp
&& (DB_TYPE(mp
) == M_PROTO
); mp
= mp
->b_cont
)
252 * Null body (exclusive of M_PROTO blocks) ==> accept.
253 * Note that a null body is not the same as an empty body.
261 * Pull the packet up to the length required by
262 * the filter. Note that doing so destroys sharing
263 * relationships, which is unfortunate, since the
264 * results of pulling up here are likely to be useful
265 * for shared messages applied to a filter on a sibling
268 * Most packet sources will provide the packet in two
269 * logical pieces: an initial header in a single mblk,
270 * and a body in a sequence of mblks hooked to the
271 * header. We're prepared to deal with variant forms,
272 * but in any case, the pullup applies only to the body
276 need
= pfp
->pf_PByteLen
;
277 if (mbp
&& (MBLKL(mbp
) < need
)) {
278 int len
= msgdsize(mbp
);
280 /* XXX discard silently on pullupmsg failure */
281 if (pullupmsg(mbp
, MIN(need
, len
)) == 0) {
288 * Misalignment (not on short boundary) ==> reject.
290 if (((uintptr_t)mp
->b_rptr
& (sizeof (ushort_t
) - 1)) ||
292 ((uintptr_t)mbp
->b_rptr
& (sizeof (ushort_t
) - 1)))) {
298 * These assignments are distasteful, but necessary,
299 * since the packet filter wants to work in terms of
300 * shorts. Odd bytes at the end of header or data can't
301 * participate in the filtering operation.
303 pd
.pd_hdr
= (ushort_t
*)mp
->b_rptr
;
304 pd
.pd_hdrlen
= (mp
->b_wptr
- mp
->b_rptr
) / sizeof (ushort_t
);
306 pd
.pd_body
= (ushort_t
*)mbp
->b_rptr
;
307 pd
.pd_bodylen
= (mbp
->b_wptr
- mbp
->b_rptr
) /
317 if (FilterPacket(&pd
, pfp
))
332 * Handle write-side M_IOCTL messages.
335 pfioctl(queue_t
*wq
, mblk_t
*mp
)
337 struct epacketfilt
*pfp
= (struct epacketfilt
*)wq
->q_ptr
;
338 struct Pf_ext_packetfilt
*upfp
;
339 struct packetfilt
*opfp
;
344 struct iocblk
*iocp
= (struct iocblk
*)mp
->b_rptr
;
347 switch (iocp
->ioc_cmd
) {
350 * Verify argument length. Since the size of packet filter
351 * got increased (ENMAXFILTERS was bumped up to 2047), to
352 * maintain backwards binary compatibility, we need to
353 * check for both possible sizes.
355 switch (iocp
->ioc_count
) {
356 case sizeof (struct Pf_ext_packetfilt
):
357 error
= miocpullup(mp
,
358 sizeof (struct Pf_ext_packetfilt
));
360 miocnak(wq
, mp
, 0, error
);
363 upfp
= (struct Pf_ext_packetfilt
*)mp
->b_cont
->b_rptr
;
364 if (upfp
->Pf_FilterLen
> PF_MAXFILTERS
) {
365 miocnak(wq
, mp
, 0, EINVAL
);
369 bcopy(upfp
, pfp
, sizeof (struct Pf_ext_packetfilt
));
370 pfp
->pf_FilterEnd
= &pfp
->pf_Filter
[pfp
->pf_FilterLen
];
373 case sizeof (struct packetfilt
):
374 error
= miocpullup(mp
, sizeof (struct packetfilt
));
376 miocnak(wq
, mp
, 0, error
);
379 opfp
= (struct packetfilt
*)mp
->b_cont
->b_rptr
;
380 /* this strange comparison keeps gcc from complaining */
381 if (opfp
->Pf_FilterLen
- 1 >= ENMAXFILTERS
) {
382 miocnak(wq
, mp
, 0, EINVAL
);
386 pfp
->pf
.Pf_Priority
= opfp
->Pf_Priority
;
387 pfp
->pf
.Pf_FilterLen
= (unsigned int)opfp
->Pf_FilterLen
;
389 bcopy(opfp
->Pf_Filter
, pfp
->pf
.Pf_Filter
,
390 sizeof (opfp
->Pf_Filter
));
391 pfp
->pf_FilterEnd
= &pfp
->pf_Filter
[pfp
->pf_FilterLen
];
395 miocnak(wq
, mp
, 0, EINVAL
);
400 * Find and record maximum byte offset that the
401 * filter users. We use this when executing the
402 * filter to determine how much of the packet
403 * body to pull up. This code depends on the
406 for (fwp
= pfp
->pf_Filter
; fwp
< pfp
->pf_FilterEnd
; fwp
++) {
407 arg
= *fwp
& ((1 << ENF_NBPA
) - 1);
410 if ((arg
-= ENF_PUSHWORD
) > maxoff
)
414 case ENF_LOAD_OFFSET
:
415 /* Point to the offset */
417 if (*fwp
> maxoffreg
)
424 /* Skip over the literal. */
440 * Convert word offset to length in bytes.
442 pfp
->pf_PByteLen
= (maxoff
+ maxoffreg
+ 1) * sizeof (ushort_t
);
443 miocack(wq
, mp
, 0, 0);
452 /* #define DEBUG 1 */
453 /* #define INNERDEBUG 1 */
456 #define enprintf(a) printf a
462 * Apply the packet filter given by pfp to the packet given by
463 * pp. Return nonzero iff the filter accepts the packet.
465 * The packet comes in two pieces, a header and a body, since
466 * that's the most convenient form for our caller. The header
467 * is in contiguous memory, whereas the body is in a mbuf.
468 * Our caller will have adjusted the mbuf chain so that its first
469 * min(MLEN, length(body)) bytes are guaranteed contiguous. For
470 * the sake of efficiency (and some laziness) the filter is prepared
471 * to examine only these two contiguous pieces. Furthermore, it
472 * assumes that the header length is even, so that there's no need
473 * to glue the last byte of header to the first byte of data.
476 #define opx(i) ((i) >> ENF_NBPA)
479 FilterPacket(struct packdesc
*pp
, struct epacketfilt
*pfp
)
481 int maxhdr
= pp
->pd_hdrlen
;
482 int maxword
= maxhdr
+ pp
->pd_bodylen
;
489 ushort_t stack
[ENMAXFILTERS
+1];
491 fp
= &pfp
->pf_Filter
[0];
492 fpe
= pfp
->pf_FilterEnd
;
494 enprintf(("FilterPacket(%p, %p, %p, %p):\n", pp
, pfp
, fp
, fpe
));
497 * Push TRUE on stack to start. The stack size is chosen such
498 * that overflow can't occur -- each operation can push at most
499 * one item on the stack, and the stack size equals the maximum
502 sp
= &stack
[ENMAXFILTERS
];
506 op
= *fp
>> ENF_NBPA
;
507 arg
= *fp
& ((1 << ENF_NBPA
) - 1);
514 * Since arg is unsigned,
515 * if it were less than ENF_PUSHWORD before,
516 * it would now be huge.
518 if (arg
+ offreg
< maxhdr
)
519 *--sp
= pp
->pd_hdr
[arg
+ offreg
];
520 else if (arg
+ offreg
< maxword
)
521 *--sp
= pp
->pd_body
[arg
- maxhdr
+ offreg
];
523 enprintf(("=>0(len)\n"));
545 case ENF_LOAD_OFFSET
:
554 enprintf(("BRTR: fp>=fpe\n"));
564 enprintf(("BRFL: fp>=fpe\n"));
570 if (sp
> &stack
[ENMAXFILTERS
]) {
571 enprintf(("stack underflow\n"));
579 if (sp
< &stack
[2]) { /* check stack overflow: small yellow zone */
580 enprintf(("=>0(--sp)\n"));
588 * all non-NOP operators binary, must have at least two operands
589 * on stack to evaluate.
591 if (sp
> &stack
[ENMAXFILTERS
-2]) {
592 enprintf(("=>0(sp++)\n"));
599 enprintf(("=>0(def)\n"));
629 /* short-circuit operators */
633 enprintf(("=>COR %x\n", *sp
));
639 enprintf(("=>CAND %x\n", *sp
));
645 enprintf(("=>COR %x\n", *sp
));
651 enprintf(("=>CNAND %x\n", *sp
));
657 enprintf(("=>%x\n", *sp
));