1 /*
2 * Copyright (C) 1993-2001, 2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7 * Use is subject to license terms.
8 */
9
10 #include <sys/systm.h>
11 #include <sys/types.h>
12 #include <sys/param.h>
13 #include <sys/errno.h>
14 #include <sys/uio.h>
15 #include <sys/buf.h>
16 #include <sys/modctl.h>
17 #include <sys/open.h>
18 #include <sys/kmem.h>
19 #include <sys/conf.h>
20 #include <sys/cmn_err.h>
21 #include <sys/stat.h>
22 #include <sys/cred.h>
23 #include <sys/dditypes.h>
24 #include <sys/poll.h>
25 #include <sys/autoconf.h>
26 #include <sys/byteorder.h>
27 #include <sys/socket.h>
28 #include <sys/dlpi.h>
29 #include <sys/stropts.h>
30 #include <sys/kstat.h>
31 #include <sys/sockio.h>
32 #include <sys/neti.h>
33 #include <sys/hook.h>
34 #include <net/if.h>
35 #if SOLARIS2 >= 6
36 #include <net/if_types.h>
37 #endif
38 #include <net/af.h>
39 #include <net/route.h>
40 #include <netinet/in.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/if_ether.h>
43 #include <netinet/ip.h>
44 #include <netinet/ip_var.h>
45 #include <netinet/tcp.h>
46 #include <netinet/udp.h>
47 #include <netinet/tcpip.h>
48 #include <netinet/ip_icmp.h>
49 #include <sys/ddi.h>
50 #include <sys/sunddi.h>
51 #include "netinet/ip_compat.h"
52 #include "netinet/ipl.h"
53 #include "netinet/ip_fil.h"
54 #include "netinet/ip_nat.h"
55 #include "netinet/ip_frag.h"
56 #include "netinet/ip_auth.h"
57 #include "netinet/ip_state.h"
58 #include "netinet/ipf_stack.h"
59
60 extern int iplwrite __P((dev_t, struct uio *, cred_t *));
61
62 static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
63 void *, void **));
64 #if SOLARIS2 < 10
65 static int ipf_identify __P((dev_info_t *));
66 #endif
67 static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
68 static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
69 static void *ipf_stack_create __P((const netid_t));
70 static void ipf_stack_destroy __P((const netid_t, void *));
71 static void ipf_stack_shutdown __P((const netid_t, void *));
72 static int ipf_property_g_update __P((dev_info_t *));
73 static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
74 IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
75 IPLOOKUP_NAME, NULL };
76
77
78 static struct cb_ops ipf_cb_ops = {
79 iplopen,
80 iplclose,
81 nodev, /* strategy */
82 nodev, /* print */
83 nodev, /* dump */
84 iplread,
85 iplwrite, /* write */
86 iplioctl, /* ioctl */
87 nodev, /* devmap */
88 nodev, /* mmap */
89 nodev, /* segmap */
90 nochpoll, /* poll */
91 ddi_prop_op,
92 NULL,
93 D_MTSAFE,
94 #if SOLARIS2 > 4
95 CB_REV,
96 nodev, /* aread */
97 nodev, /* awrite */
98 #endif
99 };
100
101 static struct dev_ops ipf_ops = {
102 DEVO_REV,
103 0,
104 ipf_getinfo,
105 #if SOLARIS2 >= 10
106 nulldev,
107 #else
108 ipf_identify,
109 #endif
110 nulldev,
111 ipf_attach,
112 ipf_detach,
113 nodev, /* reset */
114 &ipf_cb_ops,
115 (struct bus_ops *)0,
116 NULL,
117 ddi_quiesce_not_needed, /* quiesce */
118 };
119
120
121 static net_instance_t *ipfncb = NULL;
122 static ipf_stack_t *ipf_stacks = NULL;
123 static kmutex_t ipf_stack_lock;
124 extern struct mod_ops mod_driverops;
125 static struct modldrv iplmod = {
126 &mod_driverops, IPL_VERSION, &ipf_ops };
127 static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
128
129 #if SOLARIS2 >= 6
130 static size_t hdrsizes[57][2] = {
131 { 0, 0 },
132 { IFT_OTHER, 0 },
133 { IFT_1822, 0 },
134 { IFT_HDH1822, 0 },
135 { IFT_X25DDN, 0 },
136 { IFT_X25, 0 },
137 { IFT_ETHER, 14 },
138 { IFT_ISO88023, 0 },
139 { IFT_ISO88024, 0 },
140 { IFT_ISO88025, 0 },
141 { IFT_ISO88026, 0 },
142 { IFT_STARLAN, 0 },
143 { IFT_P10, 0 },
144 { IFT_P80, 0 },
145 { IFT_HY, 0 },
146 { IFT_FDDI, 24 },
147 { IFT_LAPB, 0 },
148 { IFT_SDLC, 0 },
149 { IFT_T1, 0 },
150 { IFT_CEPT, 0 },
151 { IFT_ISDNBASIC, 0 },
152 { IFT_ISDNPRIMARY, 0 },
153 { IFT_PTPSERIAL, 0 },
154 { IFT_PPP, 0 },
155 { IFT_LOOP, 0 },
156 { IFT_EON, 0 },
157 { IFT_XETHER, 0 },
158 { IFT_NSIP, 0 },
159 { IFT_SLIP, 0 },
160 { IFT_ULTRA, 0 },
161 { IFT_DS3, 0 },
162 { IFT_SIP, 0 },
163 { IFT_FRELAY, 0 },
164 { IFT_RS232, 0 },
165 { IFT_PARA, 0 },
166 { IFT_ARCNET, 0 },
167 { IFT_ARCNETPLUS, 0 },
168 { IFT_ATM, 0 },
169 { IFT_MIOX25, 0 },
170 { IFT_SONET, 0 },
171 { IFT_X25PLE, 0 },
172 { IFT_ISO88022LLC, 0 },
173 { IFT_LOCALTALK, 0 },
174 { IFT_SMDSDXI, 0 },
175 { IFT_FRELAYDCE, 0 },
176 { IFT_V35, 0 },
177 { IFT_HSSI, 0 },
178 { IFT_HIPPI, 0 },
179 { IFT_MODEM, 0 },
180 { IFT_AAL5, 0 },
181 { IFT_SONETPATH, 0 },
182 { IFT_SONETVT, 0 },
183 { IFT_SMDSICIP, 0 },
184 { IFT_PROPVIRTUAL, 0 },
185 { IFT_PROPMUX, 0 },
186 };
187 #endif /* SOLARIS2 >= 6 */
188
189 dev_info_t *ipf_dev_info = NULL;
190
191 static const filter_kstats_t ipf_kstat_tmp = {
192 { "pass", KSTAT_DATA_ULONG },
193 { "block", KSTAT_DATA_ULONG },
194 { "nomatch", KSTAT_DATA_ULONG },
195 { "short", KSTAT_DATA_ULONG },
196 { "pass, logged", KSTAT_DATA_ULONG },
197 { "block, logged", KSTAT_DATA_ULONG },
198 { "nomatch, logged", KSTAT_DATA_ULONG },
199 { "logged", KSTAT_DATA_ULONG },
200 { "skip", KSTAT_DATA_ULONG },
201 { "return sent", KSTAT_DATA_ULONG },
202 { "acct", KSTAT_DATA_ULONG },
203 { "bad frag state alloc", KSTAT_DATA_ULONG },
204 { "new frag state kept", KSTAT_DATA_ULONG },
205 { "new frag state compl. pkt", KSTAT_DATA_ULONG },
206 { "bad pkt state alloc", KSTAT_DATA_ULONG },
207 { "new pkt kept state", KSTAT_DATA_ULONG },
208 { "cachehit", KSTAT_DATA_ULONG },
209 { "tcp cksum bad", KSTAT_DATA_ULONG },
210 {{ "pullup ok", KSTAT_DATA_ULONG },
211 { "pullup nok", KSTAT_DATA_ULONG }},
212 { "src != route", KSTAT_DATA_ULONG },
213 { "ttl invalid", KSTAT_DATA_ULONG },
214 { "bad ip pkt", KSTAT_DATA_ULONG },
215 { "ipv6 pkt", KSTAT_DATA_ULONG },
216 { "dropped:pps ceiling", KSTAT_DATA_ULONG },
217 { "ip upd. fail", KSTAT_DATA_ULONG }
218 };
219
220
221 static int ipf_kstat_update(kstat_t *ksp, int rwflag);
222
223 static void
ipf_kstat_init(ipf_stack_t * ifs)224 ipf_kstat_init(ipf_stack_t *ifs)
225 {
226 ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid, "ipf", 0,
227 "inbound", "net", KSTAT_TYPE_NAMED,
228 sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
229 if (ifs->ifs_kstatp[0] != NULL) {
230 bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data,
231 sizeof (filter_kstats_t));
232 ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update;
233 ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0];
234 kstat_install(ifs->ifs_kstatp[0]);
235 }
236
237 ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid, "ipf", 0,
238 "outbound", "net", KSTAT_TYPE_NAMED,
239 sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
240 if (ifs->ifs_kstatp[1] != NULL) {
241 bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data,
242 sizeof (filter_kstats_t));
243 ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update;
244 ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1];
245 kstat_install(ifs->ifs_kstatp[1]);
246 }
247
248 #ifdef IPFDEBUG
249 cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p",
250 ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]);
251 #endif
252 }
253
254
255 static void
ipf_kstat_fini(ipf_stack_t * ifs)256 ipf_kstat_fini(ipf_stack_t *ifs)
257 {
258 int i;
259
260 for (i = 0; i < 2; i++) {
261 if (ifs->ifs_kstatp[i] != NULL) {
262 net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]);
263 ifs->ifs_kstatp[i] = NULL;
264 }
265 }
266 }
267
268
269 static int
ipf_kstat_update(kstat_t * ksp,int rwflag)270 ipf_kstat_update(kstat_t *ksp, int rwflag)
271 {
272 filter_kstats_t *fkp;
273 filterstats_t *fsp;
274
275 if (ksp == NULL || ksp->ks_data == NULL)
276 return (EIO);
277
278 if (rwflag == KSTAT_WRITE)
279 return (EACCES);
280
281 fkp = ksp->ks_data;
282 fsp = ksp->ks_private;
283
284 fkp->fks_pass.value.ul = fsp->fr_pass;
285 fkp->fks_block.value.ul = fsp->fr_block;
286 fkp->fks_nom.value.ul = fsp->fr_nom;
287 fkp->fks_short.value.ul = fsp->fr_short;
288 fkp->fks_ppkl.value.ul = fsp->fr_ppkl;
289 fkp->fks_bpkl.value.ul = fsp->fr_bpkl;
290 fkp->fks_npkl.value.ul = fsp->fr_npkl;
291 fkp->fks_pkl.value.ul = fsp->fr_pkl;
292 fkp->fks_skip.value.ul = fsp->fr_skip;
293 fkp->fks_ret.value.ul = fsp->fr_ret;
294 fkp->fks_acct.value.ul = fsp->fr_acct;
295 fkp->fks_bnfr.value.ul = fsp->fr_bnfr;
296 fkp->fks_nfr.value.ul = fsp->fr_nfr;
297 fkp->fks_cfr.value.ul = fsp->fr_cfr;
298 fkp->fks_bads.value.ul = fsp->fr_bads;
299 fkp->fks_ads.value.ul = fsp->fr_ads;
300 fkp->fks_chit.value.ul = fsp->fr_chit;
301 fkp->fks_tcpbad.value.ul = fsp->fr_tcpbad;
302 fkp->fks_pull[0].value.ul = fsp->fr_pull[0];
303 fkp->fks_pull[1].value.ul = fsp->fr_pull[1];
304 fkp->fks_badsrc.value.ul = fsp->fr_badsrc;
305 fkp->fks_badttl.value.ul = fsp->fr_badttl;
306 fkp->fks_bad.value.ul = fsp->fr_bad;
307 fkp->fks_ipv6.value.ul = fsp->fr_ipv6;
308 fkp->fks_ppshit.value.ul = fsp->fr_ppshit;
309 fkp->fks_ipud.value.ul = fsp->fr_ipud;
310
311 return (0);
312 }
313
314 int
_init()315 _init()
316 {
317 int ipfinst;
318
319 ipfinst = mod_install(&modlink1);
320 #ifdef IPFDEBUG
321 cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
322 #endif
323 mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL);
324 return (ipfinst);
325 }
326
327
328 int
_fini(void)329 _fini(void)
330 {
331 int ipfinst;
332
333 ipfinst = mod_remove(&modlink1);
334 #ifdef IPFDEBUG
335 cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
336 #endif
337 return (ipfinst);
338 }
339
340
341 int
_info(modinfop)342 _info(modinfop)
343 struct modinfo *modinfop;
344 {
345 int ipfinst;
346
347 ipfinst = mod_info(&modlink1, modinfop);
348 #ifdef IPFDEBUG
349 cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst);
350 #endif
351 return (ipfinst);
352 }
353
354
355 #if SOLARIS2 < 10
ipf_identify(dip)356 static int ipf_identify(dip)
357 dev_info_t *dip;
358 {
359 #ifdef IPFDEBUG
360 cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip);
361 #endif
362 if (strcmp(ddi_get_name(dip), "ipf") == 0)
363 return (DDI_IDENTIFIED);
364 return (DDI_NOT_IDENTIFIED);
365 }
366 #endif
367
368 /*
369 * Initialize things for IPF for each stack instance
370 */
371 static void *
ipf_stack_create(const netid_t id)372 ipf_stack_create(const netid_t id)
373 {
374 ipf_stack_t *ifs;
375
376 #ifdef IPFDEBUG
377 cmn_err(CE_NOTE, "IP Filter:stack_create id=%d", id);
378 #endif
379
380 ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP);
381 bzero(ifs, sizeof (*ifs));
382
383 ifs->ifs_hook4_physical_in = B_FALSE;
384 ifs->ifs_hook4_physical_out = B_FALSE;
385 ifs->ifs_hook4_nic_events = B_FALSE;
386 ifs->ifs_hook4_loopback_in = B_FALSE;
387 ifs->ifs_hook4_loopback_out = B_FALSE;
388 ifs->ifs_hook6_physical_in = B_FALSE;
389 ifs->ifs_hook6_physical_out = B_FALSE;
390 ifs->ifs_hook6_nic_events = B_FALSE;
391 ifs->ifs_hook6_loopback_in = B_FALSE;
392 ifs->ifs_hook6_loopback_out = B_FALSE;
393
394 /*
395 * Initialize mutex's
396 */
397 RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
398 RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
399 RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock");
400 ifs->ifs_netid = id;
401 ifs->ifs_zone = net_getzoneidbynetid(id);
402 ipf_kstat_init(ifs);
403
404 #ifdef IPFDEBUG
405 cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone);
406 #endif
407
408 /*
409 * Lock people out while we set things up.
410 */
411 WRITE_ENTER(&ifs->ifs_ipf_global);
412 ipftuneable_alloc(ifs);
413 RWLOCK_EXIT(&ifs->ifs_ipf_global);
414
415 /* Limit to global stack */
416 if (ifs->ifs_zone == GLOBAL_ZONEID)
417 cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
418
419 mutex_enter(&ipf_stack_lock);
420 if (ipf_stacks != NULL)
421 ipf_stacks->ifs_pnext = &ifs->ifs_next;
422 ifs->ifs_next = ipf_stacks;
423 ifs->ifs_pnext = &ipf_stacks;
424 ipf_stacks = ifs;
425 mutex_exit(&ipf_stack_lock);
426
427 return (ifs);
428 }
429
430
431 /*
432 * This function should only ever be used to find the pointer to the
433 * ipfilter stack structure for the zone that is currently being
434 * executed... so if you're running in the context of zone 1, you
435 * should not attempt to find the ipf_stack_t for zone 0 or 2 or
436 * anything else but 1. In that way, the returned pointer is safe
437 * as it will only be nuked when the instance is destroyed as part
438 * of the final shutdown of a zone.
439 */
440 ipf_stack_t *
ipf_find_stack(const zoneid_t zone)441 ipf_find_stack(const zoneid_t zone)
442 {
443 ipf_stack_t *ifs;
444
445 mutex_enter(&ipf_stack_lock);
446 for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) {
447 if (ifs->ifs_zone == zone)
448 break;
449 }
450 mutex_exit(&ipf_stack_lock);
451 return (ifs);
452 }
453
454
ipf_detach_check_zone(ipf_stack_t * ifs)455 static int ipf_detach_check_zone(ipf_stack_t *ifs)
456 {
457 /*
458 * Make sure we're the only one's modifying things. With
459 * this lock others should just fall out of the loop.
460 */
461 READ_ENTER(&ifs->ifs_ipf_global);
462 if (ifs->ifs_fr_running == 1) {
463 RWLOCK_EXIT(&ifs->ifs_ipf_global);
464 return (-1);
465 }
466
467 /*
468 * Make sure there is no active filter rule.
469 */
470 if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] ||
471 ifs->ifs_ipfilter[1][ifs->ifs_fr_active] ||
472 ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] ||
473 ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) {
474 RWLOCK_EXIT(&ifs->ifs_ipf_global);
475 return (-1);
476 }
477
478 RWLOCK_EXIT(&ifs->ifs_ipf_global);
479
480 return (0);
481 }
482
483
ipf_detach_check_all()484 static int ipf_detach_check_all()
485 {
486 ipf_stack_t *ifs;
487
488 mutex_enter(&ipf_stack_lock);
489 for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next)
490 if (ipf_detach_check_zone(ifs) != 0)
491 break;
492 mutex_exit(&ipf_stack_lock);
493 return ((ifs == NULL) ? 0 : -1);
494 }
495
496
497 /*
498 * Destroy things for ipf for one stack.
499 */
500 /* ARGSUSED */
501 static void
ipf_stack_shutdown(const netid_t id,void * arg)502 ipf_stack_shutdown(const netid_t id, void *arg)
503 {
504 ipf_stack_t *ifs = (ipf_stack_t *)arg;
505
506 ipf_kstat_fini(ifs);
507 }
508
509
510 /*
511 * Destroy things for ipf for one stack.
512 */
513 /* ARGSUSED */
514 static void
ipf_stack_destroy(const netid_t id,void * arg)515 ipf_stack_destroy(const netid_t id, void *arg)
516 {
517 ipf_stack_t *ifs = (ipf_stack_t *)arg;
518 timeout_id_t tid;
519
520 #ifdef IPFDEBUG
521 (void) printf("ipf_stack_destroy(%p)\n", (void *)ifs);
522 #endif
523
524 /*
525 * Make sure we're the only one's modifying things. With
526 * this lock others should just fall out of the loop.
527 */
528 WRITE_ENTER(&ifs->ifs_ipf_global);
529 if (ifs->ifs_fr_running == -2) {
530 RWLOCK_EXIT(&ifs->ifs_ipf_global);
531 return;
532 }
533 ifs->ifs_fr_running = -2;
534 tid = ifs->ifs_fr_timer_id;
535 ifs->ifs_fr_timer_id = NULL;
536 RWLOCK_EXIT(&ifs->ifs_ipf_global);
537
538 mutex_enter(&ipf_stack_lock);
539 if (ifs->ifs_next != NULL)
540 ifs->ifs_next->ifs_pnext = ifs->ifs_pnext;
541 *ifs->ifs_pnext = ifs->ifs_next;
542 mutex_exit(&ipf_stack_lock);
543
544 if (tid != NULL)
545 (void) untimeout(tid);
546
547 WRITE_ENTER(&ifs->ifs_ipf_global);
548 if (ipldetach(ifs) != 0) {
549 printf("ipf_stack_destroy: ipldetach failed\n");
550 }
551
552 ipftuneable_free(ifs);
553
554 RWLOCK_EXIT(&ifs->ifs_ipf_global);
555 RW_DESTROY(&ifs->ifs_ipf_mutex);
556 RW_DESTROY(&ifs->ifs_ipf_frcache);
557 RW_DESTROY(&ifs->ifs_ipf_global);
558
559 KFREE(ifs);
560 }
561
562
ipf_attach(dip,cmd)563 static int ipf_attach(dip, cmd)
564 dev_info_t *dip;
565 ddi_attach_cmd_t cmd;
566 {
567 char *s;
568 int i;
569 int instance;
570
571 #ifdef IPFDEBUG
572 cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd);
573 #endif
574
575 switch (cmd)
576 {
577 case DDI_ATTACH:
578 instance = ddi_get_instance(dip);
579 /* Only one instance of ipf (instance 0) can be attached. */
580 if (instance > 0)
581 return (DDI_FAILURE);
582
583 #ifdef IPFDEBUG
584 cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance);
585 #endif
586
587 (void) ipf_property_g_update(dip);
588
589 for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
590 s = strrchr(s, '/');
591 if (s == NULL)
592 continue;
593 s++;
594 if (ddi_create_minor_node(dip, s, S_IFCHR, i,
595 DDI_PSEUDO, 0) ==
596 DDI_FAILURE) {
597 ddi_remove_minor_node(dip, NULL);
598 goto attach_failed;
599 }
600 }
601
602 ipf_dev_info = dip;
603
604 ipfncb = net_instance_alloc(NETINFO_VERSION);
605 ipfncb->nin_name = "ipf";
606 ipfncb->nin_create = ipf_stack_create;
607 ipfncb->nin_destroy = ipf_stack_destroy;
608 ipfncb->nin_shutdown = ipf_stack_shutdown;
609 i = net_instance_register(ipfncb);
610
611 #ifdef IPFDEBUG
612 cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
613 #endif
614
615 return (DDI_SUCCESS);
616 /* NOTREACHED */
617 default:
618 break;
619 }
620
621 attach_failed:
622 ddi_prop_remove_all(dip);
623 return (DDI_FAILURE);
624 }
625
626
ipf_detach(dip,cmd)627 static int ipf_detach(dip, cmd)
628 dev_info_t *dip;
629 ddi_detach_cmd_t cmd;
630 {
631 int i;
632
633 #ifdef IPFDEBUG
634 cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
635 #endif
636 switch (cmd) {
637 case DDI_DETACH:
638 if (ipf_detach_check_all() != 0)
639 return (DDI_FAILURE);
640
641 /*
642 * Undo what we did in ipf_attach, freeing resources
643 * and removing things we installed. The system
644 * framework guarantees we are not active with this devinfo
645 * node in any other entry points at this time.
646 */
647 ddi_prop_remove_all(dip);
648 i = ddi_get_instance(dip);
649 ddi_remove_minor_node(dip, NULL);
650 if (i > 0) {
651 cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
652 return (DDI_FAILURE);
653 }
654
655 (void) net_instance_unregister(ipfncb);
656 net_instance_free(ipfncb);
657
658 return (DDI_SUCCESS);
659 /* NOTREACHED */
660 default:
661 break;
662 }
663 cmn_err(CE_NOTE, "IP Filter: failed to detach\n");
664 return (DDI_FAILURE);
665 }
666
667
668 /*ARGSUSED*/
ipf_getinfo(dip,infocmd,arg,result)669 static int ipf_getinfo(dip, infocmd, arg, result)
670 dev_info_t *dip;
671 ddi_info_cmd_t infocmd;
672 void *arg, **result;
673 {
674 int error;
675
676 error = DDI_FAILURE;
677 #ifdef IPFDEBUG
678 cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg);
679 #endif
680 switch (infocmd) {
681 case DDI_INFO_DEVT2DEVINFO:
682 *result = ipf_dev_info;
683 error = DDI_SUCCESS;
684 break;
685 case DDI_INFO_DEVT2INSTANCE:
686 *result = (void *)0;
687 error = DDI_SUCCESS;
688 break;
689 default:
690 break;
691 }
692 return (error);
693 }
694
695
696 /*
697 * Fetch configuration file values that have been entered into the ipf.conf
698 * driver file.
699 */
ipf_property_g_update(dip)700 static int ipf_property_g_update(dip)
701 dev_info_t *dip;
702 {
703 #ifdef DDI_NO_AUTODETACH
704 if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
705 DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) {
706 cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed");
707 return (DDI_FAILURE);
708 }
709 #else
710 if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
711 "ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) {
712 cmn_err(CE_WARN, "!updating ddi-no-autodetach failed");
713 return (DDI_FAILURE);
714 }
715 #endif
716
717 return (DDI_SUCCESS);
718 }
719
720 int
ipf_property_update(dip,ifs)721 ipf_property_update(dip, ifs)
722 dev_info_t *dip;
723 ipf_stack_t *ifs;
724 {
725 ipftuneable_t *ipft;
726 char *name;
727 uint_t one;
728 int *i32p;
729 int err, rv = 0;
730
731 for (ipft = ifs->ifs_ipf_tuneables;
732 (name = ipft->ipft_name) != NULL; ipft++) {
733 one = 1;
734 i32p = NULL;
735 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
736 0, name, &i32p, &one);
737 if (err == DDI_PROP_NOT_FOUND)
738 continue;
739 #ifdef IPFDEBUG
740 cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
741 name, err);
742 #endif
743 if (err != DDI_PROP_SUCCESS) {
744 rv = err;
745 continue;
746 }
747
748 if (*i32p >= ipft->ipft_min &&
749 *i32p <= ipft->ipft_max) {
750 if (ipft->ipft_sz == sizeof (uint32_t)) {
751 *ipft->ipft_pint = *i32p;
752 } else if (ipft->ipft_sz == sizeof (uint64_t)) {
753 *ipft->ipft_plong = *i32p;
754 }
755 }
756
757 ddi_prop_free(i32p);
758 }
759
760 return (rv);
761 }
762