Print this page
OS-406
OS-249
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/dld/dld_drv.c
+++ new/usr/src/uts/common/io/dld/dld_drv.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright (c) 2011, Joyent Inc. All rights reserved.
23 24 */
24 25
25 26 /*
26 27 * Data-Link Driver
27 28 */
28 29
29 30 #include <sys/conf.h>
30 31 #include <sys/mkdev.h>
31 32 #include <sys/modctl.h>
32 33 #include <sys/stat.h>
33 34 #include <sys/dld_impl.h>
34 35 #include <sys/dld_ioc.h>
35 36 #include <sys/dls_impl.h>
36 37 #include <sys/softmac.h>
37 38 #include <sys/mac.h>
38 39 #include <sys/mac_ether.h>
39 40 #include <sys/mac_client.h>
40 41 #include <sys/mac_client_impl.h>
41 42 #include <sys/mac_client_priv.h>
42 43 #include <inet/common.h>
43 44 #include <sys/policy.h>
44 45 #include <sys/priv_names.h>
45 46 #include <sys/zone.h>
46 47 #include <sys/sysmacros.h>
47 48
48 49 static void drv_init(void);
49 50 static int drv_fini(void);
50 51
51 52 static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
52 53 static int drv_attach(dev_info_t *, ddi_attach_cmd_t);
53 54 static int drv_detach(dev_info_t *, ddi_detach_cmd_t);
54 55
55 56 /*
56 57 * Secure objects declarations
57 58 */
58 59 #define SECOBJ_WEP_HASHSZ 67
59 60 static krwlock_t drv_secobj_lock;
60 61 static kmem_cache_t *drv_secobj_cachep;
61 62 static mod_hash_t *drv_secobj_hash;
62 63 static void drv_secobj_init(void);
63 64 static void drv_secobj_fini(void);
64 65 static int drv_ioc_setap(datalink_id_t, struct dlautopush *);
65 66 static int drv_ioc_getap(datalink_id_t, struct dlautopush *);
66 67 static int drv_ioc_clrap(datalink_id_t);
67 68
68 69
69 70 /*
70 71 * The following entry points are private to dld and are used for control
71 72 * operations only. The entry points exported to mac drivers are defined
72 73 * in dld_str.c. Refer to the comment on top of dld_str.c for details.
73 74 */
74 75 static int drv_open(dev_t *, int, int, cred_t *);
75 76 static int drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
76 77
77 78 static dev_info_t *dld_dip; /* dev_info_t for the driver */
78 79 uint32_t dld_opt = 0; /* Global options */
79 80
80 81 #define NAUTOPUSH 32
81 82 static mod_hash_t *dld_ap_hashp;
82 83 static krwlock_t dld_ap_hash_lock;
83 84
84 85 static struct cb_ops drv_cb_ops = {
85 86 drv_open, /* open */
86 87 nulldev, /* close */
87 88 nulldev, /* strategy */
88 89 nulldev, /* print */
89 90 nodev, /* dump */
90 91 nodev, /* read */
91 92 nodev, /* write */
92 93 drv_ioctl, /* ioctl */
93 94 nodev, /* devmap */
94 95 nodev, /* mmap */
95 96 nodev, /* segmap */
96 97 nochpoll, /* poll */
97 98 ddi_prop_op, /* cb_prop_op */
98 99 0, /* streamtab */
99 100 D_MP /* Driver compatibility flag */
100 101 };
101 102
102 103 static struct dev_ops drv_ops = {
103 104 DEVO_REV, /* devo_rev */
104 105 0, /* refcnt */
105 106 drv_getinfo, /* get_dev_info */
106 107 nulldev, /* identify */
107 108 nulldev, /* probe */
108 109 drv_attach, /* attach */
109 110 drv_detach, /* detach */
110 111 nodev, /* reset */
111 112 &drv_cb_ops, /* driver operations */
112 113 NULL, /* bus operations */
113 114 nodev, /* dev power */
114 115 ddi_quiesce_not_supported, /* dev quiesce */
115 116 };
116 117
117 118 /*
118 119 * Module linkage information for the kernel.
119 120 */
120 121 static struct modldrv drv_modldrv = {
121 122 &mod_driverops,
122 123 DLD_INFO,
123 124 &drv_ops
124 125 };
125 126
126 127 static struct modlinkage drv_modlinkage = {
127 128 MODREV_1,
128 129 &drv_modldrv,
129 130 NULL
130 131 };
131 132
132 133 int
133 134 _init(void)
134 135 {
135 136 return (mod_install(&drv_modlinkage));
136 137 }
137 138
138 139 int
139 140 _fini(void)
140 141 {
141 142 return (mod_remove(&drv_modlinkage));
142 143 }
143 144
144 145 int
145 146 _info(struct modinfo *modinfop)
146 147 {
147 148 return (mod_info(&drv_modlinkage, modinfop));
148 149 }
149 150
150 151 /*
151 152 * Initialize component modules.
152 153 */
153 154 static void
154 155 drv_init(void)
155 156 {
156 157 drv_secobj_init();
157 158 dld_str_init();
158 159
159 160 /*
160 161 * Create a hash table for autopush configuration.
161 162 */
162 163 dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash",
163 164 NAUTOPUSH, mod_hash_null_valdtor);
164 165
165 166 ASSERT(dld_ap_hashp != NULL);
166 167 rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL);
167 168 }
168 169
169 170 /* ARGSUSED */
170 171 static uint_t
171 172 drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
172 173 {
173 174 boolean_t *pexist = arg;
174 175
175 176 *pexist = B_TRUE;
176 177 return (MH_WALK_TERMINATE);
177 178 }
178 179
179 180 static int
180 181 drv_fini(void)
181 182 {
182 183 int err;
183 184 boolean_t exist = B_FALSE;
184 185
185 186 rw_enter(&dld_ap_hash_lock, RW_READER);
186 187 mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist);
187 188 rw_exit(&dld_ap_hash_lock);
188 189 if (exist)
189 190 return (EBUSY);
190 191
191 192 if ((err = dld_str_fini()) != 0)
192 193 return (err);
193 194
194 195 drv_secobj_fini();
195 196 mod_hash_destroy_idhash(dld_ap_hashp);
196 197 rw_destroy(&dld_ap_hash_lock);
197 198 return (0);
198 199 }
199 200
200 201 /*
201 202 * devo_getinfo: getinfo(9e)
202 203 */
203 204 /*ARGSUSED*/
204 205 static int
205 206 drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
206 207 {
207 208 if (dld_dip == NULL)
208 209 return (DDI_FAILURE);
209 210
210 211 switch (cmd) {
211 212 case DDI_INFO_DEVT2INSTANCE:
212 213 *resp = 0;
213 214 break;
214 215 case DDI_INFO_DEVT2DEVINFO:
215 216 *resp = dld_dip;
216 217 break;
217 218 default:
218 219 return (DDI_FAILURE);
219 220 }
220 221
221 222 return (DDI_SUCCESS);
222 223 }
223 224
224 225 /*
225 226 * Check properties to set options. (See dld.h for property definitions).
226 227 */
227 228 static void
228 229 drv_set_opt(dev_info_t *dip)
229 230 {
230 231 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
231 232 DLD_PROP_NO_FASTPATH, 0) != 0) {
232 233 dld_opt |= DLD_OPT_NO_FASTPATH;
233 234 }
234 235
235 236 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
236 237 DLD_PROP_NO_POLL, 0) != 0) {
237 238 dld_opt |= DLD_OPT_NO_POLL;
238 239 }
239 240
240 241 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
241 242 DLD_PROP_NO_ZEROCOPY, 0) != 0) {
242 243 dld_opt |= DLD_OPT_NO_ZEROCOPY;
243 244 }
244 245
245 246 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
246 247 DLD_PROP_NO_SOFTRING, 0) != 0) {
247 248 dld_opt |= DLD_OPT_NO_SOFTRING;
248 249 }
249 250 }
250 251
251 252 /*
252 253 * devo_attach: attach(9e)
253 254 */
254 255 static int
255 256 drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
256 257 {
257 258 if (cmd != DDI_ATTACH)
258 259 return (DDI_FAILURE);
259 260
260 261 ASSERT(ddi_get_instance(dip) == 0);
261 262 drv_init();
262 263 drv_set_opt(dip);
263 264
264 265 /*
265 266 * Create control node. DLPI provider nodes will be created on demand.
266 267 */
267 268 if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
268 269 DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
269 270 return (DDI_FAILURE);
270 271
271 272 dld_dip = dip;
272 273
273 274 /*
274 275 * Log the fact that the driver is now attached.
275 276 */
276 277 ddi_report_dev(dip);
277 278 return (DDI_SUCCESS);
278 279 }
279 280
280 281 /*
281 282 * devo_detach: detach(9e)
282 283 */
283 284 static int
284 285 drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
285 286 {
286 287 if (cmd != DDI_DETACH)
287 288 return (DDI_FAILURE);
288 289
289 290 ASSERT(dld_dip == dip);
290 291 if (drv_fini() != 0)
291 292 return (DDI_FAILURE);
292 293
293 294 /*
294 295 * Remove the control node.
295 296 */
296 297 ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
297 298 dld_dip = NULL;
298 299
299 300 return (DDI_SUCCESS);
300 301 }
301 302
302 303 /*
303 304 * dld control node open procedure.
304 305 */
305 306 /*ARGSUSED*/
306 307 static int
307 308 drv_open(dev_t *devp, int flag, int sflag, cred_t *credp)
308 309 {
309 310 /*
310 311 * Only the control node can be opened.
311 312 */
312 313 if (getminor(*devp) != DLD_CONTROL_MINOR)
313 314 return (ENODEV);
314 315 return (0);
315 316 }
316 317
317 318 /*
318 319 * Verify if the caller is allowed to modify a link of the given class.
319 320 */
320 321 static int
321 322 drv_ioc_checkprivs(datalink_class_t class, cred_t *cred)
322 323 {
323 324 if (class == DATALINK_CLASS_IPTUN)
324 325 return (secpolicy_iptun_config(cred));
325 326 return (secpolicy_dl_config(cred));
326 327 }
327 328
328 329 /*
329 330 * DLDIOC_ATTR
330 331 */
331 332 /* ARGSUSED */
332 333 static int
333 334 drv_ioc_attr(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
334 335 {
335 336 dld_ioc_attr_t *diap = karg;
336 337 dls_dl_handle_t dlh;
337 338 dls_link_t *dlp;
338 339 zoneid_t zoneid = crgetzoneid(cred);
339 340 int err;
340 341 mac_perim_handle_t mph;
341 342
342 343 if (zoneid != GLOBAL_ZONEID &&
343 344 zone_check_datalink(&zoneid, diap->dia_linkid) != 0)
344 345 return (ENOENT);
345 346
346 347 if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0)
347 348 return (err);
348 349
349 350 if ((err = mac_perim_enter_by_macname(
350 351 dls_devnet_mac(dlh), &mph)) != 0) {
351 352 dls_devnet_rele_tmp(dlh);
352 353 return (err);
353 354 }
354 355
355 356 if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) {
356 357 mac_perim_exit(mph);
357 358 dls_devnet_rele_tmp(dlh);
358 359 return (err);
359 360 }
360 361
361 362 mac_sdu_get(dlp->dl_mh, NULL, &diap->dia_max_sdu);
362 363
363 364 dls_link_rele(dlp);
364 365 mac_perim_exit(mph);
365 366 dls_devnet_rele_tmp(dlh);
366 367
367 368 return (0);
368 369 }
369 370
370 371 /*
371 372 * DLDIOC_PHYS_ATTR
372 373 */
373 374 /* ARGSUSED */
374 375 static int
375 376 drv_ioc_phys_attr(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
376 377 {
377 378 dld_ioc_phys_attr_t *dipp = karg;
378 379 int err;
379 380 dls_dl_handle_t dlh;
380 381 dls_dev_handle_t ddh;
381 382 dev_t phydev;
382 383 zoneid_t zoneid = crgetzoneid(cred);
383 384
384 385 if (zoneid != GLOBAL_ZONEID &&
385 386 zone_check_datalink(&zoneid, dipp->dip_linkid) != 0)
386 387 return (ENOENT);
387 388
388 389 /*
389 390 * Every physical link should have its physical dev_t kept in the
390 391 * daemon. If not, it is not a valid physical link.
391 392 */
392 393 if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0)
393 394 return (EINVAL);
394 395
395 396 /*
396 397 * Although this is a valid physical link, it might already be removed
397 398 * by DR or during system shutdown. softmac_hold_device() would return
398 399 * ENOENT in this case.
399 400 */
400 401 if ((err = softmac_hold_device(phydev, &ddh)) != 0)
401 402 return (err);
402 403
403 404 if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) {
404 405 /*
405 406 * Although this is an active physical link, its link type is
406 407 * not supported by GLDv3, and therefore it does not have
407 408 * vanity naming support.
408 409 */
409 410 dipp->dip_novanity = B_TRUE;
410 411 } else {
411 412 dipp->dip_novanity = B_FALSE;
412 413 dls_devnet_rele_tmp(dlh);
413 414 }
414 415 /*
415 416 * Get the physical device name from the major number and the instance
416 417 * number derived from phydev.
417 418 */
418 419 (void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d",
419 420 ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1);
420 421
421 422 softmac_rele_device(ddh);
422 423 return (0);
423 424 }
424 425
425 426 /* ARGSUSED */
426 427 static int
427 428 drv_ioc_hwgrpget(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
428 429 {
429 430 dld_ioc_hwgrpget_t *hwgrpp = karg;
430 431 dld_hwgrpinfo_t hwgrp, *hip;
431 432 mac_handle_t mh = NULL;
432 433 int i, err, rgrpnum, tgrpnum;
433 434 uint_t bytes_left;
434 435 int totgrps = 0;
435 436 zoneid_t zoneid = crgetzoneid(cred);
436 437
437 438 if (zoneid != GLOBAL_ZONEID &&
438 439 zone_check_datalink(&zoneid, hwgrpp->dih_linkid) != 0)
439 440 return (ENOENT);
440 441
441 442 hwgrpp->dih_n_groups = 0;
442 443 err = mac_open_by_linkid(hwgrpp->dih_linkid, &mh);
443 444 if (err != 0)
444 445 goto done;
445 446
446 447 hip = (dld_hwgrpinfo_t *)
447 448 ((uchar_t *)arg + sizeof (dld_ioc_hwgrpget_t));
448 449 bytes_left = hwgrpp->dih_size;
449 450
450 451 rgrpnum = mac_hwgrp_num(mh, MAC_RING_TYPE_RX);
451 452 /* display the default group information first */
452 453 if (rgrpnum > 0) {
453 454 if (sizeof (dld_hwgrpinfo_t) > bytes_left) {
454 455 err = ENOSPC;
455 456 goto done;
456 457 }
457 458
458 459 bzero(&hwgrp, sizeof (hwgrp));
459 460 bcopy(mac_name(mh), hwgrp.dhi_link_name,
460 461 sizeof (hwgrp.dhi_link_name));
461 462 mac_get_hwrxgrp_info(mh, 0, &hwgrp.dhi_grp_num,
462 463 &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type,
463 464 &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts);
464 465 if (hwgrp.dhi_n_rings != 0) {
465 466 if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) {
466 467 err = EFAULT;
467 468 goto done;
468 469 }
469 470 }
470 471 hip++;
471 472 totgrps++;
472 473 bytes_left -= sizeof (dld_hwgrpinfo_t);
473 474 }
474 475
475 476 tgrpnum = mac_hwgrp_num(mh, MAC_RING_TYPE_TX);
476 477 /* display the default group information first */
477 478 if (tgrpnum > 0) {
478 479 if (sizeof (dld_hwgrpinfo_t) > bytes_left) {
479 480 err = ENOSPC;
480 481 goto done;
481 482 }
482 483
483 484 bzero(&hwgrp, sizeof (hwgrp));
484 485 bcopy(mac_name(mh), hwgrp.dhi_link_name,
485 486 sizeof (hwgrp.dhi_link_name));
486 487 mac_get_hwtxgrp_info(mh, tgrpnum - 1, &hwgrp.dhi_grp_num,
487 488 &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type,
488 489 &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts);
489 490 if (hwgrp.dhi_n_rings != 0) {
490 491 if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) {
491 492 err = EFAULT;
492 493 goto done;
493 494 }
494 495 }
495 496 hip++;
496 497 totgrps++;
497 498 bytes_left -= sizeof (dld_hwgrpinfo_t);
498 499 }
499 500
500 501 /* Rest of the rx groups */
501 502 for (i = 1; i < rgrpnum; i++) {
502 503 if (sizeof (dld_hwgrpinfo_t) > bytes_left) {
503 504 err = ENOSPC;
504 505 goto done;
505 506 }
506 507
507 508 bzero(&hwgrp, sizeof (hwgrp));
508 509 bcopy(mac_name(mh), hwgrp.dhi_link_name,
509 510 sizeof (hwgrp.dhi_link_name));
510 511 mac_get_hwrxgrp_info(mh, i, &hwgrp.dhi_grp_num,
511 512 &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type,
512 513 &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts);
513 514 if (hwgrp.dhi_n_rings == 0)
514 515 continue;
515 516 if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) {
516 517 err = EFAULT;
517 518 goto done;
518 519 }
519 520
520 521 hip++;
521 522 totgrps++;
522 523 bytes_left -= sizeof (dld_hwgrpinfo_t);
523 524 }
524 525
525 526 /* Rest of the tx group */
526 527 tgrpnum = mac_hwgrp_num(mh, MAC_RING_TYPE_TX);
527 528 for (i = 0; i < tgrpnum - 1; i++) {
528 529 if (sizeof (dld_hwgrpinfo_t) > bytes_left) {
529 530 err = ENOSPC;
530 531 goto done;
531 532 }
532 533
533 534 bzero(&hwgrp, sizeof (hwgrp));
534 535 bcopy(mac_name(mh), hwgrp.dhi_link_name,
535 536 sizeof (hwgrp.dhi_link_name));
536 537 mac_get_hwtxgrp_info(mh, i, &hwgrp.dhi_grp_num,
537 538 &hwgrp.dhi_n_rings, hwgrp.dhi_rings, &hwgrp.dhi_grp_type,
538 539 &hwgrp.dhi_n_clnts, hwgrp.dhi_clnts);
539 540 if (hwgrp.dhi_n_rings == 0)
540 541 continue;
541 542 if (copyout(&hwgrp, hip, sizeof (hwgrp)) != 0) {
542 543 err = EFAULT;
543 544 goto done;
544 545 }
545 546
546 547 hip++;
547 548 totgrps++;
548 549 bytes_left -= sizeof (dld_hwgrpinfo_t);
549 550 }
550 551
551 552 done:
552 553 if (mh != NULL)
553 554 dld_mac_close(mh);
554 555 if (err == 0)
555 556 hwgrpp->dih_n_groups = totgrps;
556 557 return (err);
557 558 }
558 559
559 560 /* ARGSUSED */
560 561 static int
561 562 drv_ioc_macaddrget(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
562 563 {
563 564 dld_ioc_macaddrget_t *magp = karg;
564 565 dld_macaddrinfo_t mai, *maip;
565 566 mac_handle_t mh = NULL;
566 567 int i, err;
567 568 uint_t bytes_left;
568 569 boolean_t is_used;
569 570 zoneid_t zoneid = crgetzoneid(cred);
570 571
571 572 if (zoneid != GLOBAL_ZONEID &&
572 573 zone_check_datalink(&zoneid, magp->dig_linkid) != 0)
573 574 return (ENOENT);
574 575
575 576 magp->dig_count = 0;
576 577 err = mac_open_by_linkid(magp->dig_linkid, &mh);
577 578 if (err != 0)
578 579 goto done;
579 580
580 581 maip = (dld_macaddrinfo_t *)
581 582 ((uchar_t *)arg + sizeof (dld_ioc_macaddrget_t));
582 583 bytes_left = magp->dig_size;
583 584
584 585 for (i = 0; i < mac_addr_factory_num(mh) + 1; i++) {
585 586 if (sizeof (dld_macaddrinfo_t) > bytes_left) {
586 587 err = ENOSPC;
587 588 goto done;
588 589 }
589 590
590 591 bzero(&mai, sizeof (mai));
591 592
592 593 if (i == 0) {
593 594 /* primary MAC address */
594 595 mac_unicast_primary_get(mh, mai.dmi_addr);
595 596 mai.dmi_addrlen = mac_addr_len(mh);
596 597 mac_unicast_primary_info(mh, mai.dmi_client_name,
597 598 &is_used);
598 599 } else {
599 600 /* factory MAC address slot */
600 601 mac_addr_factory_value(mh, i, mai.dmi_addr,
601 602 &mai.dmi_addrlen, mai.dmi_client_name, &is_used);
602 603 }
603 604
604 605 mai.dmi_slot = i;
605 606 if (is_used)
606 607 mai.dmi_flags |= DLDIOCMACADDR_USED;
607 608
608 609 if (copyout(&mai, maip, sizeof (mai)) != 0) {
609 610 err = EFAULT;
610 611 goto done;
611 612 }
612 613
613 614 maip++;
614 615 bytes_left -= sizeof (dld_macaddrinfo_t);
615 616 }
616 617
617 618 done:
618 619 if (mh != NULL)
619 620 dld_mac_close(mh);
620 621 if (err == 0)
621 622 magp->dig_count = mac_addr_factory_num(mh) + 1;
622 623 return (err);
623 624 }
624 625
625 626 /*
626 627 * DLDIOC_SET/GETMACPROP
627 628 */
628 629 static int
629 630 drv_ioc_prop_common(dld_ioc_macprop_t *prop, intptr_t arg, boolean_t set,
630 631 cred_t *cred, int mode)
631 632 {
632 633 int err = EINVAL;
633 634 dls_dl_handle_t dlh = NULL;
634 635 dls_link_t *dlp = NULL;
635 636 mac_perim_handle_t mph = NULL;
636 637 dld_ioc_macprop_t *kprop;
637 638 datalink_id_t linkid;
638 639 datalink_class_t class;
639 640 zoneid_t zoneid = crgetzoneid(cred);
640 641 uint_t dsize;
641 642
642 643 /*
643 644 * We only use pr_valsize from prop, as the caller only did a
644 645 * copyin() for sizeof (dld_ioc_prop_t), which doesn't cover
645 646 * the property data. We copyin the full dld_ioc_prop_t
646 647 * including the data into kprop down below.
647 648 */
648 649 dsize = sizeof (dld_ioc_macprop_t) + prop->pr_valsize - 1;
649 650 if (dsize < prop->pr_valsize)
650 651 return (EINVAL);
651 652
652 653 /*
653 654 * The property data is variable size, so we need to allocate
654 655 * a buffer for kernel use as this data was not part of the
655 656 * prop allocation and copyin() done by the framework.
656 657 */
657 658 if ((kprop = kmem_alloc(dsize, KM_NOSLEEP)) == NULL)
658 659 return (ENOMEM);
659 660
660 661 if (ddi_copyin((void *)arg, kprop, dsize, mode) != 0) {
661 662 err = EFAULT;
662 663 goto done;
663 664 }
664 665
665 666 linkid = kprop->pr_linkid;
666 667
667 668 if (set) {
668 669 if ((err = dls_mgmt_get_linkinfo(linkid, NULL, &class, NULL,
669 670 NULL)) != 0 || (err = drv_ioc_checkprivs(class, cred)) != 0)
670 671 goto done;
671 672 }
672 673
673 674 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
674 675 goto done;
675 676 if ((err = mac_perim_enter_by_macname(dls_devnet_mac(dlh), &mph)) != 0)
676 677 goto done;
677 678 if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0)
678 679 goto done;
679 680
680 681 /*
681 682 * Don't allow a process to get or set properties of a link if that
682 683 * link doesn't belong to that zone.
683 684 */
684 685 if (zoneid != dls_devnet_getownerzid(dlh)) {
685 686 err = ENOENT;
686 687 goto done;
687 688 }
688 689
689 690 if (!mac_prop_check_size(kprop->pr_num, kprop->pr_valsize,
690 691 kprop->pr_flags & DLD_PROP_POSSIBLE)) {
691 692 err = ENOBUFS;
692 693 goto done;
693 694 }
|
↓ open down ↓ |
661 lines elided |
↑ open up ↑ |
694 695
695 696 switch (kprop->pr_num) {
696 697 case MAC_PROP_ZONE:
697 698 if (set) {
698 699 dld_ioc_zid_t *dzp = (dld_ioc_zid_t *)kprop->pr_val;
699 700
700 701 if (zoneid != GLOBAL_ZONEID) {
701 702 err = EACCES;
702 703 goto done;
703 704 }
704 - err = dls_devnet_setzid(dlh, dzp->diz_zid);
705 + err = dls_devnet_setzid(dlh, dzp->diz_zid,
706 + dzp->diz_transient);
705 707 } else {
706 708 kprop->pr_perm_flags = MAC_PROP_PERM_RW;
707 709 (*(zoneid_t *)kprop->pr_val) = dls_devnet_getzid(dlh);
708 710 }
709 711 break;
710 712 case MAC_PROP_AUTOPUSH: {
711 713 struct dlautopush *dlap = (struct dlautopush *)kprop->pr_val;
712 714
713 715 if (set) {
714 716 if (kprop->pr_valsize != 0)
715 717 err = drv_ioc_setap(linkid, dlap);
716 718 else
717 719 err = drv_ioc_clrap(linkid);
718 720 } else {
719 721 if (kprop->pr_valsize == 0)
720 722 return (ENOBUFS);
721 723
722 724 kprop->pr_perm_flags = MAC_PROP_PERM_RW;
723 725 err = drv_ioc_getap(linkid, dlap);
724 726 }
725 727 break;
726 728 }
727 729 case MAC_PROP_TAGMODE:
728 730 if (set) {
729 731 link_tagmode_t mode = *(link_tagmode_t *)kprop->pr_val;
730 732
731 733 if (mode != LINK_TAGMODE_VLANONLY &&
732 734 mode != LINK_TAGMODE_NORMAL) {
733 735 err = EINVAL;
734 736 } else {
735 737 dlp->dl_tagmode = mode;
736 738 err = 0;
737 739 }
738 740 } else {
739 741 *(link_tagmode_t *)kprop->pr_val = dlp->dl_tagmode;
740 742 kprop->pr_perm_flags = MAC_PROP_PERM_RW;
741 743 err = 0;
742 744 }
743 745 break;
744 746 default: {
745 747 mac_propval_range_t *rangep = NULL;
746 748 void *default_val = NULL;
747 749 uint_t default_size = 0;
748 750
749 751 /* set a property value */
750 752 if (set) {
751 753 err = mac_set_prop(dlp->dl_mh, kprop->pr_num,
752 754 kprop->pr_name, kprop->pr_val, kprop->pr_valsize);
753 755 break;
754 756 }
755 757
756 758 /*
757 759 * Get the property value, default, or possible value
758 760 * depending on flags passed from the user.
759 761 */
760 762
761 763 /* a property has RW permissions by default */
762 764 kprop->pr_perm_flags = MAC_PROP_PERM_RW;
763 765
764 766 if (kprop->pr_flags & DLD_PROP_POSSIBLE) {
765 767 rangep = (mac_propval_range_t *)kprop->pr_val;
766 768
767 769 /*
768 770 * fail if rangep is not aligned to first
769 771 * member of mac_propval_range_t.
770 772 */
771 773 ASSERT(IS_P2ALIGNED(rangep, sizeof (uint_t)));
772 774 } else if (kprop->pr_flags & DLD_PROP_DEFAULT) {
773 775 default_val = kprop->pr_val;
774 776 default_size = kprop->pr_valsize;
775 777 }
776 778
777 779 /*
778 780 * Always return the permissions, and optionally return
779 781 * the default value or possible values range.
780 782 */
781 783 err = mac_prop_info(dlp->dl_mh, kprop->pr_num, kprop->pr_name,
782 784 default_val, default_size, rangep, &kprop->pr_perm_flags);
783 785 if (err != 0)
784 786 goto done;
785 787
786 788 if (default_val == NULL && rangep == NULL) {
787 789 err = mac_get_prop(dlp->dl_mh, kprop->pr_num,
788 790 kprop->pr_name, kprop->pr_val, kprop->pr_valsize);
789 791 }
790 792 }
791 793 }
792 794
793 795 done:
794 796 if (!set && ddi_copyout(kprop, (void *)arg, dsize, mode) != 0)
795 797 err = EFAULT;
796 798
797 799 if (dlp != NULL)
798 800 dls_link_rele(dlp);
799 801
800 802 if (mph != NULL) {
801 803 int32_t cpuid;
802 804 void *mdip = NULL;
803 805
804 806 if (dlp != NULL && set && err == 0) {
805 807 cpuid = mac_client_intr_cpu(dlp->dl_mch);
806 808 mdip = mac_get_devinfo(dlp->dl_mh);
807 809 }
808 810
809 811 mac_perim_exit(mph);
810 812
811 813 if (mdip != NULL && cpuid != -1)
812 814 mac_client_set_intr_cpu(mdip, dlp->dl_mch, cpuid);
813 815 }
814 816
815 817 if (dlh != NULL)
816 818 dls_devnet_rele_tmp(dlh);
817 819
818 820 if (kprop != NULL)
819 821 kmem_free(kprop, dsize);
820 822 return (err);
821 823 }
822 824
823 825 /* ARGSUSED */
824 826 static int
825 827 drv_ioc_setprop(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
826 828 {
827 829 return (drv_ioc_prop_common(karg, arg, B_TRUE, cred, mode));
828 830 }
829 831
830 832 /* ARGSUSED */
831 833 static int
832 834 drv_ioc_getprop(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
833 835 {
834 836 return (drv_ioc_prop_common(karg, arg, B_FALSE, cred, mode));
835 837 }
836 838
837 839 /*
838 840 * DLDIOC_RENAME.
839 841 *
840 842 * This function handles two cases of link renaming. See more in comments above
841 843 * dls_datalink_rename().
842 844 */
843 845 /* ARGSUSED */
844 846 static int
845 847 drv_ioc_rename(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
846 848 {
847 849 dld_ioc_rename_t *dir = karg;
848 850 mod_hash_key_t key;
849 851 mod_hash_val_t val;
850 852 zoneid_t zoneid = crgetzoneid(cred);
851 853 datalink_class_t class;
852 854 int err;
853 855
854 856 if (zoneid != GLOBAL_ZONEID &&
855 857 (zone_check_datalink(&zoneid, dir->dir_linkid1) != 0 ||
856 858 dir->dir_linkid2 != DATALINK_INVALID_LINKID &&
857 859 zone_check_datalink(&zoneid, dir->dir_linkid2) != 0))
|
↓ open down ↓ |
143 lines elided |
↑ open up ↑ |
858 860 return (ENOENT);
859 861
860 862 if ((err = dls_mgmt_get_linkinfo(dir->dir_linkid1, NULL, &class, NULL,
861 863 NULL)) != 0)
862 864 return (err);
863 865
864 866 if ((err = drv_ioc_checkprivs(class, cred)) != 0)
865 867 return (err);
866 868
867 869 if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2,
868 - dir->dir_link)) != 0)
870 + dir->dir_link, dir->dir_zoneinit)) != 0)
869 871 return (err);
870 872
871 873 if (dir->dir_linkid2 == DATALINK_INVALID_LINKID)
872 874 return (0);
873 875
874 876 /*
875 877 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this
876 878 * renaming request is to rename a valid physical link (dir_linkid1)
877 879 * to a "removed" physical link (dir_linkid2, which is removed by DR
878 880 * or during system shutdown). In this case, the link (specified by
879 881 * dir_linkid1) would inherit all the configuration of dir_linkid2,
880 882 * and dir_linkid1 and its configuration would be lost.
881 883 *
882 884 * Remove per-link autopush configuration of dir_linkid1 in this case.
883 885 */
884 886 key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1;
885 887 rw_enter(&dld_ap_hash_lock, RW_WRITER);
886 888 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) {
887 889 rw_exit(&dld_ap_hash_lock);
888 890 return (0);
889 891 }
890 892
891 893 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0);
892 894 kmem_free(val, sizeof (dld_ap_t));
893 895 rw_exit(&dld_ap_hash_lock);
894 896 return (0);
895 897 }
896 898
897 899 static int
898 900 drv_ioc_setap(datalink_id_t linkid, struct dlautopush *dlap)
899 901 {
900 902 dld_ap_t *dap;
901 903 int i;
902 904 mod_hash_key_t key;
903 905
904 906 if (dlap->dap_npush == 0 || dlap->dap_npush > MAXAPUSH)
905 907 return (EINVAL);
906 908
907 909 /*
908 910 * Validate that the specified list of modules exist.
909 911 */
910 912 for (i = 0; i < dlap->dap_npush; i++) {
911 913 if (fmodsw_find(dlap->dap_aplist[i], FMODSW_LOAD) == NULL)
912 914 return (EINVAL);
913 915 }
914 916
915 917
916 918 key = (mod_hash_key_t)(uintptr_t)linkid;
917 919
918 920 rw_enter(&dld_ap_hash_lock, RW_WRITER);
919 921 if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) {
920 922 dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP);
921 923 if (dap == NULL) {
922 924 rw_exit(&dld_ap_hash_lock);
923 925 return (ENOMEM);
924 926 }
925 927
926 928 dap->da_linkid = linkid;
927 929 VERIFY(mod_hash_insert(dld_ap_hashp, key,
928 930 (mod_hash_val_t)dap) == 0);
929 931 }
930 932
931 933 /*
932 934 * Update the configuration.
933 935 */
934 936 dap->da_anchor = dlap->dap_anchor;
935 937 dap->da_npush = dlap->dap_npush;
936 938 for (i = 0; i < dlap->dap_npush; i++) {
937 939 (void) strlcpy(dap->da_aplist[i], dlap->dap_aplist[i],
938 940 FMNAMESZ + 1);
939 941 }
940 942 rw_exit(&dld_ap_hash_lock);
941 943
942 944 return (0);
943 945 }
944 946
945 947 static int
946 948 drv_ioc_getap(datalink_id_t linkid, struct dlautopush *dlap)
947 949 {
948 950 dld_ap_t *dap;
949 951 int i;
950 952
951 953 rw_enter(&dld_ap_hash_lock, RW_READER);
952 954 if (mod_hash_find(dld_ap_hashp,
953 955 (mod_hash_key_t)(uintptr_t)linkid,
954 956 (mod_hash_val_t *)&dap) != 0) {
955 957 rw_exit(&dld_ap_hash_lock);
956 958 dlap->dap_npush = 0;
957 959 return (0);
958 960 }
959 961
960 962 /*
961 963 * Retrieve the configuration.
962 964 */
963 965 dlap->dap_anchor = dap->da_anchor;
964 966 dlap->dap_npush = dap->da_npush;
965 967 for (i = 0; i < dap->da_npush; i++) {
966 968 (void) strlcpy(dlap->dap_aplist[i], dap->da_aplist[i],
967 969 FMNAMESZ + 1);
968 970 }
969 971 rw_exit(&dld_ap_hash_lock);
970 972
971 973 return (0);
972 974 }
973 975
974 976 static int
975 977 drv_ioc_clrap(datalink_id_t linkid)
976 978 {
977 979 mod_hash_val_t val;
978 980 mod_hash_key_t key;
979 981
980 982 key = (mod_hash_key_t)(uintptr_t)linkid;
981 983
982 984 rw_enter(&dld_ap_hash_lock, RW_WRITER);
983 985 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) {
984 986 rw_exit(&dld_ap_hash_lock);
985 987 return (0);
986 988 }
987 989
988 990 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0);
989 991 kmem_free(val, sizeof (dld_ap_t));
990 992 rw_exit(&dld_ap_hash_lock);
991 993 return (0);
992 994 }
993 995
994 996 /*
995 997 * DLDIOC_DOORSERVER
996 998 */
997 999 /* ARGSUSED */
998 1000 static int
999 1001 drv_ioc_doorserver(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1000 1002 {
1001 1003 dld_ioc_door_t *did = karg;
1002 1004
1003 1005 return (dls_mgmt_door_set(did->did_start_door));
1004 1006 }
1005 1007
1006 1008 /*
1007 1009 * DLDIOC_USAGELOG
1008 1010 */
1009 1011 /* ARGSUSED */
1010 1012 static int
1011 1013 drv_ioc_usagelog(void *karg, intptr_t arg, int mode, cred_t *cred,
1012 1014 int *rvalp)
1013 1015 {
1014 1016 dld_ioc_usagelog_t *log_info = (dld_ioc_usagelog_t *)karg;
1015 1017 int err = 0;
1016 1018
1017 1019 if (log_info->ul_type < MAC_LOGTYPE_LINK ||
1018 1020 log_info->ul_type > MAC_LOGTYPE_FLOW)
1019 1021 return (EINVAL);
1020 1022
1021 1023 if (log_info->ul_onoff) {
1022 1024 err = mac_start_logusage(log_info->ul_type,
1023 1025 log_info->ul_interval);
1024 1026 } else {
1025 1027 mac_stop_logusage(log_info->ul_type);
1026 1028 }
1027 1029 return (err);
1028 1030 }
1029 1031
1030 1032 /*
1031 1033 * Process a DLDIOC_ADDFLOW request.
1032 1034 */
1033 1035 /* ARGSUSED */
1034 1036 static int
1035 1037 drv_ioc_addflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1036 1038 {
1037 1039 dld_ioc_addflow_t *afp = karg;
1038 1040
1039 1041 return (dld_add_flow(afp->af_linkid, afp->af_name,
1040 1042 &afp->af_flow_desc, &afp->af_resource_props));
1041 1043 }
1042 1044
1043 1045 /*
1044 1046 * Process a DLDIOC_REMOVEFLOW request.
1045 1047 */
1046 1048 /* ARGSUSED */
1047 1049 static int
1048 1050 drv_ioc_removeflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1049 1051 {
1050 1052 dld_ioc_removeflow_t *rfp = karg;
1051 1053
1052 1054 return (dld_remove_flow(rfp->rf_name));
1053 1055 }
1054 1056
1055 1057 /*
1056 1058 * Process a DLDIOC_MODIFYFLOW request.
1057 1059 */
1058 1060 /* ARGSUSED */
1059 1061 static int
1060 1062 drv_ioc_modifyflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1061 1063 {
1062 1064 dld_ioc_modifyflow_t *mfp = karg;
1063 1065
1064 1066 return (dld_modify_flow(mfp->mf_name, &mfp->mf_resource_props));
1065 1067 }
1066 1068
1067 1069 /*
1068 1070 * Process a DLDIOC_WALKFLOW request.
1069 1071 */
1070 1072 /* ARGSUSED */
1071 1073 static int
1072 1074 drv_ioc_walkflow(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1073 1075 {
1074 1076 dld_ioc_walkflow_t *wfp = karg;
1075 1077
1076 1078 return (dld_walk_flow(wfp, arg, cred));
1077 1079 }
1078 1080
1079 1081 /*
1080 1082 * Check for GLDv3 autopush information. There are three cases:
1081 1083 *
1082 1084 * 1. If devp points to a GLDv3 datalink and it has autopush configuration,
1083 1085 * fill dlap in with that information and return 0.
1084 1086 *
1085 1087 * 2. If devp points to a GLDv3 datalink but it doesn't have autopush
1086 1088 * configuration, then replace devp with the physical device (if one
1087 1089 * exists) and return 1. This allows stropen() to find the old-school
1088 1090 * per-driver autopush configuration. (For softmac, the result is that
1089 1091 * the softmac dev_t is replaced with the legacy device's dev_t).
1090 1092 *
1091 1093 * 3. If neither of the above apply, don't touch the args and return -1.
1092 1094 */
1093 1095 int
1094 1096 dld_autopush(dev_t *devp, struct dlautopush *dlap)
1095 1097 {
1096 1098 dld_ap_t *dap;
1097 1099 datalink_id_t linkid;
1098 1100 dev_t phydev;
1099 1101
1100 1102 if (!GLDV3_DRV(getmajor(*devp)))
1101 1103 return (-1);
1102 1104
1103 1105 /*
1104 1106 * Find the linkid by the link's dev_t.
1105 1107 */
1106 1108 if (dls_devnet_dev2linkid(*devp, &linkid) != 0)
1107 1109 return (-1);
1108 1110
1109 1111 /*
1110 1112 * Find the autopush configuration associated with the linkid.
1111 1113 */
1112 1114 rw_enter(&dld_ap_hash_lock, RW_READER);
1113 1115 if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid,
1114 1116 (mod_hash_val_t *)&dap) == 0) {
1115 1117 *dlap = dap->da_ap;
1116 1118 rw_exit(&dld_ap_hash_lock);
1117 1119 return (0);
1118 1120 }
1119 1121 rw_exit(&dld_ap_hash_lock);
1120 1122
1121 1123 if (dls_devnet_phydev(linkid, &phydev) != 0)
1122 1124 return (-1);
1123 1125
1124 1126 *devp = phydev;
1125 1127 return (1);
1126 1128 }
1127 1129
1128 1130 /*
1129 1131 * Secure objects implementation
1130 1132 */
1131 1133
1132 1134 /* ARGSUSED */
1133 1135 static int
1134 1136 drv_secobj_ctor(void *buf, void *arg, int kmflag)
1135 1137 {
1136 1138 bzero(buf, sizeof (dld_secobj_t));
1137 1139 return (0);
1138 1140 }
1139 1141
1140 1142 static void
1141 1143 drv_secobj_init(void)
1142 1144 {
1143 1145 rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL);
1144 1146 drv_secobj_cachep = kmem_cache_create("drv_secobj_cache",
1145 1147 sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL,
1146 1148 NULL, NULL, NULL, 0);
1147 1149 drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash",
1148 1150 SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
1149 1151 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
1150 1152 }
1151 1153
1152 1154 static void
1153 1155 drv_secobj_fini(void)
1154 1156 {
1155 1157 mod_hash_destroy_hash(drv_secobj_hash);
1156 1158 kmem_cache_destroy(drv_secobj_cachep);
1157 1159 rw_destroy(&drv_secobj_lock);
1158 1160 }
1159 1161
1160 1162 /* ARGSUSED */
1161 1163 static int
1162 1164 drv_ioc_secobj_set(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1163 1165 {
1164 1166 dld_ioc_secobj_set_t *ssp = karg;
1165 1167 dld_secobj_t *sobjp, *objp;
1166 1168 int err;
1167 1169
1168 1170 sobjp = &ssp->ss_obj;
1169 1171
1170 1172 if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP &&
1171 1173 sobjp->so_class != DLD_SECOBJ_CLASS_WPA)
1172 1174 return (EINVAL);
1173 1175
1174 1176 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' ||
1175 1177 sobjp->so_len > DLD_SECOBJ_VAL_MAX)
1176 1178 return (EINVAL);
1177 1179
1178 1180 rw_enter(&drv_secobj_lock, RW_WRITER);
1179 1181 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name,
1180 1182 (mod_hash_val_t *)&objp);
1181 1183 if (err == 0) {
1182 1184 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) {
1183 1185 rw_exit(&drv_secobj_lock);
1184 1186 return (EEXIST);
1185 1187 }
1186 1188 } else {
1187 1189 ASSERT(err == MH_ERR_NOTFOUND);
1188 1190 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) {
1189 1191 rw_exit(&drv_secobj_lock);
1190 1192 return (ENOENT);
1191 1193 }
1192 1194 objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP);
1193 1195 (void) strlcpy(objp->so_name, sobjp->so_name,
1194 1196 DLD_SECOBJ_NAME_MAX);
1195 1197
1196 1198 VERIFY(mod_hash_insert(drv_secobj_hash,
1197 1199 (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp) == 0);
1198 1200 }
1199 1201 bcopy(sobjp->so_val, objp->so_val, sobjp->so_len);
1200 1202 objp->so_len = sobjp->so_len;
1201 1203 objp->so_class = sobjp->so_class;
1202 1204 rw_exit(&drv_secobj_lock);
1203 1205 return (0);
1204 1206 }
1205 1207
1206 1208 typedef struct dld_secobj_state {
1207 1209 uint_t ss_free;
1208 1210 uint_t ss_count;
1209 1211 int ss_rc;
1210 1212 int ss_mode;
1211 1213 dld_secobj_t *ss_objp;
1212 1214 } dld_secobj_state_t;
1213 1215
1214 1216 /* ARGSUSED */
1215 1217 static uint_t
1216 1218 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1217 1219 {
1218 1220 dld_secobj_state_t *statep = arg;
1219 1221 dld_secobj_t *sobjp = (dld_secobj_t *)val;
1220 1222
1221 1223 if (statep->ss_free < sizeof (dld_secobj_t)) {
1222 1224 statep->ss_rc = ENOSPC;
1223 1225 return (MH_WALK_TERMINATE);
1224 1226 }
1225 1227 if (ddi_copyout(sobjp, statep->ss_objp, sizeof (*sobjp),
1226 1228 statep->ss_mode) != 0) {
1227 1229 statep->ss_rc = EFAULT;
1228 1230 return (MH_WALK_TERMINATE);
1229 1231 }
1230 1232 statep->ss_objp++;
1231 1233 statep->ss_free -= sizeof (dld_secobj_t);
1232 1234 statep->ss_count++;
1233 1235 return (MH_WALK_CONTINUE);
1234 1236 }
1235 1237
1236 1238 /* ARGSUSED */
1237 1239 static int
1238 1240 drv_ioc_secobj_get(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1239 1241 {
1240 1242 dld_ioc_secobj_get_t *sgp = karg;
1241 1243 dld_secobj_t *sobjp, *objp;
1242 1244 int err;
1243 1245
1244 1246 sobjp = &sgp->sg_obj;
1245 1247 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
1246 1248 return (EINVAL);
1247 1249
1248 1250 rw_enter(&drv_secobj_lock, RW_READER);
1249 1251 if (sobjp->so_name[0] != '\0') {
1250 1252 err = mod_hash_find(drv_secobj_hash,
1251 1253 (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp);
1252 1254 if (err != 0) {
1253 1255 ASSERT(err == MH_ERR_NOTFOUND);
1254 1256 rw_exit(&drv_secobj_lock);
1255 1257 return (ENOENT);
1256 1258 }
1257 1259 bcopy(objp->so_val, sobjp->so_val, objp->so_len);
1258 1260 sobjp->so_len = objp->so_len;
1259 1261 sobjp->so_class = objp->so_class;
1260 1262 sgp->sg_count = 1;
1261 1263 } else {
1262 1264 dld_secobj_state_t state;
1263 1265
1264 1266 state.ss_free = sgp->sg_size - sizeof (dld_ioc_secobj_get_t);
1265 1267 state.ss_count = 0;
1266 1268 state.ss_rc = 0;
1267 1269 state.ss_mode = mode;
1268 1270 state.ss_objp = (dld_secobj_t *)((uchar_t *)arg +
1269 1271 sizeof (dld_ioc_secobj_get_t));
1270 1272
1271 1273 mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state);
1272 1274 if (state.ss_rc != 0) {
1273 1275 rw_exit(&drv_secobj_lock);
1274 1276 return (state.ss_rc);
1275 1277 }
1276 1278 sgp->sg_count = state.ss_count;
1277 1279 }
1278 1280 rw_exit(&drv_secobj_lock);
1279 1281 return (0);
1280 1282 }
1281 1283
1282 1284 /* ARGSUSED */
1283 1285 static int
1284 1286 drv_ioc_secobj_unset(void *karg, intptr_t arg, int mode, cred_t *cred,
1285 1287 int *rvalp)
1286 1288 {
1287 1289 dld_ioc_secobj_unset_t *sup = karg;
1288 1290 dld_secobj_t *objp;
1289 1291 mod_hash_val_t val;
1290 1292 int err;
1291 1293
1292 1294 if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
1293 1295 return (EINVAL);
1294 1296
1295 1297 rw_enter(&drv_secobj_lock, RW_WRITER);
1296 1298 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
1297 1299 (mod_hash_val_t *)&objp);
1298 1300 if (err != 0) {
1299 1301 ASSERT(err == MH_ERR_NOTFOUND);
1300 1302 rw_exit(&drv_secobj_lock);
1301 1303 return (ENOENT);
1302 1304 }
1303 1305 VERIFY(mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
1304 1306 (mod_hash_val_t *)&val) == 0);
1305 1307 ASSERT(objp == (dld_secobj_t *)val);
1306 1308
1307 1309 kmem_cache_free(drv_secobj_cachep, objp);
1308 1310 rw_exit(&drv_secobj_lock);
1309 1311 return (0);
1310 1312 }
1311 1313
1312 1314 /*
1313 1315 * Note that ioctls that modify links have a NULL di_priv_func(), as
1314 1316 * privileges can only be checked after we know the class of the link being
1315 1317 * modified (due to class-specific fine-grained privileges such as
1316 1318 * sys_iptun_config).
1317 1319 */
1318 1320 static dld_ioc_info_t drv_ioc_list[] = {
1319 1321 {DLDIOC_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_attr_t),
1320 1322 drv_ioc_attr, NULL},
1321 1323 {DLDIOC_PHYS_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_phys_attr_t),
1322 1324 drv_ioc_phys_attr, NULL},
1323 1325 {DLDIOC_SECOBJ_SET, DLDCOPYIN, sizeof (dld_ioc_secobj_set_t),
1324 1326 drv_ioc_secobj_set, secpolicy_dl_config},
1325 1327 {DLDIOC_SECOBJ_GET, DLDCOPYINOUT, sizeof (dld_ioc_secobj_get_t),
1326 1328 drv_ioc_secobj_get, secpolicy_dl_config},
1327 1329 {DLDIOC_SECOBJ_UNSET, DLDCOPYIN, sizeof (dld_ioc_secobj_unset_t),
1328 1330 drv_ioc_secobj_unset, secpolicy_dl_config},
1329 1331 {DLDIOC_DOORSERVER, DLDCOPYIN, sizeof (dld_ioc_door_t),
1330 1332 drv_ioc_doorserver, secpolicy_dl_config},
1331 1333 {DLDIOC_RENAME, DLDCOPYIN, sizeof (dld_ioc_rename_t),
1332 1334 drv_ioc_rename, NULL},
1333 1335 {DLDIOC_MACADDRGET, DLDCOPYINOUT, sizeof (dld_ioc_macaddrget_t),
1334 1336 drv_ioc_macaddrget, NULL},
1335 1337 {DLDIOC_ADDFLOW, DLDCOPYIN, sizeof (dld_ioc_addflow_t),
1336 1338 drv_ioc_addflow, secpolicy_dl_config},
1337 1339 {DLDIOC_REMOVEFLOW, DLDCOPYIN, sizeof (dld_ioc_removeflow_t),
1338 1340 drv_ioc_removeflow, secpolicy_dl_config},
1339 1341 {DLDIOC_MODIFYFLOW, DLDCOPYIN, sizeof (dld_ioc_modifyflow_t),
1340 1342 drv_ioc_modifyflow, secpolicy_dl_config},
1341 1343 {DLDIOC_WALKFLOW, DLDCOPYINOUT, sizeof (dld_ioc_walkflow_t),
1342 1344 drv_ioc_walkflow, NULL},
1343 1345 {DLDIOC_USAGELOG, DLDCOPYIN, sizeof (dld_ioc_usagelog_t),
1344 1346 drv_ioc_usagelog, secpolicy_dl_config},
1345 1347 {DLDIOC_SETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t),
1346 1348 drv_ioc_setprop, NULL},
1347 1349 {DLDIOC_GETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t),
1348 1350 drv_ioc_getprop, NULL},
1349 1351 {DLDIOC_GETHWGRP, DLDCOPYINOUT, sizeof (dld_ioc_hwgrpget_t),
1350 1352 drv_ioc_hwgrpget, NULL},
1351 1353 };
1352 1354
1353 1355 typedef struct dld_ioc_modentry {
1354 1356 uint16_t dim_modid; /* Top 16 bits of ioctl command */
1355 1357 char *dim_modname; /* Module to be loaded */
1356 1358 int ctrl_node_inst; /* Ctrl node instance */
1357 1359 dld_ioc_info_t *dim_list; /* array of ioctl structures */
1358 1360 uint_t dim_count; /* number of elements in dim_list */
1359 1361 } dld_ioc_modentry_t;
1360 1362
1361 1363 /*
1362 1364 * For all modules except for dld, dim_list and dim_count are assigned
1363 1365 * when the modules register their ioctls in dld_ioc_register(). We
1364 1366 * can statically initialize dld's ioctls in-line here; there's no
1365 1367 * need for it to call dld_ioc_register() itself. ctrl_node_inst controls
1366 1368 * whether an instance of the device will be held or the driver. If set to
1367 1369 * a non-negative integer, device instance specified in ctrl_node_inst will
1368 1370 * be held; so dld_ioc_register() _must_ be called in xxx_attach() routine of
1369 1371 * the driver. If set to -1, driver will be held; so dld_ioc_register() _must_
1370 1372 * be called in xxx_init() routine of the driver.
1371 1373 */
1372 1374 static dld_ioc_modentry_t dld_ioc_modtable[] = {
1373 1375 {DLD_IOC, "dld", 0, drv_ioc_list, DLDIOCCNT(drv_ioc_list)},
1374 1376 {AGGR_IOC, "aggr", 0, NULL, 0},
1375 1377 {VNIC_IOC, "vnic", 0, NULL, 0},
1376 1378 {SIMNET_IOC, "simnet", 0, NULL, 0},
1377 1379 {BRIDGE_IOC, "bridge", 0, NULL, 0},
1378 1380 {IPTUN_IOC, "iptun", 0, NULL, 0},
1379 1381 {IBPART_IOC, "ibp", -1, NULL, 0}
1380 1382 };
1381 1383 #define DLDIOC_CNT \
1382 1384 (sizeof (dld_ioc_modtable) / sizeof (dld_ioc_modentry_t))
1383 1385
1384 1386 static dld_ioc_modentry_t *
1385 1387 dld_ioc_findmod(uint16_t modid)
1386 1388 {
1387 1389 int i;
1388 1390
1389 1391 for (i = 0; i < DLDIOC_CNT; i++) {
1390 1392 if (modid == dld_ioc_modtable[i].dim_modid)
1391 1393 return (&dld_ioc_modtable[i]);
1392 1394 }
1393 1395 return (NULL);
1394 1396 }
1395 1397
1396 1398 int
1397 1399 dld_ioc_register(uint16_t modid, dld_ioc_info_t *list, uint_t count)
1398 1400 {
1399 1401 dld_ioc_modentry_t *dim = dld_ioc_findmod(modid);
1400 1402
1401 1403 if (dim == NULL)
1402 1404 return (ENOENT);
1403 1405
1404 1406 dim->dim_list = list;
1405 1407 dim->dim_count = count;
1406 1408 return (0);
1407 1409 }
1408 1410
1409 1411 void
1410 1412 dld_ioc_unregister(uint16_t modid)
1411 1413 {
1412 1414 VERIFY(dld_ioc_register(modid, NULL, 0) == 0);
1413 1415 }
1414 1416
1415 1417 /*
1416 1418 * The general design with GLDv3 ioctls is that all ioctls issued
1417 1419 * through /dev/dld go through this drv_ioctl() function. This
1418 1420 * function handles all ioctls on behalf of modules listed in
1419 1421 * dld_ioc_modtable.
1420 1422 *
1421 1423 * When an ioctl is received, this function looks for the associated
1422 1424 * module-id-specific ioctl information using dld_ioc_findmod(). The
1423 1425 * call to ddi_hold_driver() or ddi_hold_devi_by_instance() on the
1424 1426 * associated device will cause the kernel module responsible for the
1425 1427 * ioctl to be loaded if it's not already loaded, which should result
1426 1428 * in that module calling dld_ioc_register(), thereby filling in the
1427 1429 * dim_list containing the details for the ioctl being processed.
1428 1430 *
1429 1431 * This function can then perform operations such as copyin() data and
1430 1432 * do credential checks based on the registered ioctl information,
1431 1433 * then issue the callback function di_func() registered by the
1432 1434 * responsible module. Upon return, the appropriate copyout()
1433 1435 * operation can be performed and the operation completes.
1434 1436 */
1435 1437 /* ARGSUSED */
1436 1438 static int
1437 1439 drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1438 1440 {
1439 1441 dld_ioc_modentry_t *dim;
1440 1442 dld_ioc_info_t *info;
1441 1443 dev_info_t *dip = NULL;
1442 1444 struct dev_ops *dops = NULL;
1443 1445 major_t major;
1444 1446 void *buf = NULL;
1445 1447 size_t sz;
1446 1448 int i, err;
1447 1449
1448 1450 if ((dim = dld_ioc_findmod(DLD_IOC_MODID(cmd))) == NULL)
1449 1451 return (ENOTSUP);
1450 1452
1451 1453 major = ddi_name_to_major(dim->dim_modname);
1452 1454
1453 1455 if (dim->ctrl_node_inst == -1) {
1454 1456 /*
1455 1457 * No dedicated instance to process ioctls.
1456 1458 * dld_ioc_register() is called in xxx_init().
1457 1459 */
1458 1460 dops = ddi_hold_driver(major);
1459 1461 } else {
1460 1462 /*
1461 1463 * Dedicated instance to handle ioctl.
1462 1464 * dld_ioc_register() is called in xxx_attach().
1463 1465 */
1464 1466 dip = ddi_hold_devi_by_instance(major, dim->ctrl_node_inst, 0);
1465 1467 }
1466 1468
1467 1469 if ((dip == NULL && dops == NULL) || dim->dim_list == NULL) {
1468 1470 err = ENODEV;
1469 1471 goto done;
1470 1472 }
1471 1473
1472 1474 for (i = 0; i < dim->dim_count; i++) {
1473 1475 if (cmd == dim->dim_list[i].di_cmd)
1474 1476 break;
1475 1477 }
1476 1478 if (i == dim->dim_count) {
1477 1479 err = ENOTSUP;
1478 1480 goto done;
1479 1481 }
1480 1482
1481 1483 info = &dim->dim_list[i];
1482 1484
1483 1485 if (info->di_priv_func != NULL &&
1484 1486 (err = info->di_priv_func(cred)) != 0)
1485 1487 goto done;
1486 1488
1487 1489 sz = info->di_argsize;
1488 1490 if ((buf = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
1489 1491 err = ENOMEM;
1490 1492 goto done;
1491 1493 }
1492 1494
1493 1495 if ((info->di_flags & DLDCOPYIN) &&
1494 1496 ddi_copyin((void *)arg, buf, sz, mode) != 0) {
1495 1497 err = EFAULT;
1496 1498 goto done;
1497 1499 }
1498 1500
1499 1501 err = info->di_func(buf, arg, mode, cred, rvalp);
1500 1502
1501 1503 if ((info->di_flags & DLDCOPYOUT) &&
1502 1504 ddi_copyout(buf, (void *)arg, sz, mode) != 0 && err == 0)
1503 1505 err = EFAULT;
1504 1506
1505 1507 done:
1506 1508 if (buf != NULL)
1507 1509 kmem_free(buf, sz);
1508 1510 if (dip != NULL)
1509 1511 ddi_release_devi(dip);
1510 1512 if (dops != NULL)
1511 1513 ddi_rele_driver(major);
1512 1514 return (err);
1513 1515 }
|
↓ open down ↓ |
635 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX