Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/inet/ipf/solaris.c
+++ new/usr/src/uts/common/inet/ipf/solaris.c
1 1 /*
2 2 * Copyright (C) 1993-2001, 2003 by Darren Reed.
3 3 *
4 4 * See the IPFILTER.LICENCE file for details on licencing.
5 5 *
6 6 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7 7 * Use is subject to license terms.
8 8 *
9 9 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
10 10 */
11 11
12 12 /*
13 13 * ipfilter kernel module mutexes and locking:
14 14 *
15 15 * Enabling ipfilter creates a per-netstack ipf_stack_t object that is
16 16 * stored in the ipf_stacks list, which is protected by ipf_stack_lock.
17 17 * ipf_stack_t objects are accessed in three contexts:
18 18 *
19 19 * 1) administering that filter (eg: ioctls handled with iplioctl())
20 20 * 2) reading log data (eg: iplread() / iplwrite())
21 21 * 3) filtering packets (eg: ipf_hook4_* and ipf_hook6_* pfhooks
22 22 * functions)
23 23 *
24 24 * Each ipf_stack_t has a RW lock, ifs_ipf_global, protecting access to the
25 25 * whole structure. The structure also has locks protecting the various
26 26 * data structures used for filtering. The following guidelines should be
27 27 * followed for ipf_stack_t locks:
28 28 *
29 29 * - ipf_stack_lock must be held when accessing the ipf_stacks list
30 30 * - ipf_stack_lock should be held before acquiring ifs_ipf_global for
31 31 * a stack (the exception to this is ipf_stack_destroy(), which removes
32 32 * the ipf_stack_t from the list, then drops ipf_stack_lock before
33 33 * acquiring ifs_ipf_global)
34 34 * - ifs_ipf_global must be held when accessing an ipf_stack_t in that list:
35 35 * - The write lock is held only during stack creation / destruction
36 36 * - The read lock should be held for all other accesses
37 37 * - To alter the filtering data in the administrative context, one must:
38 38 * - acquire the read lock for ifs_ipf_global
39 39 * - then acquire the write lock for the data in question
40 40 * - In the filtering path, the read lock needs to be held for each type of
41 41 * filtering data used
42 42 * - ifs_ipf_global does not need to be held in the filtering path:
43 43 * - The filtering hooks don't need to modify the stack itself
44 44 * - The ipf_stack_t will not be destroyed until the hooks are unregistered.
45 45 * This requires a write lock on the hook, ensuring that no active hooks
46 46 * (eg: the filtering path) are running, and that the hooks won't be run
47 47 * afterward.
48 48 *
49 49 * Note that there is a deadlock possible when calling net_hook_register()
50 50 * or net_hook_unregister() with ifs_ipf_global held: see the comments in
51 51 * iplattach() and ipldetach() for details.
52 52 */
53 53
54 54 #include <sys/systm.h>
55 55 #include <sys/types.h>
56 56 #include <sys/param.h>
57 57 #include <sys/errno.h>
58 58 #include <sys/uio.h>
59 59 #include <sys/buf.h>
60 60 #include <sys/modctl.h>
61 61 #include <sys/open.h>
62 62 #include <sys/kmem.h>
63 63 #include <sys/conf.h>
64 64 #include <sys/cmn_err.h>
65 65 #include <sys/stat.h>
66 66 #include <sys/cred.h>
67 67 #include <sys/dditypes.h>
68 68 #include <sys/poll.h>
69 69 #include <sys/autoconf.h>
70 70 #include <sys/byteorder.h>
71 71 #include <sys/socket.h>
72 72 #include <sys/dlpi.h>
73 73 #include <sys/stropts.h>
74 74 #include <sys/kstat.h>
75 75 #include <sys/sockio.h>
76 76 #include <sys/neti.h>
77 77 #include <sys/hook.h>
78 78 #include <net/if.h>
79 79 #if SOLARIS2 >= 6
80 80 #include <net/if_types.h>
81 81 #endif
82 82 #include <net/af.h>
83 83 #include <net/route.h>
84 84 #include <netinet/in.h>
85 85 #include <netinet/in_systm.h>
86 86 #include <netinet/if_ether.h>
87 87 #include <netinet/ip.h>
88 88 #include <netinet/ip_var.h>
89 89 #include <netinet/tcp.h>
90 90 #include <netinet/udp.h>
91 91 #include <netinet/tcpip.h>
92 92 #include <netinet/ip_icmp.h>
93 93 #include <sys/ddi.h>
94 94 #include <sys/sunddi.h>
95 95 #include "netinet/ip_compat.h"
96 96 #include "netinet/ipl.h"
97 97 #include "netinet/ip_fil.h"
98 98 #include "netinet/ip_nat.h"
99 99 #include "netinet/ip_frag.h"
100 100 #include "netinet/ip_auth.h"
101 101 #include "netinet/ip_state.h"
102 102 #include "netinet/ipf_stack.h"
103 103
104 104 extern int iplwrite __P((dev_t, struct uio *, cred_t *));
105 105
106 106 static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
107 107 void *, void **));
108 108 #if SOLARIS2 < 10
109 109 static int ipf_identify __P((dev_info_t *));
110 110 #endif
111 111 static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
112 112 static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
113 113 static void *ipf_stack_create __P((const netid_t));
114 114 static void ipf_stack_destroy __P((const netid_t, void *));
115 115 static void ipf_stack_shutdown __P((const netid_t, void *));
116 116 static int ipf_property_g_update __P((dev_info_t *));
117 117 static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
118 118 IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
119 119 IPLOOKUP_NAME, NULL };
120 120 extern void *ipf_state; /* DDI state */
121 121 extern vmem_t *ipf_minor; /* minor number arena */
122 122
123 123 static struct cb_ops ipf_cb_ops = {
124 124 iplopen,
125 125 iplclose,
126 126 nodev, /* strategy */
127 127 nodev, /* print */
128 128 nodev, /* dump */
129 129 iplread,
130 130 iplwrite, /* write */
131 131 iplioctl, /* ioctl */
132 132 nodev, /* devmap */
133 133 nodev, /* mmap */
134 134 nodev, /* segmap */
135 135 nochpoll, /* poll */
136 136 ddi_prop_op,
137 137 NULL,
138 138 D_MTSAFE,
139 139 #if SOLARIS2 > 4
140 140 CB_REV,
141 141 nodev, /* aread */
142 142 nodev, /* awrite */
143 143 #endif
144 144 };
145 145
146 146 static struct dev_ops ipf_ops = {
147 147 DEVO_REV,
148 148 0,
149 149 ipf_getinfo,
150 150 #if SOLARIS2 >= 10
151 151 nulldev,
152 152 #else
153 153 ipf_identify,
154 154 #endif
155 155 nulldev,
156 156 ipf_attach,
157 157 ipf_detach,
158 158 nodev, /* reset */
159 159 &ipf_cb_ops,
160 160 (struct bus_ops *)0,
161 161 NULL,
↓ open down ↓ |
161 lines elided |
↑ open up ↑ |
162 162 ddi_quiesce_not_needed, /* quiesce */
163 163 };
164 164
165 165
166 166 static net_instance_t *ipfncb = NULL;
167 167 static ipf_stack_t *ipf_stacks = NULL;
168 168 static kmutex_t ipf_stack_lock;
169 169 extern struct mod_ops mod_driverops;
170 170 static struct modldrv iplmod = {
171 171 &mod_driverops, IPL_VERSION, &ipf_ops };
172 -static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
172 +static struct modlinkage modlink1 = { MODREV_1, { &iplmod, NULL } };
173 173
174 174 #if SOLARIS2 >= 6
175 175 static size_t hdrsizes[57][2] = {
176 176 { 0, 0 },
177 177 { IFT_OTHER, 0 },
178 178 { IFT_1822, 0 },
179 179 { IFT_HDH1822, 0 },
180 180 { IFT_X25DDN, 0 },
181 181 { IFT_X25, 0 },
182 182 { IFT_ETHER, 14 },
183 183 { IFT_ISO88023, 0 },
184 184 { IFT_ISO88024, 0 },
185 185 { IFT_ISO88025, 0 },
186 186 { IFT_ISO88026, 0 },
187 187 { IFT_STARLAN, 0 },
188 188 { IFT_P10, 0 },
189 189 { IFT_P80, 0 },
190 190 { IFT_HY, 0 },
191 191 { IFT_FDDI, 24 },
192 192 { IFT_LAPB, 0 },
193 193 { IFT_SDLC, 0 },
194 194 { IFT_T1, 0 },
195 195 { IFT_CEPT, 0 },
196 196 { IFT_ISDNBASIC, 0 },
197 197 { IFT_ISDNPRIMARY, 0 },
198 198 { IFT_PTPSERIAL, 0 },
199 199 { IFT_PPP, 0 },
200 200 { IFT_LOOP, 0 },
201 201 { IFT_EON, 0 },
202 202 { IFT_XETHER, 0 },
203 203 { IFT_NSIP, 0 },
204 204 { IFT_SLIP, 0 },
205 205 { IFT_ULTRA, 0 },
206 206 { IFT_DS3, 0 },
207 207 { IFT_SIP, 0 },
208 208 { IFT_FRELAY, 0 },
209 209 { IFT_RS232, 0 },
210 210 { IFT_PARA, 0 },
211 211 { IFT_ARCNET, 0 },
212 212 { IFT_ARCNETPLUS, 0 },
213 213 { IFT_ATM, 0 },
214 214 { IFT_MIOX25, 0 },
215 215 { IFT_SONET, 0 },
216 216 { IFT_X25PLE, 0 },
217 217 { IFT_ISO88022LLC, 0 },
218 218 { IFT_LOCALTALK, 0 },
219 219 { IFT_SMDSDXI, 0 },
220 220 { IFT_FRELAYDCE, 0 },
221 221 { IFT_V35, 0 },
222 222 { IFT_HSSI, 0 },
223 223 { IFT_HIPPI, 0 },
224 224 { IFT_MODEM, 0 },
225 225 { IFT_AAL5, 0 },
226 226 { IFT_SONETPATH, 0 },
227 227 { IFT_SONETVT, 0 },
228 228 { IFT_SMDSICIP, 0 },
229 229 { IFT_PROPVIRTUAL, 0 },
230 230 { IFT_PROPMUX, 0 },
231 231 };
232 232 #endif /* SOLARIS2 >= 6 */
233 233
234 234 dev_info_t *ipf_dev_info = NULL;
235 235
236 236 static const filter_kstats_t ipf_kstat_tmp = {
237 237 { "pass", KSTAT_DATA_ULONG },
238 238 { "block", KSTAT_DATA_ULONG },
239 239 { "nomatch", KSTAT_DATA_ULONG },
240 240 { "short", KSTAT_DATA_ULONG },
241 241 { "pass, logged", KSTAT_DATA_ULONG },
242 242 { "block, logged", KSTAT_DATA_ULONG },
243 243 { "nomatch, logged", KSTAT_DATA_ULONG },
244 244 { "logged", KSTAT_DATA_ULONG },
245 245 { "skip", KSTAT_DATA_ULONG },
246 246 { "return sent", KSTAT_DATA_ULONG },
247 247 { "acct", KSTAT_DATA_ULONG },
248 248 { "bad frag state alloc", KSTAT_DATA_ULONG },
249 249 { "new frag state kept", KSTAT_DATA_ULONG },
250 250 { "new frag state compl. pkt", KSTAT_DATA_ULONG },
251 251 { "bad pkt state alloc", KSTAT_DATA_ULONG },
252 252 { "new pkt kept state", KSTAT_DATA_ULONG },
253 253 { "cachehit", KSTAT_DATA_ULONG },
254 254 { "tcp cksum bad", KSTAT_DATA_ULONG },
255 255 {{ "pullup ok", KSTAT_DATA_ULONG },
256 256 { "pullup nok", KSTAT_DATA_ULONG }},
257 257 { "src != route", KSTAT_DATA_ULONG },
258 258 { "ttl invalid", KSTAT_DATA_ULONG },
259 259 { "bad ip pkt", KSTAT_DATA_ULONG },
260 260 { "ipv6 pkt", KSTAT_DATA_ULONG },
261 261 { "dropped:pps ceiling", KSTAT_DATA_ULONG },
262 262 { "ip upd. fail", KSTAT_DATA_ULONG }
263 263 };
264 264
265 265
266 266 static int ipf_kstat_update(kstat_t *ksp, int rwflag);
267 267
268 268 static void
269 269 ipf_kstat_init(ipf_stack_t *ifs, boolean_t from_gz)
270 270 {
271 271 ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid,
272 272 (from_gz ? "ipf_gz" : "ipf"),
273 273 0, "inbound", "net", KSTAT_TYPE_NAMED,
274 274 sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
275 275 if (ifs->ifs_kstatp[0] != NULL) {
276 276 bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data,
277 277 sizeof (filter_kstats_t));
278 278 ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update;
279 279 ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0];
280 280 kstat_install(ifs->ifs_kstatp[0]);
281 281 }
282 282
283 283 ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid,
284 284 (from_gz ? "ipf_gz" : "ipf"),
285 285 0, "outbound", "net", KSTAT_TYPE_NAMED,
286 286 sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
287 287 if (ifs->ifs_kstatp[1] != NULL) {
288 288 bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data,
289 289 sizeof (filter_kstats_t));
290 290 ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update;
291 291 ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1];
292 292 kstat_install(ifs->ifs_kstatp[1]);
293 293 }
294 294
295 295 #ifdef IPFDEBUG
296 296 cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p",
297 297 ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]);
298 298 #endif
299 299 }
300 300
301 301
302 302 static void
303 303 ipf_kstat_fini(ipf_stack_t *ifs)
304 304 {
305 305 int i;
306 306
307 307 for (i = 0; i < 2; i++) {
308 308 if (ifs->ifs_kstatp[i] != NULL) {
309 309 net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]);
310 310 ifs->ifs_kstatp[i] = NULL;
311 311 }
312 312 }
313 313 }
314 314
315 315
316 316 static int
317 317 ipf_kstat_update(kstat_t *ksp, int rwflag)
318 318 {
319 319 filter_kstats_t *fkp;
320 320 filterstats_t *fsp;
321 321
322 322 if (ksp == NULL || ksp->ks_data == NULL)
323 323 return (EIO);
324 324
325 325 if (rwflag == KSTAT_WRITE)
326 326 return (EACCES);
327 327
328 328 fkp = ksp->ks_data;
329 329 fsp = ksp->ks_private;
330 330
331 331 fkp->fks_pass.value.ul = fsp->fr_pass;
332 332 fkp->fks_block.value.ul = fsp->fr_block;
333 333 fkp->fks_nom.value.ul = fsp->fr_nom;
334 334 fkp->fks_short.value.ul = fsp->fr_short;
335 335 fkp->fks_ppkl.value.ul = fsp->fr_ppkl;
336 336 fkp->fks_bpkl.value.ul = fsp->fr_bpkl;
337 337 fkp->fks_npkl.value.ul = fsp->fr_npkl;
338 338 fkp->fks_pkl.value.ul = fsp->fr_pkl;
339 339 fkp->fks_skip.value.ul = fsp->fr_skip;
340 340 fkp->fks_ret.value.ul = fsp->fr_ret;
341 341 fkp->fks_acct.value.ul = fsp->fr_acct;
342 342 fkp->fks_bnfr.value.ul = fsp->fr_bnfr;
343 343 fkp->fks_nfr.value.ul = fsp->fr_nfr;
344 344 fkp->fks_cfr.value.ul = fsp->fr_cfr;
345 345 fkp->fks_bads.value.ul = fsp->fr_bads;
346 346 fkp->fks_ads.value.ul = fsp->fr_ads;
347 347 fkp->fks_chit.value.ul = fsp->fr_chit;
348 348 fkp->fks_tcpbad.value.ul = fsp->fr_tcpbad;
349 349 fkp->fks_pull[0].value.ul = fsp->fr_pull[0];
350 350 fkp->fks_pull[1].value.ul = fsp->fr_pull[1];
351 351 fkp->fks_badsrc.value.ul = fsp->fr_badsrc;
352 352 fkp->fks_badttl.value.ul = fsp->fr_badttl;
353 353 fkp->fks_bad.value.ul = fsp->fr_bad;
354 354 fkp->fks_ipv6.value.ul = fsp->fr_ipv6;
355 355 fkp->fks_ppshit.value.ul = fsp->fr_ppshit;
356 356 fkp->fks_ipud.value.ul = fsp->fr_ipud;
357 357
358 358 return (0);
359 359 }
360 360
361 361 int
362 362 _init()
363 363 {
364 364 int ipfinst;
365 365
366 366 ipfinst = mod_install(&modlink1);
367 367 #ifdef IPFDEBUG
368 368 cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
369 369 #endif
370 370 mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL);
371 371 return (ipfinst);
372 372 }
373 373
374 374
375 375 int
376 376 _fini(void)
377 377 {
378 378 int ipfinst;
379 379
380 380 ipfinst = mod_remove(&modlink1);
381 381 #ifdef IPFDEBUG
382 382 cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
383 383 #endif
384 384 return (ipfinst);
385 385 }
386 386
387 387
388 388 int
389 389 _info(modinfop)
390 390 struct modinfo *modinfop;
391 391 {
392 392 int ipfinst;
393 393
394 394 ipfinst = mod_info(&modlink1, modinfop);
395 395 #ifdef IPFDEBUG
396 396 cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst);
397 397 #endif
398 398 return (ipfinst);
399 399 }
400 400
401 401
402 402 #if SOLARIS2 < 10
403 403 static int ipf_identify(dip)
404 404 dev_info_t *dip;
405 405 {
406 406 #ifdef IPFDEBUG
407 407 cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip);
408 408 #endif
409 409 if (strcmp(ddi_get_name(dip), "ipf") == 0)
410 410 return (DDI_IDENTIFIED);
411 411 return (DDI_NOT_IDENTIFIED);
412 412 }
413 413 #endif
414 414
415 415 /*
416 416 * Initialize things for IPF for each stack instance
417 417 */
418 418 static void *
419 419 ipf_stack_create_one(const netid_t id, const zoneid_t zid, boolean_t from_gz,
420 420 ipf_stack_t *ifs_gz)
421 421 {
422 422 ipf_stack_t *ifs;
423 423
424 424 #ifdef IPFDEBUG
425 425 cmn_err(CE_NOTE, "IP Filter:stack_create_one id=%d global=%d", id,
426 426 global);
427 427 #endif
428 428
429 429 ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP);
430 430 bzero(ifs, sizeof (*ifs));
431 431
432 432 ifs->ifs_hook4_physical_in = B_FALSE;
433 433 ifs->ifs_hook4_physical_out = B_FALSE;
434 434 ifs->ifs_hook4_nic_events = B_FALSE;
435 435 ifs->ifs_hook4_loopback_in = B_FALSE;
436 436 ifs->ifs_hook4_loopback_out = B_FALSE;
437 437 ifs->ifs_hook6_physical_in = B_FALSE;
438 438 ifs->ifs_hook6_physical_out = B_FALSE;
439 439 ifs->ifs_hook6_nic_events = B_FALSE;
440 440 ifs->ifs_hook6_loopback_in = B_FALSE;
441 441 ifs->ifs_hook6_loopback_out = B_FALSE;
442 442
443 443 /*
444 444 * Initialize mutex's
445 445 */
446 446 RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
447 447 RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
448 448 RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock");
449 449 ifs->ifs_netid = id;
450 450 ifs->ifs_zone = zid;
451 451 ifs->ifs_gz_controlled = from_gz;
452 452 ifs->ifs_gz_cont_ifs = ifs_gz;
453 453
454 454 ipf_kstat_init(ifs, from_gz);
455 455
456 456 #ifdef IPFDEBUG
457 457 cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone);
458 458 #endif
459 459
460 460 /*
461 461 * Lock people out while we set things up.
462 462 */
463 463 WRITE_ENTER(&ifs->ifs_ipf_global);
464 464 ipftuneable_alloc(ifs);
465 465 RWLOCK_EXIT(&ifs->ifs_ipf_global);
466 466
467 467 /* Limit to global stack */
468 468 if (ifs->ifs_zone == GLOBAL_ZONEID)
469 469 cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
470 470
471 471 mutex_enter(&ipf_stack_lock);
472 472 if (ipf_stacks != NULL)
473 473 ipf_stacks->ifs_pnext = &ifs->ifs_next;
474 474 ifs->ifs_next = ipf_stacks;
475 475 ifs->ifs_pnext = &ipf_stacks;
476 476 ipf_stacks = ifs;
477 477 mutex_exit(&ipf_stack_lock);
478 478
479 479 return (ifs);
480 480 }
481 481
482 482 static void *
483 483 ipf_stack_create(const netid_t id)
484 484 {
485 485 ipf_stack_t *ifs = NULL;
486 486 zoneid_t zid = net_getzoneidbynetid(id);
487 487
488 488 /*
489 489 * Create two ipfilter stacks for a zone - the first can only be
490 490 * controlled from the global zone, and the second is owned by
491 491 * the zone itself. There is no need to create a GZ-controlled
492 492 * stack for the global zone, since we're already in the global
493 493 * zone. See the "GZ-controlled and per-zone stacks" comment block in
494 494 * ip_fil_solaris.c for details.
495 495 */
496 496 if (zid != GLOBAL_ZONEID)
497 497 ifs = ipf_stack_create_one(id, zid, B_TRUE, NULL);
498 498
499 499 return (ipf_stack_create_one(id, zid, B_FALSE, ifs));
500 500 }
501 501
502 502 /*
503 503 * Find an ipfilter stack for the given zone. Return the GZ-controlled or
504 504 * per-zone stack if set by an earlier SIOCIPFZONESET ioctl call. See the
505 505 * "GZ-controlled and per-zone stacks" comment block in ip_fil_solaris.c for
506 506 * details.
507 507 *
508 508 * This function returns with the ipf_stack_t's ifs_ipf_global
509 509 * read lock held (if the stack is found). See the "ipfilter kernel module
510 510 * mutexes and locking" comment block at the top of this file.
511 511 */
512 512 ipf_stack_t *
513 513 ipf_find_stack(const zoneid_t orig_zone, ipf_devstate_t *isp)
514 514 {
515 515 ipf_stack_t *ifs;
516 516 boolean_t gz_stack;
517 517 zoneid_t zone;
518 518
519 519 /*
520 520 * If we're in the GZ, determine if we're acting on a zone's stack,
521 521 * and whether or not that stack is the GZ-controlled or in-zone
522 522 * one. See the "GZ and per-zone stacks" note at the top of this
523 523 * file.
524 524 */
525 525 if (orig_zone == GLOBAL_ZONEID &&
526 526 (isp->ipfs_zoneid != IPFS_ZONE_UNSET)) {
527 527 /* Global zone, and we've set the zoneid for this fd already */
528 528
529 529 if (orig_zone == isp->ipfs_zoneid) {
530 530 /* There's only a per-zone stack for the GZ */
531 531 gz_stack = B_FALSE;
532 532 } else {
533 533 gz_stack = isp->ipfs_gz;
534 534 }
535 535
536 536 zone = isp->ipfs_zoneid;
537 537 } else {
538 538 /*
539 539 * Non-global zone or GZ without having set a zoneid: act on
540 540 * the per-zone stack of the zone that this ioctl originated
541 541 * from.
542 542 */
543 543 gz_stack = B_FALSE;
544 544 zone = orig_zone;
545 545 }
546 546
547 547 mutex_enter(&ipf_stack_lock);
548 548 for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) {
549 549 if (ifs->ifs_zone == zone && ifs->ifs_gz_controlled == gz_stack)
550 550 break;
551 551 }
552 552
553 553 if (ifs != NULL) {
554 554 READ_ENTER(&ifs->ifs_ipf_global);
555 555 }
556 556 mutex_exit(&ipf_stack_lock);
557 557 return (ifs);
558 558 }
559 559
560 560 static int ipf_detach_check_zone(ipf_stack_t *ifs)
561 561 {
562 562 /*
563 563 * Make sure we're the only one's modifying things. With
564 564 * this lock others should just fall out of the loop.
565 565 */
566 566 READ_ENTER(&ifs->ifs_ipf_global);
567 567 if (ifs->ifs_fr_running == 1) {
568 568 RWLOCK_EXIT(&ifs->ifs_ipf_global);
569 569 return (-1);
570 570 }
571 571
572 572 /*
573 573 * Make sure there is no active filter rule.
574 574 */
575 575 if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] ||
576 576 ifs->ifs_ipfilter[1][ifs->ifs_fr_active] ||
577 577 ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] ||
578 578 ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) {
579 579 RWLOCK_EXIT(&ifs->ifs_ipf_global);
580 580 return (-1);
581 581 }
582 582
583 583 RWLOCK_EXIT(&ifs->ifs_ipf_global);
584 584
585 585 return (0);
586 586 }
587 587
588 588
589 589 static int ipf_detach_check_all()
590 590 {
591 591 ipf_stack_t *ifs;
592 592
593 593 mutex_enter(&ipf_stack_lock);
594 594 for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next)
595 595 if (ipf_detach_check_zone(ifs) != 0)
596 596 break;
597 597 mutex_exit(&ipf_stack_lock);
598 598 return ((ifs == NULL) ? 0 : -1);
599 599 }
600 600
601 601
602 602 /*
603 603 * Remove ipf kstats for both the per-zone ipf stack and the
604 604 * GZ-controlled stack for the same zone, if it exists.
605 605 */
606 606 /* ARGSUSED */
607 607 static void
608 608 ipf_stack_shutdown(const netid_t id, void *arg)
609 609 {
610 610 ipf_stack_t *ifs = (ipf_stack_t *)arg;
611 611
612 612 /*
613 613 * The GZ-controlled stack
614 614 */
615 615 if (ifs->ifs_gz_cont_ifs != NULL)
616 616 ipf_kstat_fini(ifs->ifs_gz_cont_ifs);
617 617
618 618 /*
619 619 * The per-zone stack
620 620 */
621 621 ipf_kstat_fini(ifs);
622 622 }
623 623
624 624
625 625 /*
626 626 * Destroy things for ipf for one stack.
627 627 */
628 628 /* ARGSUSED */
629 629 static void
630 630 ipf_stack_destroy_one(const netid_t id, ipf_stack_t *ifs)
631 631 {
632 632 timeout_id_t tid;
633 633
634 634 #ifdef IPFDEBUG
635 635 (void) printf("ipf_stack_destroy_one(%p)\n", (void *)ifs);
636 636 #endif
637 637
638 638 /*
639 639 * Make sure we're the only one's modifying things. With
640 640 * this lock others should just fall out of the loop.
641 641 */
642 642 WRITE_ENTER(&ifs->ifs_ipf_global);
643 643 if (ifs->ifs_fr_running == -2) {
644 644 RWLOCK_EXIT(&ifs->ifs_ipf_global);
645 645 return;
646 646 }
647 647 ifs->ifs_fr_running = -2;
648 648 tid = ifs->ifs_fr_timer_id;
649 649 ifs->ifs_fr_timer_id = NULL;
650 650 RWLOCK_EXIT(&ifs->ifs_ipf_global);
651 651
652 652 mutex_enter(&ipf_stack_lock);
653 653 if (ifs->ifs_next != NULL)
654 654 ifs->ifs_next->ifs_pnext = ifs->ifs_pnext;
655 655 *ifs->ifs_pnext = ifs->ifs_next;
656 656 mutex_exit(&ipf_stack_lock);
657 657
658 658 if (tid != NULL)
659 659 (void) untimeout(tid);
660 660
661 661 WRITE_ENTER(&ifs->ifs_ipf_global);
662 662 if (ipldetach(ifs) != 0) {
663 663 printf("ipf_stack_destroy_one: ipldetach failed\n");
664 664 }
665 665
666 666 ipftuneable_free(ifs);
667 667
668 668 RWLOCK_EXIT(&ifs->ifs_ipf_global);
669 669 RW_DESTROY(&ifs->ifs_ipf_mutex);
670 670 RW_DESTROY(&ifs->ifs_ipf_frcache);
671 671 RW_DESTROY(&ifs->ifs_ipf_global);
672 672
673 673 KFREE(ifs);
674 674 }
675 675
676 676
677 677 /*
678 678 * Destroy things for ipf for both the per-zone ipf stack and the
679 679 * GZ-controlled stack for the same zone, if it exists. See the "GZ-controlled
680 680 * and per-zone stacks" comment block in ip_fil_solaris.c for details.
681 681 */
682 682 /* ARGSUSED */
683 683 static void
684 684 ipf_stack_destroy(const netid_t id, void *arg)
685 685 {
686 686 ipf_stack_t *ifs = (ipf_stack_t *)arg;
687 687
688 688 /*
689 689 * The GZ-controlled stack
690 690 */
691 691 if (ifs->ifs_gz_cont_ifs != NULL)
692 692 ipf_stack_destroy_one(id, ifs->ifs_gz_cont_ifs);
693 693
694 694 /*
695 695 * The per-zone stack
696 696 */
697 697 ipf_stack_destroy_one(id, ifs);
698 698 }
699 699
700 700
701 701 static int ipf_attach(dip, cmd)
702 702 dev_info_t *dip;
703 703 ddi_attach_cmd_t cmd;
704 704 {
705 705 char *s;
706 706 int i;
707 707 int instance;
708 708
709 709 #ifdef IPFDEBUG
710 710 cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd);
711 711 #endif
712 712
713 713 switch (cmd)
714 714 {
715 715 case DDI_ATTACH:
716 716 instance = ddi_get_instance(dip);
717 717 /* Only one instance of ipf (instance 0) can be attached. */
718 718 if (instance > 0)
719 719 return (DDI_FAILURE);
720 720
721 721 #ifdef IPFDEBUG
722 722 cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance);
723 723 #endif
724 724
725 725 (void) ipf_property_g_update(dip);
726 726
727 727 if (ddi_soft_state_init(&ipf_state, sizeof (ipf_devstate_t), 1)
728 728 != 0) {
729 729 ddi_prop_remove_all(dip);
730 730 return (DDI_FAILURE);
731 731 }
732 732
733 733 for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
734 734 s = strrchr(s, '/');
735 735 if (s == NULL)
736 736 continue;
737 737 s++;
738 738 if (ddi_create_minor_node(dip, s, S_IFCHR, i,
739 739 DDI_PSEUDO, 0) == DDI_FAILURE)
740 740 goto attach_failed;
741 741 }
742 742
743 743 ipf_dev_info = dip;
744 744
745 745 ipfncb = net_instance_alloc(NETINFO_VERSION);
746 746 if (ipfncb == NULL)
747 747 goto attach_failed;
748 748
749 749 ipfncb->nin_name = "ipf";
750 750 ipfncb->nin_create = ipf_stack_create;
751 751 ipfncb->nin_destroy = ipf_stack_destroy;
752 752 ipfncb->nin_shutdown = ipf_stack_shutdown;
753 753 if (net_instance_register(ipfncb) == DDI_FAILURE) {
754 754 net_instance_free(ipfncb);
755 755 goto attach_failed;
756 756 }
757 757
758 758 ipf_minor = vmem_create("ipf_minor", (void *)1, UINT32_MAX - 1,
759 759 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
760 760
761 761 #ifdef IPFDEBUG
762 762 cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
763 763 #endif
764 764
765 765 return (DDI_SUCCESS);
766 766 /* NOTREACHED */
767 767 default:
768 768 break;
769 769 }
770 770
771 771 attach_failed:
772 772 ddi_remove_minor_node(dip, NULL);
773 773 ddi_prop_remove_all(dip);
774 774 ddi_soft_state_fini(&ipf_state);
775 775 return (DDI_FAILURE);
776 776 }
777 777
778 778
779 779 static int ipf_detach(dip, cmd)
780 780 dev_info_t *dip;
781 781 ddi_detach_cmd_t cmd;
782 782 {
783 783 int i;
784 784
785 785 #ifdef IPFDEBUG
786 786 cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
787 787 #endif
788 788 switch (cmd) {
789 789 case DDI_DETACH:
790 790 if (ipf_detach_check_all() != 0)
791 791 return (DDI_FAILURE);
792 792
793 793 /*
794 794 * Undo what we did in ipf_attach, freeing resources
795 795 * and removing things we installed. The system
796 796 * framework guarantees we are not active with this devinfo
797 797 * node in any other entry points at this time.
798 798 */
799 799 ddi_prop_remove_all(dip);
800 800 i = ddi_get_instance(dip);
801 801 ddi_remove_minor_node(dip, NULL);
802 802 if (i > 0) {
803 803 cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
804 804 return (DDI_FAILURE);
805 805 }
806 806
807 807 vmem_destroy(ipf_minor);
808 808 ddi_soft_state_fini(&ipf_state);
809 809
810 810 (void) net_instance_unregister(ipfncb);
811 811 net_instance_free(ipfncb);
812 812
813 813 return (DDI_SUCCESS);
814 814 /* NOTREACHED */
815 815 default:
816 816 break;
817 817 }
818 818 cmn_err(CE_NOTE, "IP Filter: failed to detach\n");
819 819 return (DDI_FAILURE);
820 820 }
821 821
822 822
823 823 /*ARGSUSED*/
824 824 static int ipf_getinfo(dip, infocmd, arg, result)
825 825 dev_info_t *dip;
826 826 ddi_info_cmd_t infocmd;
827 827 void *arg, **result;
828 828 {
829 829 int error;
830 830
831 831 error = DDI_FAILURE;
832 832 #ifdef IPFDEBUG
833 833 cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg);
834 834 #endif
835 835 switch (infocmd) {
836 836 case DDI_INFO_DEVT2DEVINFO:
837 837 *result = ipf_dev_info;
838 838 error = DDI_SUCCESS;
839 839 break;
840 840 case DDI_INFO_DEVT2INSTANCE:
841 841 *result = (void *)0;
842 842 error = DDI_SUCCESS;
843 843 break;
844 844 default:
845 845 break;
846 846 }
847 847 return (error);
848 848 }
849 849
850 850
851 851 /*
852 852 * Fetch configuration file values that have been entered into the ipf.conf
853 853 * driver file.
854 854 */
855 855 static int ipf_property_g_update(dip)
856 856 dev_info_t *dip;
857 857 {
858 858 #ifdef DDI_NO_AUTODETACH
859 859 if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
860 860 DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) {
861 861 cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed");
862 862 return (DDI_FAILURE);
863 863 }
864 864 #else
865 865 if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
866 866 "ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) {
867 867 cmn_err(CE_WARN, "!updating ddi-no-autodetach failed");
868 868 return (DDI_FAILURE);
869 869 }
870 870 #endif
871 871
872 872 return (DDI_SUCCESS);
873 873 }
874 874
875 875 int
876 876 ipf_property_update(dip, ifs)
877 877 dev_info_t *dip;
878 878 ipf_stack_t *ifs;
879 879 {
880 880 ipftuneable_t *ipft;
881 881 char *name;
882 882 uint_t one;
883 883 int *i32p;
884 884 int err, rv = 0;
885 885
886 886 for (ipft = ifs->ifs_ipf_tuneables;
887 887 (name = ipft->ipft_name) != NULL; ipft++) {
888 888 one = 1;
889 889 i32p = NULL;
890 890 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
891 891 0, name, &i32p, &one);
892 892 if (err == DDI_PROP_NOT_FOUND)
893 893 continue;
894 894 #ifdef IPFDEBUG
895 895 cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
896 896 name, err);
897 897 #endif
898 898 if (err != DDI_PROP_SUCCESS) {
899 899 rv = err;
900 900 continue;
901 901 }
902 902
903 903 if (*i32p >= ipft->ipft_min &&
904 904 *i32p <= ipft->ipft_max) {
905 905 if (ipft->ipft_sz == sizeof (uint32_t)) {
906 906 *ipft->ipft_pint = *i32p;
907 907 } else if (ipft->ipft_sz == sizeof (uint64_t)) {
908 908 *ipft->ipft_plong = *i32p;
909 909 }
910 910 }
911 911
912 912 ddi_prop_free(i32p);
913 913 }
914 914
915 915 return (rv);
916 916 }
↓ open down ↓ |
734 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX