Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/pfmod.c
+++ new/usr/src/uts/common/io/pfmod.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 26 /*
29 27 * STREAMS Packet Filter Module
30 28 *
31 29 * This module applies a filter to messages arriving on its read
32 30 * queue, passing on messages that the filter accepts adn discarding
33 31 * the others. It supports ioctls for setting the filter.
34 32 *
35 33 * On the write side, the module simply passes everything through
36 34 * unchanged.
37 35 *
38 36 * Based on SunOS 4.x version. This version has minor changes:
39 37 * - general SVR4 porting stuff
40 38 * - change name and prefixes from "nit" buffer to streams buffer
41 39 * - multithreading assumes configured as D_MTQPAIR
42 40 */
43 41
44 42 #include <sys/types.h>
45 43 #include <sys/sysmacros.h>
46 44 #include <sys/errno.h>
47 45 #include <sys/debug.h>
48 46 #include <sys/time.h>
49 47 #include <sys/stropts.h>
50 48 #include <sys/stream.h>
51 49 #include <sys/conf.h>
52 50 #include <sys/ddi.h>
53 51 #include <sys/sunddi.h>
54 52 #include <sys/kmem.h>
55 53 #include <sys/strsun.h>
56 54 #include <sys/pfmod.h>
57 55 #include <sys/modctl.h>
58 56
59 57 /*
60 58 * Expanded version of the Packetfilt structure that includes
61 59 * some additional fields that aid filter execution efficiency.
62 60 */
63 61 struct epacketfilt {
64 62 struct Pf_ext_packetfilt pf;
65 63 #define pf_Priority pf.Pf_Priority
66 64 #define pf_FilterLen pf.Pf_FilterLen
67 65 #define pf_Filter pf.Pf_Filter
68 66 /* pointer to word immediately past end of filter */
69 67 ushort_t *pf_FilterEnd;
70 68 /* length in bytes of packet prefix the filter examines */
71 69 ushort_t pf_PByteLen;
72 70 };
73 71
74 72 /*
75 73 * (Internal) packet descriptor for FilterPacket
76 74 */
77 75 struct packdesc {
78 76 ushort_t *pd_hdr; /* header starting address */
79 77 uint_t pd_hdrlen; /* header length in shorts */
80 78 ushort_t *pd_body; /* body starting address */
81 79 uint_t pd_bodylen; /* body length in shorts */
82 80 };
83 81
84 82
85 83 /*
86 84 * Function prototypes.
87 85 */
88 86 static int pfopen(queue_t *, dev_t *, int, int, cred_t *);
89 87 static int pfclose(queue_t *);
90 88 static void pfioctl(queue_t *wq, mblk_t *mp);
91 89 static int FilterPacket(struct packdesc *, struct epacketfilt *);
92 90 /*
93 91 * To save instructions, since STREAMS ignores the return value
94 92 * from these functions, they are defined as void here. Kind of icky, but...
95 93 */
96 94 static void pfwput(queue_t *, mblk_t *);
97 95 static void pfrput(queue_t *, mblk_t *);
98 96
99 97 static struct module_info pf_minfo = {
100 98 22, /* mi_idnum */
101 99 "pfmod", /* mi_idname */
102 100 0, /* mi_minpsz */
103 101 INFPSZ, /* mi_maxpsz */
104 102 0, /* mi_hiwat */
105 103 0 /* mi_lowat */
106 104 };
107 105
108 106 static struct qinit pf_rinit = {
109 107 (int (*)())pfrput, /* qi_putp */
110 108 NULL,
111 109 pfopen, /* qi_qopen */
112 110 pfclose, /* qi_qclose */
113 111 NULL, /* qi_qadmin */
114 112 &pf_minfo, /* qi_minfo */
115 113 NULL /* qi_mstat */
116 114 };
117 115
118 116 static struct qinit pf_winit = {
119 117 (int (*)())pfwput, /* qi_putp */
120 118 NULL, /* qi_srvp */
121 119 NULL, /* qi_qopen */
122 120 NULL, /* qi_qclose */
123 121 NULL, /* qi_qadmin */
124 122 &pf_minfo, /* qi_minfo */
125 123 NULL /* qi_mstat */
126 124 };
127 125
128 126 static struct streamtab pf_info = {
129 127 &pf_rinit, /* st_rdinit */
130 128 &pf_winit, /* st_wrinit */
131 129 NULL, /* st_muxrinit */
132 130 NULL /* st_muxwinit */
133 131 };
134 132
135 133 static struct fmodsw fsw = {
↓ open down ↓ |
98 lines elided |
↑ open up ↑ |
136 134 "pfmod",
137 135 &pf_info,
138 136 D_MTQPAIR | D_MP
139 137 };
140 138
141 139 static struct modlstrmod modlstrmod = {
142 140 &mod_strmodops, "streams packet filter module", &fsw
143 141 };
144 142
145 143 static struct modlinkage modlinkage = {
146 - MODREV_1, &modlstrmod, NULL
144 + MODREV_1, { &modlstrmod, NULL }
147 145 };
148 146
149 147 int
150 148 _init(void)
151 149 {
152 150 return (mod_install(&modlinkage));
153 151 }
154 152
155 153 int
156 154 _fini(void)
157 155 {
158 156 return (mod_remove(&modlinkage));
159 157 }
160 158
161 159 int
162 160 _info(struct modinfo *modinfop)
163 161 {
164 162 return (mod_info(&modlinkage, modinfop));
165 163 }
166 164
167 165 /*ARGSUSED*/
168 166 static int
169 167 pfopen(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp)
170 168 {
171 169 struct epacketfilt *pfp;
172 170
173 171 ASSERT(rq);
174 172
175 173 if (sflag != MODOPEN)
176 174 return (EINVAL);
177 175
178 176 if (rq->q_ptr)
179 177 return (0);
180 178
181 179 /*
182 180 * Allocate and initialize per-Stream structure.
183 181 */
184 182 pfp = kmem_alloc(sizeof (struct epacketfilt), KM_SLEEP);
185 183 rq->q_ptr = WR(rq)->q_ptr = (char *)pfp;
186 184
187 185 qprocson(rq);
188 186
189 187 return (0);
190 188 }
191 189
192 190 static int
193 191 pfclose(queue_t *rq)
194 192 {
195 193 struct epacketfilt *pfp = (struct epacketfilt *)rq->q_ptr;
196 194
197 195 ASSERT(pfp);
198 196
199 197 qprocsoff(rq);
200 198
201 199 kmem_free(pfp, sizeof (struct epacketfilt));
202 200 rq->q_ptr = WR(rq)->q_ptr = NULL;
203 201
204 202 return (0);
205 203 }
206 204
207 205 /*
208 206 * Write-side put procedure. Its main task is to detect ioctls.
209 207 * Other message types are passed on through.
210 208 */
211 209 static void
212 210 pfwput(queue_t *wq, mblk_t *mp)
213 211 {
214 212 switch (mp->b_datap->db_type) {
215 213 case M_IOCTL:
216 214 pfioctl(wq, mp);
217 215 break;
218 216
219 217 default:
220 218 putnext(wq, mp);
221 219 break;
222 220 }
223 221 }
224 222
225 223 /*
226 224 * Read-side put procedure. It's responsible for applying the
227 225 * packet filter and passing upstream message on or discarding it
228 226 * depending upon the results.
229 227 *
230 228 * Upstream messages can start with zero or more M_PROTO mblks
231 229 * which are skipped over before executing the packet filter
232 230 * on any remaining M_DATA mblks.
233 231 */
234 232 static void
235 233 pfrput(queue_t *rq, mblk_t *mp)
236 234 {
237 235 struct epacketfilt *pfp = (struct epacketfilt *)rq->q_ptr;
238 236 mblk_t *mbp, *mpp;
239 237 struct packdesc pd;
240 238 int need;
241 239
242 240 ASSERT(pfp);
243 241
244 242 switch (DB_TYPE(mp)) {
245 243 case M_PROTO:
246 244 case M_DATA:
247 245 /*
248 246 * Skip over protocol information and find the start
249 247 * of the message body, saving the overall message
250 248 * start in mpp.
251 249 */
252 250 for (mpp = mp; mp && (DB_TYPE(mp) == M_PROTO); mp = mp->b_cont)
253 251 ;
254 252
255 253 /*
256 254 * Null body (exclusive of M_PROTO blocks) ==> accept.
257 255 * Note that a null body is not the same as an empty body.
258 256 */
259 257 if (mp == NULL) {
260 258 putnext(rq, mpp);
261 259 break;
262 260 }
263 261
264 262 /*
265 263 * Pull the packet up to the length required by
266 264 * the filter. Note that doing so destroys sharing
267 265 * relationships, which is unfortunate, since the
268 266 * results of pulling up here are likely to be useful
269 267 * for shared messages applied to a filter on a sibling
270 268 * stream.
271 269 *
272 270 * Most packet sources will provide the packet in two
273 271 * logical pieces: an initial header in a single mblk,
274 272 * and a body in a sequence of mblks hooked to the
275 273 * header. We're prepared to deal with variant forms,
276 274 * but in any case, the pullup applies only to the body
277 275 * part.
278 276 */
279 277 mbp = mp->b_cont;
280 278 need = pfp->pf_PByteLen;
281 279 if (mbp && (MBLKL(mbp) < need)) {
282 280 int len = msgdsize(mbp);
283 281
284 282 /* XXX discard silently on pullupmsg failure */
285 283 if (pullupmsg(mbp, MIN(need, len)) == 0) {
286 284 freemsg(mpp);
287 285 break;
288 286 }
289 287 }
290 288
291 289 /*
292 290 * Misalignment (not on short boundary) ==> reject.
293 291 */
294 292 if (((uintptr_t)mp->b_rptr & (sizeof (ushort_t) - 1)) ||
295 293 (mbp != NULL &&
296 294 ((uintptr_t)mbp->b_rptr & (sizeof (ushort_t) - 1)))) {
297 295 freemsg(mpp);
298 296 break;
299 297 }
300 298
301 299 /*
302 300 * These assignments are distasteful, but necessary,
303 301 * since the packet filter wants to work in terms of
304 302 * shorts. Odd bytes at the end of header or data can't
305 303 * participate in the filtering operation.
306 304 */
307 305 pd.pd_hdr = (ushort_t *)mp->b_rptr;
308 306 pd.pd_hdrlen = (mp->b_wptr - mp->b_rptr) / sizeof (ushort_t);
309 307 if (mbp) {
310 308 pd.pd_body = (ushort_t *)mbp->b_rptr;
311 309 pd.pd_bodylen = (mbp->b_wptr - mbp->b_rptr) /
312 310 sizeof (ushort_t);
313 311 } else {
314 312 pd.pd_body = NULL;
315 313 pd.pd_bodylen = 0;
316 314 }
317 315
318 316 /*
319 317 * Apply the filter.
320 318 */
321 319 if (FilterPacket(&pd, pfp))
322 320 putnext(rq, mpp);
323 321 else
324 322 freemsg(mpp);
325 323
326 324 break;
327 325
328 326 default:
329 327 putnext(rq, mp);
330 328 break;
331 329 }
332 330
333 331 }
334 332
335 333 /*
336 334 * Handle write-side M_IOCTL messages.
337 335 */
338 336 static void
339 337 pfioctl(queue_t *wq, mblk_t *mp)
340 338 {
341 339 struct epacketfilt *pfp = (struct epacketfilt *)wq->q_ptr;
342 340 struct Pf_ext_packetfilt *upfp;
343 341 struct packetfilt *opfp;
344 342 ushort_t *fwp;
345 343 int arg;
346 344 int maxoff = 0;
347 345 int maxoffreg = 0;
348 346 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
349 347 int error;
350 348
351 349 switch (iocp->ioc_cmd) {
352 350 case PFIOCSETF:
353 351 /*
354 352 * Verify argument length. Since the size of packet filter
355 353 * got increased (ENMAXFILTERS was bumped up to 2047), to
356 354 * maintain backwards binary compatibility, we need to
357 355 * check for both possible sizes.
358 356 */
359 357 switch (iocp->ioc_count) {
360 358 case sizeof (struct Pf_ext_packetfilt):
361 359 error = miocpullup(mp,
362 360 sizeof (struct Pf_ext_packetfilt));
363 361 if (error != 0) {
364 362 miocnak(wq, mp, 0, error);
365 363 return;
366 364 }
367 365 upfp = (struct Pf_ext_packetfilt *)mp->b_cont->b_rptr;
368 366 if (upfp->Pf_FilterLen > PF_MAXFILTERS) {
369 367 miocnak(wq, mp, 0, EINVAL);
370 368 return;
371 369 }
372 370
373 371 bcopy(upfp, pfp, sizeof (struct Pf_ext_packetfilt));
374 372 pfp->pf_FilterEnd = &pfp->pf_Filter[pfp->pf_FilterLen];
375 373 break;
376 374
377 375 case sizeof (struct packetfilt):
378 376 error = miocpullup(mp, sizeof (struct packetfilt));
379 377 if (error != 0) {
380 378 miocnak(wq, mp, 0, error);
381 379 return;
382 380 }
383 381 opfp = (struct packetfilt *)mp->b_cont->b_rptr;
384 382 /* this strange comparison keeps gcc from complaining */
385 383 if (opfp->Pf_FilterLen - 1 >= ENMAXFILTERS) {
386 384 miocnak(wq, mp, 0, EINVAL);
387 385 return;
388 386 }
389 387
390 388 pfp->pf.Pf_Priority = opfp->Pf_Priority;
391 389 pfp->pf.Pf_FilterLen = (unsigned int)opfp->Pf_FilterLen;
392 390
393 391 bcopy(opfp->Pf_Filter, pfp->pf.Pf_Filter,
394 392 sizeof (opfp->Pf_Filter));
395 393 pfp->pf_FilterEnd = &pfp->pf_Filter[pfp->pf_FilterLen];
396 394 break;
397 395
398 396 default:
399 397 miocnak(wq, mp, 0, EINVAL);
400 398 return;
401 399 }
402 400
403 401 /*
404 402 * Find and record maximum byte offset that the
405 403 * filter users. We use this when executing the
406 404 * filter to determine how much of the packet
407 405 * body to pull up. This code depends on the
408 406 * filter encoding.
409 407 */
410 408 for (fwp = pfp->pf_Filter; fwp < pfp->pf_FilterEnd; fwp++) {
411 409 arg = *fwp & ((1 << ENF_NBPA) - 1);
412 410 switch (arg) {
413 411 default:
414 412 if ((arg -= ENF_PUSHWORD) > maxoff)
415 413 maxoff = arg;
416 414 break;
417 415
418 416 case ENF_LOAD_OFFSET:
419 417 /* Point to the offset */
420 418 fwp++;
421 419 if (*fwp > maxoffreg)
422 420 maxoffreg = *fwp;
423 421 break;
424 422
425 423 case ENF_PUSHLIT:
426 424 case ENF_BRTR:
427 425 case ENF_BRFL:
428 426 /* Skip over the literal. */
429 427 fwp++;
430 428 break;
431 429
432 430 case ENF_PUSHZERO:
433 431 case ENF_PUSHONE:
434 432 case ENF_PUSHFFFF:
435 433 case ENF_PUSHFF00:
436 434 case ENF_PUSH00FF:
437 435 case ENF_NOPUSH:
438 436 case ENF_POP:
439 437 break;
440 438 }
441 439 }
442 440
443 441 /*
444 442 * Convert word offset to length in bytes.
445 443 */
446 444 pfp->pf_PByteLen = (maxoff + maxoffreg + 1) * sizeof (ushort_t);
447 445 miocack(wq, mp, 0, 0);
448 446 break;
449 447
450 448 default:
451 449 putnext(wq, mp);
452 450 break;
453 451 }
454 452 }
455 453
456 454 /* #define DEBUG 1 */
457 455 /* #define INNERDEBUG 1 */
458 456
459 457 #ifdef INNERDEBUG
460 458 #define enprintf(a) printf a
461 459 #else
462 460 #define enprintf(a)
463 461 #endif
464 462
465 463 /*
466 464 * Apply the packet filter given by pfp to the packet given by
467 465 * pp. Return nonzero iff the filter accepts the packet.
468 466 *
469 467 * The packet comes in two pieces, a header and a body, since
470 468 * that's the most convenient form for our caller. The header
471 469 * is in contiguous memory, whereas the body is in a mbuf.
472 470 * Our caller will have adjusted the mbuf chain so that its first
473 471 * min(MLEN, length(body)) bytes are guaranteed contiguous. For
474 472 * the sake of efficiency (and some laziness) the filter is prepared
475 473 * to examine only these two contiguous pieces. Furthermore, it
476 474 * assumes that the header length is even, so that there's no need
477 475 * to glue the last byte of header to the first byte of data.
478 476 */
479 477
480 478 #define opx(i) ((i) >> ENF_NBPA)
481 479
482 480 static int
483 481 FilterPacket(struct packdesc *pp, struct epacketfilt *pfp)
484 482 {
485 483 int maxhdr = pp->pd_hdrlen;
486 484 int maxword = maxhdr + pp->pd_bodylen;
487 485 ushort_t *sp;
488 486 ushort_t *fp;
489 487 ushort_t *fpe;
490 488 unsigned op;
491 489 unsigned arg;
492 490 unsigned offreg = 0;
493 491 ushort_t stack[ENMAXFILTERS+1];
494 492
495 493 fp = &pfp->pf_Filter[0];
496 494 fpe = pfp->pf_FilterEnd;
497 495
498 496 enprintf(("FilterPacket(%p, %p, %p, %p):\n", pp, pfp, fp, fpe));
499 497
500 498 /*
501 499 * Push TRUE on stack to start. The stack size is chosen such
502 500 * that overflow can't occur -- each operation can push at most
503 501 * one item on the stack, and the stack size equals the maximum
504 502 * program length.
505 503 */
506 504 sp = &stack[ENMAXFILTERS];
507 505 *sp = 1;
508 506
509 507 while (fp < fpe) {
510 508 op = *fp >> ENF_NBPA;
511 509 arg = *fp & ((1 << ENF_NBPA) - 1);
512 510 fp++;
513 511
514 512 switch (arg) {
515 513 default:
516 514 arg -= ENF_PUSHWORD;
517 515 /*
518 516 * Since arg is unsigned,
519 517 * if it were less than ENF_PUSHWORD before,
520 518 * it would now be huge.
521 519 */
522 520 if (arg + offreg < maxhdr)
523 521 *--sp = pp->pd_hdr[arg + offreg];
524 522 else if (arg + offreg < maxword)
525 523 *--sp = pp->pd_body[arg - maxhdr + offreg];
526 524 else {
527 525 enprintf(("=>0(len)\n"));
528 526 return (0);
529 527 }
530 528 break;
531 529 case ENF_PUSHLIT:
532 530 *--sp = *fp++;
533 531 break;
534 532 case ENF_PUSHZERO:
535 533 *--sp = 0;
536 534 break;
537 535 case ENF_PUSHONE:
538 536 *--sp = 1;
539 537 break;
540 538 case ENF_PUSHFFFF:
541 539 *--sp = 0xffff;
542 540 break;
543 541 case ENF_PUSHFF00:
544 542 *--sp = 0xff00;
545 543 break;
546 544 case ENF_PUSH00FF:
547 545 *--sp = 0x00ff;
548 546 break;
549 547 case ENF_LOAD_OFFSET:
550 548 offreg = *fp++;
551 549 break;
552 550 case ENF_BRTR:
553 551 if (*sp != 0)
554 552 fp += *fp;
555 553 else
556 554 fp++;
557 555 if (fp >= fpe) {
558 556 enprintf(("BRTR: fp>=fpe\n"));
559 557 return (0);
560 558 }
561 559 break;
562 560 case ENF_BRFL:
563 561 if (*sp == 0)
564 562 fp += *fp;
565 563 else
566 564 fp++;
567 565 if (fp >= fpe) {
568 566 enprintf(("BRFL: fp>=fpe\n"));
569 567 return (0);
570 568 }
571 569 break;
572 570 case ENF_POP:
573 571 ++sp;
574 572 if (sp > &stack[ENMAXFILTERS]) {
575 573 enprintf(("stack underflow\n"));
576 574 return (0);
577 575 }
578 576 break;
579 577 case ENF_NOPUSH:
580 578 break;
581 579 }
582 580
583 581 if (sp < &stack[2]) { /* check stack overflow: small yellow zone */
584 582 enprintf(("=>0(--sp)\n"));
585 583 return (0);
586 584 }
587 585
588 586 if (op == ENF_NOP)
589 587 continue;
590 588
591 589 /*
592 590 * all non-NOP operators binary, must have at least two operands
593 591 * on stack to evaluate.
594 592 */
595 593 if (sp > &stack[ENMAXFILTERS-2]) {
596 594 enprintf(("=>0(sp++)\n"));
597 595 return (0);
598 596 }
599 597
600 598 arg = *sp++;
601 599 switch (op) {
602 600 default:
603 601 enprintf(("=>0(def)\n"));
604 602 return (0);
605 603 case opx(ENF_AND):
606 604 *sp &= arg;
607 605 break;
608 606 case opx(ENF_OR):
609 607 *sp |= arg;
610 608 break;
611 609 case opx(ENF_XOR):
612 610 *sp ^= arg;
613 611 break;
614 612 case opx(ENF_EQ):
615 613 *sp = (*sp == arg);
616 614 break;
617 615 case opx(ENF_NEQ):
618 616 *sp = (*sp != arg);
619 617 break;
620 618 case opx(ENF_LT):
621 619 *sp = (*sp < arg);
622 620 break;
623 621 case opx(ENF_LE):
624 622 *sp = (*sp <= arg);
625 623 break;
626 624 case opx(ENF_GT):
627 625 *sp = (*sp > arg);
628 626 break;
629 627 case opx(ENF_GE):
630 628 *sp = (*sp >= arg);
631 629 break;
632 630
633 631 /* short-circuit operators */
634 632
635 633 case opx(ENF_COR):
636 634 if (*sp++ == arg) {
637 635 enprintf(("=>COR %x\n", *sp));
638 636 return (1);
639 637 }
640 638 break;
641 639 case opx(ENF_CAND):
642 640 if (*sp++ != arg) {
643 641 enprintf(("=>CAND %x\n", *sp));
644 642 return (0);
645 643 }
646 644 break;
647 645 case opx(ENF_CNOR):
648 646 if (*sp++ == arg) {
649 647 enprintf(("=>COR %x\n", *sp));
650 648 return (0);
651 649 }
652 650 break;
653 651 case opx(ENF_CNAND):
654 652 if (*sp++ != arg) {
655 653 enprintf(("=>CNAND %x\n", *sp));
656 654 return (1);
657 655 }
658 656 break;
659 657 }
660 658 }
661 659 enprintf(("=>%x\n", *sp));
662 660 return (*sp);
663 661 }
↓ open down ↓ |
507 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX