4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2017, Joyent, Inc.
31 #include <sys/mkdev.h>
32 #include <sys/modctl.h>
34 #include <sys/dld_impl.h>
35 #include <sys/dld_ioc.h>
36 #include <sys/dls_impl.h>
37 #include <sys/softmac.h>
39 #include <sys/mac_ether.h>
40 #include <sys/mac_client.h>
41 #include <sys/mac_client_impl.h>
42 #include <sys/mac_client_priv.h>
43 #include <inet/common.h>
44 #include <sys/policy.h>
45 #include <sys/priv_names.h>
47 #include <sys/sysmacros.h>
49 static void drv_init(void);
50 static int drv_fini(void);
52 static int drv_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
53 static int drv_attach(dev_info_t
*, ddi_attach_cmd_t
);
54 static int drv_detach(dev_info_t
*, ddi_detach_cmd_t
);
57 * Secure objects declarations
59 #define SECOBJ_WEP_HASHSZ 67
60 static krwlock_t drv_secobj_lock
;
61 static kmem_cache_t
*drv_secobj_cachep
;
62 static mod_hash_t
*drv_secobj_hash
;
63 static void drv_secobj_init(void);
64 static void drv_secobj_fini(void);
65 static int drv_ioc_setap(datalink_id_t
, struct dlautopush
*);
66 static int drv_ioc_getap(datalink_id_t
, struct dlautopush
*);
67 static int drv_ioc_clrap(datalink_id_t
);
71 * The following entry points are private to dld and are used for control
72 * operations only. The entry points exported to mac drivers are defined
73 * in dld_str.c. Refer to the comment on top of dld_str.c for details.
75 static int drv_open(dev_t
*, int, int, cred_t
*);
76 static int drv_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
78 static dev_info_t
*dld_dip
; /* dev_info_t for the driver */
79 uint32_t dld_opt
= 0; /* Global options */
82 static mod_hash_t
*dld_ap_hashp
;
83 static krwlock_t dld_ap_hash_lock
;
85 static struct cb_ops drv_cb_ops
= {
88 nulldev
, /* strategy */
93 drv_ioctl
, /* ioctl */
98 ddi_prop_op
, /* cb_prop_op */
100 D_MP
/* Driver compatibility flag */
103 static struct dev_ops drv_ops
= {
104 DEVO_REV
, /* devo_rev */
106 drv_getinfo
, /* get_dev_info */
107 nulldev
, /* identify */
109 drv_attach
, /* attach */
110 drv_detach
, /* detach */
112 &drv_cb_ops
, /* driver operations */
113 NULL
, /* bus operations */
114 nodev
, /* dev power */
115 ddi_quiesce_not_supported
, /* dev quiesce */
119 * Module linkage information for the kernel.
121 static struct modldrv drv_modldrv
= {
127 static struct modlinkage drv_modlinkage
= {
136 return (mod_install(&drv_modlinkage
));
142 return (mod_remove(&drv_modlinkage
));
146 _info(struct modinfo
*modinfop
)
148 return (mod_info(&drv_modlinkage
, modinfop
));
152 * Initialize component modules.
161 * Create a hash table for autopush configuration.
163 dld_ap_hashp
= mod_hash_create_idhash("dld_autopush_hash",
164 NAUTOPUSH
, mod_hash_null_valdtor
);
166 ASSERT(dld_ap_hashp
!= NULL
);
167 rw_init(&dld_ap_hash_lock
, NULL
, RW_DRIVER
, NULL
);
172 drv_ap_exist(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
174 boolean_t
*pexist
= arg
;
177 return (MH_WALK_TERMINATE
);
184 boolean_t exist
= B_FALSE
;
186 rw_enter(&dld_ap_hash_lock
, RW_READER
);
187 mod_hash_walk(dld_ap_hashp
, drv_ap_exist
, &exist
);
188 rw_exit(&dld_ap_hash_lock
);
192 if ((err
= dld_str_fini()) != 0)
196 mod_hash_destroy_idhash(dld_ap_hashp
);
197 rw_destroy(&dld_ap_hash_lock
);
202 * devo_getinfo: getinfo(9e)
206 drv_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **resp
)
209 return (DDI_FAILURE
);
212 case DDI_INFO_DEVT2INSTANCE
:
215 case DDI_INFO_DEVT2DEVINFO
:
219 return (DDI_FAILURE
);
222 return (DDI_SUCCESS
);
226 * Check properties to set options. (See dld.h for property definitions).
229 drv_set_opt(dev_info_t
*dip
)
231 if (ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
232 DLD_PROP_NO_FASTPATH
, 0) != 0) {
233 dld_opt
|= DLD_OPT_NO_FASTPATH
;
236 if (ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
237 DLD_PROP_NO_POLL
, 0) != 0) {
238 dld_opt
|= DLD_OPT_NO_POLL
;
241 if (ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
242 DLD_PROP_NO_ZEROCOPY
, 0) != 0) {
243 dld_opt
|= DLD_OPT_NO_ZEROCOPY
;
246 if (ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
247 DLD_PROP_NO_SOFTRING
, 0) != 0) {
248 dld_opt
|= DLD_OPT_NO_SOFTRING
;
253 * devo_attach: attach(9e)
256 drv_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
258 if (cmd
!= DDI_ATTACH
)
259 return (DDI_FAILURE
);
261 ASSERT(ddi_get_instance(dip
) == 0);
266 * Create control node. DLPI provider nodes will be created on demand.
268 if (ddi_create_minor_node(dip
, DLD_CONTROL_MINOR_NAME
, S_IFCHR
,
269 DLD_CONTROL_MINOR
, DDI_PSEUDO
, 0) != DDI_SUCCESS
)
270 return (DDI_FAILURE
);
275 * Log the fact that the driver is now attached.
278 return (DDI_SUCCESS
);
282 * devo_detach: detach(9e)
285 drv_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
287 if (cmd
!= DDI_DETACH
)
288 return (DDI_FAILURE
);
290 ASSERT(dld_dip
== dip
);
292 return (DDI_FAILURE
);
295 * Remove the control node.
297 ddi_remove_minor_node(dip
, DLD_CONTROL_MINOR_NAME
);
300 return (DDI_SUCCESS
);
304 * dld control node open procedure.
308 drv_open(dev_t
*devp
, int flag
, int sflag
, cred_t
*credp
)
311 * Only the control node can be opened.
313 if (getminor(*devp
) != DLD_CONTROL_MINOR
)
319 * Verify if the caller is allowed to modify a link of the given class.
322 drv_ioc_checkprivs(datalink_class_t
class, cred_t
*cred
)
324 if (class == DATALINK_CLASS_IPTUN
)
325 return (secpolicy_iptun_config(cred
));
326 return (secpolicy_dl_config(cred
));
334 drv_ioc_attr(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
336 dld_ioc_attr_t
*diap
= karg
;
339 zoneid_t zoneid
= crgetzoneid(cred
);
341 mac_perim_handle_t mph
;
343 if (zoneid
!= GLOBAL_ZONEID
&&
344 zone_check_datalink(&zoneid
, diap
->dia_linkid
) != 0)
347 if ((err
= dls_devnet_hold_tmp(diap
->dia_linkid
, &dlh
)) != 0)
350 if ((err
= mac_perim_enter_by_macname(
351 dls_devnet_mac(dlh
), &mph
)) != 0) {
352 dls_devnet_rele_tmp(dlh
);
356 if ((err
= dls_link_hold(dls_devnet_mac(dlh
), &dlp
)) != 0) {
358 dls_devnet_rele_tmp(dlh
);
362 mac_sdu_get(dlp
->dl_mh
, NULL
, &diap
->dia_max_sdu
);
366 dls_devnet_rele_tmp(dlh
);
376 drv_ioc_phys_attr(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
378 dld_ioc_phys_attr_t
*dipp
= karg
;
381 dls_dev_handle_t ddh
;
383 zoneid_t zoneid
= crgetzoneid(cred
);
385 if (zoneid
!= GLOBAL_ZONEID
&&
386 zone_check_datalink(&zoneid
, dipp
->dip_linkid
) != 0)
390 * Every physical link should have its physical dev_t kept in the
391 * daemon. If not, it is not a valid physical link.
393 if (dls_mgmt_get_phydev(dipp
->dip_linkid
, &phydev
) != 0)
397 * Although this is a valid physical link, it might already be removed
398 * by DR or during system shutdown. softmac_hold_device() would return
399 * ENOENT in this case.
401 if ((err
= softmac_hold_device(phydev
, &ddh
)) != 0)
404 if (dls_devnet_hold_tmp(dipp
->dip_linkid
, &dlh
) != 0) {
406 * Although this is an active physical link, its link type is
407 * not supported by GLDv3, and therefore it does not have
408 * vanity naming support.
410 dipp
->dip_novanity
= B_TRUE
;
412 dipp
->dip_novanity
= B_FALSE
;
413 dls_devnet_rele_tmp(dlh
);
416 * Get the physical device name from the major number and the instance
417 * number derived from phydev.
419 (void) snprintf(dipp
->dip_dev
, MAXLINKNAMELEN
, "%s%d",
420 ddi_major_to_name(getmajor(phydev
)), getminor(phydev
) - 1);
422 softmac_rele_device(ddh
);
428 drv_ioc_hwgrpget(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
430 dld_ioc_hwgrpget_t
*hwgrpp
= karg
;
431 dld_hwgrpinfo_t hwgrp
, *hip
;
432 mac_handle_t mh
= NULL
;
433 int i
, err
, rgrpnum
, tgrpnum
;
436 zoneid_t zoneid
= crgetzoneid(cred
);
438 if (zoneid
!= GLOBAL_ZONEID
&&
439 zone_check_datalink(&zoneid
, hwgrpp
->dih_linkid
) != 0)
442 hwgrpp
->dih_n_groups
= 0;
443 err
= mac_open_by_linkid(hwgrpp
->dih_linkid
, &mh
);
447 hip
= (dld_hwgrpinfo_t
*)
448 ((uchar_t
*)arg
+ sizeof (dld_ioc_hwgrpget_t
));
449 bytes_left
= hwgrpp
->dih_size
;
451 rgrpnum
= mac_hwgrp_num(mh
, MAC_RING_TYPE_RX
);
452 /* display the default group information first */
454 if (sizeof (dld_hwgrpinfo_t
) > bytes_left
) {
459 bzero(&hwgrp
, sizeof (hwgrp
));
460 bcopy(mac_name(mh
), hwgrp
.dhi_link_name
,
461 sizeof (hwgrp
.dhi_link_name
));
462 mac_get_hwrxgrp_info(mh
, 0, &hwgrp
.dhi_grp_num
,
463 &hwgrp
.dhi_n_rings
, hwgrp
.dhi_rings
, &hwgrp
.dhi_grp_type
,
464 &hwgrp
.dhi_n_clnts
, hwgrp
.dhi_clnts
);
465 if (hwgrp
.dhi_n_rings
!= 0) {
466 if (copyout(&hwgrp
, hip
, sizeof (hwgrp
)) != 0) {
473 bytes_left
-= sizeof (dld_hwgrpinfo_t
);
476 tgrpnum
= mac_hwgrp_num(mh
, MAC_RING_TYPE_TX
);
477 /* display the default group information first */
479 if (sizeof (dld_hwgrpinfo_t
) > bytes_left
) {
484 bzero(&hwgrp
, sizeof (hwgrp
));
485 bcopy(mac_name(mh
), hwgrp
.dhi_link_name
,
486 sizeof (hwgrp
.dhi_link_name
));
487 mac_get_hwtxgrp_info(mh
, tgrpnum
- 1, &hwgrp
.dhi_grp_num
,
488 &hwgrp
.dhi_n_rings
, hwgrp
.dhi_rings
, &hwgrp
.dhi_grp_type
,
489 &hwgrp
.dhi_n_clnts
, hwgrp
.dhi_clnts
);
490 if (hwgrp
.dhi_n_rings
!= 0) {
491 if (copyout(&hwgrp
, hip
, sizeof (hwgrp
)) != 0) {
498 bytes_left
-= sizeof (dld_hwgrpinfo_t
);
501 /* Rest of the rx groups */
502 for (i
= 1; i
< rgrpnum
; i
++) {
503 if (sizeof (dld_hwgrpinfo_t
) > bytes_left
) {
508 bzero(&hwgrp
, sizeof (hwgrp
));
509 bcopy(mac_name(mh
), hwgrp
.dhi_link_name
,
510 sizeof (hwgrp
.dhi_link_name
));
511 mac_get_hwrxgrp_info(mh
, i
, &hwgrp
.dhi_grp_num
,
512 &hwgrp
.dhi_n_rings
, hwgrp
.dhi_rings
, &hwgrp
.dhi_grp_type
,
513 &hwgrp
.dhi_n_clnts
, hwgrp
.dhi_clnts
);
514 if (hwgrp
.dhi_n_rings
== 0)
516 if (copyout(&hwgrp
, hip
, sizeof (hwgrp
)) != 0) {
523 bytes_left
-= sizeof (dld_hwgrpinfo_t
);
526 /* Rest of the tx group */
527 tgrpnum
= mac_hwgrp_num(mh
, MAC_RING_TYPE_TX
);
528 for (i
= 0; i
< tgrpnum
- 1; i
++) {
529 if (sizeof (dld_hwgrpinfo_t
) > bytes_left
) {
534 bzero(&hwgrp
, sizeof (hwgrp
));
535 bcopy(mac_name(mh
), hwgrp
.dhi_link_name
,
536 sizeof (hwgrp
.dhi_link_name
));
537 mac_get_hwtxgrp_info(mh
, i
, &hwgrp
.dhi_grp_num
,
538 &hwgrp
.dhi_n_rings
, hwgrp
.dhi_rings
, &hwgrp
.dhi_grp_type
,
539 &hwgrp
.dhi_n_clnts
, hwgrp
.dhi_clnts
);
540 if (hwgrp
.dhi_n_rings
== 0)
542 if (copyout(&hwgrp
, hip
, sizeof (hwgrp
)) != 0) {
549 bytes_left
-= sizeof (dld_hwgrpinfo_t
);
556 hwgrpp
->dih_n_groups
= totgrps
;
562 drv_ioc_macaddrget(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
564 dld_ioc_macaddrget_t
*magp
= karg
;
565 dld_macaddrinfo_t mai
, *maip
;
566 mac_handle_t mh
= NULL
;
570 zoneid_t zoneid
= crgetzoneid(cred
);
572 if (zoneid
!= GLOBAL_ZONEID
&&
573 zone_check_datalink(&zoneid
, magp
->dig_linkid
) != 0)
577 err
= mac_open_by_linkid(magp
->dig_linkid
, &mh
);
581 maip
= (dld_macaddrinfo_t
*)
582 ((uchar_t
*)arg
+ sizeof (dld_ioc_macaddrget_t
));
583 bytes_left
= magp
->dig_size
;
585 for (i
= 0; i
< mac_addr_factory_num(mh
) + 1; i
++) {
586 if (sizeof (dld_macaddrinfo_t
) > bytes_left
) {
591 bzero(&mai
, sizeof (mai
));
594 /* primary MAC address */
595 mac_unicast_primary_get(mh
, mai
.dmi_addr
);
596 mai
.dmi_addrlen
= mac_addr_len(mh
);
597 mac_unicast_primary_info(mh
, mai
.dmi_client_name
,
600 /* factory MAC address slot */
601 mac_addr_factory_value(mh
, i
, mai
.dmi_addr
,
602 &mai
.dmi_addrlen
, mai
.dmi_client_name
, &is_used
);
607 mai
.dmi_flags
|= DLDIOCMACADDR_USED
;
609 if (copyout(&mai
, maip
, sizeof (mai
)) != 0) {
615 bytes_left
-= sizeof (dld_macaddrinfo_t
);
622 magp
->dig_count
= mac_addr_factory_num(mh
) + 1;
627 * DLDIOC_SET/GETMACPROP
630 drv_ioc_prop_common(dld_ioc_macprop_t
*prop
, intptr_t arg
, boolean_t set
,
631 cred_t
*cred
, int mode
)
634 dls_dl_handle_t dlh
= NULL
;
635 dls_link_t
*dlp
= NULL
;
636 mac_perim_handle_t mph
= NULL
;
637 dld_ioc_macprop_t
*kprop
;
638 datalink_id_t linkid
;
639 datalink_class_t
class;
640 zoneid_t zoneid
= crgetzoneid(cred
);
644 * We only use pr_valsize from prop, as the caller only did a
645 * copyin() for sizeof (dld_ioc_prop_t), which doesn't cover
646 * the property data. We copyin the full dld_ioc_prop_t
647 * including the data into kprop down below.
649 dsize
= sizeof (dld_ioc_macprop_t
) + prop
->pr_valsize
- 1;
650 if (dsize
< prop
->pr_valsize
)
654 * The property data is variable size, so we need to allocate
655 * a buffer for kernel use as this data was not part of the
656 * prop allocation and copyin() done by the framework.
658 if ((kprop
= kmem_alloc(dsize
, KM_NOSLEEP
)) == NULL
)
661 if (ddi_copyin((void *)arg
, kprop
, dsize
, mode
) != 0) {
666 linkid
= kprop
->pr_linkid
;
669 if ((err
= dls_mgmt_get_linkinfo(linkid
, NULL
, &class, NULL
,
670 NULL
)) != 0 || (err
= drv_ioc_checkprivs(class, cred
)) != 0)
674 if ((err
= dls_devnet_hold_tmp(linkid
, &dlh
)) != 0)
676 if ((err
= mac_perim_enter_by_macname(dls_devnet_mac(dlh
), &mph
)) != 0)
678 if ((err
= dls_link_hold(dls_devnet_mac(dlh
), &dlp
)) != 0)
682 * Don't allow a process to get or set properties of a link if that
683 * link doesn't belong to that zone.
685 if (zoneid
!= dls_devnet_getownerzid(dlh
)) {
690 if (!mac_prop_check_size(kprop
->pr_num
, kprop
->pr_valsize
,
691 kprop
->pr_flags
& DLD_PROP_POSSIBLE
)) {
696 switch (kprop
->pr_num
) {
699 dld_ioc_zid_t
*dzp
= (dld_ioc_zid_t
*)kprop
->pr_val
;
701 if (zoneid
!= GLOBAL_ZONEID
) {
705 err
= dls_devnet_setzid(dlh
, dzp
->diz_zid
);
707 kprop
->pr_perm_flags
= MAC_PROP_PERM_RW
;
708 (*(zoneid_t
*)kprop
->pr_val
) = dls_devnet_getzid(dlh
);
711 case MAC_PROP_AUTOPUSH
: {
712 struct dlautopush
*dlap
= (struct dlautopush
*)kprop
->pr_val
;
715 if (kprop
->pr_valsize
!= 0)
716 err
= drv_ioc_setap(linkid
, dlap
);
718 err
= drv_ioc_clrap(linkid
);
720 if (kprop
->pr_valsize
== 0)
723 kprop
->pr_perm_flags
= MAC_PROP_PERM_RW
;
724 err
= drv_ioc_getap(linkid
, dlap
);
728 case MAC_PROP_TAGMODE
:
730 link_tagmode_t mode
= *(link_tagmode_t
*)kprop
->pr_val
;
732 if (mode
!= LINK_TAGMODE_VLANONLY
&&
733 mode
!= LINK_TAGMODE_NORMAL
) {
736 dlp
->dl_tagmode
= mode
;
740 *(link_tagmode_t
*)kprop
->pr_val
= dlp
->dl_tagmode
;
741 kprop
->pr_perm_flags
= MAC_PROP_PERM_RW
;
746 mac_propval_range_t
*rangep
= NULL
;
747 void *default_val
= NULL
;
748 uint_t default_size
= 0;
750 /* set a property value */
752 err
= mac_set_prop(dlp
->dl_mh
, kprop
->pr_num
,
753 kprop
->pr_name
, kprop
->pr_val
, kprop
->pr_valsize
);
758 * Get the property value, default, or possible value
759 * depending on flags passed from the user.
762 /* a property has RW permissions by default */
763 kprop
->pr_perm_flags
= MAC_PROP_PERM_RW
;
765 if (kprop
->pr_flags
& DLD_PROP_POSSIBLE
) {
766 rangep
= (mac_propval_range_t
*)kprop
->pr_val
;
769 * fail if rangep is not aligned to first
770 * member of mac_propval_range_t.
772 ASSERT(IS_P2ALIGNED(rangep
, sizeof (uint_t
)));
773 } else if (kprop
->pr_flags
& DLD_PROP_DEFAULT
) {
774 default_val
= kprop
->pr_val
;
775 default_size
= kprop
->pr_valsize
;
779 * Always return the permissions, and optionally return
780 * the default value or possible values range.
782 err
= mac_prop_info(dlp
->dl_mh
, kprop
->pr_num
, kprop
->pr_name
,
783 default_val
, default_size
, rangep
, &kprop
->pr_perm_flags
);
787 if (default_val
== NULL
&& rangep
== NULL
) {
788 err
= mac_get_prop(dlp
->dl_mh
, kprop
->pr_num
,
789 kprop
->pr_name
, kprop
->pr_val
, kprop
->pr_valsize
);
795 if (!set
&& ddi_copyout(kprop
, (void *)arg
, dsize
, mode
) != 0)
805 if (dlp
!= NULL
&& set
&& err
== 0) {
806 cpuid
= mac_client_intr_cpu(dlp
->dl_mch
);
807 mdip
= mac_get_devinfo(dlp
->dl_mh
);
812 if (mdip
!= NULL
&& cpuid
!= -1)
813 mac_client_set_intr_cpu(mdip
, dlp
->dl_mch
, cpuid
);
817 dls_devnet_rele_tmp(dlh
);
820 kmem_free(kprop
, dsize
);
826 drv_ioc_setprop(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
828 return (drv_ioc_prop_common(karg
, arg
, B_TRUE
, cred
, mode
));
833 drv_ioc_getprop(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
835 return (drv_ioc_prop_common(karg
, arg
, B_FALSE
, cred
, mode
));
841 * This function handles two cases of link renaming. See more in comments above
842 * dls_datalink_rename().
846 drv_ioc_rename(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
848 dld_ioc_rename_t
*dir
= karg
;
851 zoneid_t zoneid
= crgetzoneid(cred
);
852 datalink_class_t
class;
855 if (zoneid
!= GLOBAL_ZONEID
&&
856 (zone_check_datalink(&zoneid
, dir
->dir_linkid1
) != 0 ||
857 dir
->dir_linkid2
!= DATALINK_INVALID_LINKID
&&
858 zone_check_datalink(&zoneid
, dir
->dir_linkid2
) != 0))
861 if ((err
= dls_mgmt_get_linkinfo(dir
->dir_linkid1
, NULL
, &class, NULL
,
865 if ((err
= drv_ioc_checkprivs(class, cred
)) != 0)
868 if ((err
= dls_devnet_rename(dir
->dir_linkid1
, dir
->dir_linkid2
,
869 dir
->dir_link
)) != 0)
872 if (dir
->dir_linkid2
== DATALINK_INVALID_LINKID
)
876 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this
877 * renaming request is to rename a valid physical link (dir_linkid1)
878 * to a "removed" physical link (dir_linkid2, which is removed by DR
879 * or during system shutdown). In this case, the link (specified by
880 * dir_linkid1) would inherit all the configuration of dir_linkid2,
881 * and dir_linkid1 and its configuration would be lost.
883 * Remove per-link autopush configuration of dir_linkid1 in this case.
885 key
= (mod_hash_key_t
)(uintptr_t)dir
->dir_linkid1
;
886 rw_enter(&dld_ap_hash_lock
, RW_WRITER
);
887 if (mod_hash_find(dld_ap_hashp
, key
, &val
) != 0) {
888 rw_exit(&dld_ap_hash_lock
);
892 VERIFY(mod_hash_remove(dld_ap_hashp
, key
, &val
) == 0);
893 kmem_free(val
, sizeof (dld_ap_t
));
894 rw_exit(&dld_ap_hash_lock
);
899 drv_ioc_setap(datalink_id_t linkid
, struct dlautopush
*dlap
)
905 if (dlap
->dap_npush
== 0 || dlap
->dap_npush
> MAXAPUSH
)
909 * Validate that the specified list of modules exist.
911 for (i
= 0; i
< dlap
->dap_npush
; i
++) {
912 if (fmodsw_find(dlap
->dap_aplist
[i
], FMODSW_LOAD
) == NULL
)
917 key
= (mod_hash_key_t
)(uintptr_t)linkid
;
919 rw_enter(&dld_ap_hash_lock
, RW_WRITER
);
920 if (mod_hash_find(dld_ap_hashp
, key
, (mod_hash_val_t
*)&dap
) != 0) {
921 dap
= kmem_zalloc(sizeof (dld_ap_t
), KM_NOSLEEP
);
923 rw_exit(&dld_ap_hash_lock
);
927 dap
->da_linkid
= linkid
;
928 VERIFY(mod_hash_insert(dld_ap_hashp
, key
,
929 (mod_hash_val_t
)dap
) == 0);
933 * Update the configuration.
935 dap
->da_anchor
= dlap
->dap_anchor
;
936 dap
->da_npush
= dlap
->dap_npush
;
937 for (i
= 0; i
< dlap
->dap_npush
; i
++) {
938 (void) strlcpy(dap
->da_aplist
[i
], dlap
->dap_aplist
[i
],
941 rw_exit(&dld_ap_hash_lock
);
947 drv_ioc_getap(datalink_id_t linkid
, struct dlautopush
*dlap
)
952 rw_enter(&dld_ap_hash_lock
, RW_READER
);
953 if (mod_hash_find(dld_ap_hashp
,
954 (mod_hash_key_t
)(uintptr_t)linkid
,
955 (mod_hash_val_t
*)&dap
) != 0) {
956 rw_exit(&dld_ap_hash_lock
);
962 * Retrieve the configuration.
964 dlap
->dap_anchor
= dap
->da_anchor
;
965 dlap
->dap_npush
= dap
->da_npush
;
966 for (i
= 0; i
< dap
->da_npush
; i
++) {
967 (void) strlcpy(dlap
->dap_aplist
[i
], dap
->da_aplist
[i
],
970 rw_exit(&dld_ap_hash_lock
);
976 drv_ioc_clrap(datalink_id_t linkid
)
981 key
= (mod_hash_key_t
)(uintptr_t)linkid
;
983 rw_enter(&dld_ap_hash_lock
, RW_WRITER
);
984 if (mod_hash_find(dld_ap_hashp
, key
, &val
) != 0) {
985 rw_exit(&dld_ap_hash_lock
);
989 VERIFY(mod_hash_remove(dld_ap_hashp
, key
, &val
) == 0);
990 kmem_free(val
, sizeof (dld_ap_t
));
991 rw_exit(&dld_ap_hash_lock
);
1000 drv_ioc_doorserver(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1002 dld_ioc_door_t
*did
= karg
;
1004 return (dls_mgmt_door_set(did
->did_start_door
));
1012 drv_ioc_usagelog(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
,
1015 dld_ioc_usagelog_t
*log_info
= (dld_ioc_usagelog_t
*)karg
;
1018 if (log_info
->ul_type
< MAC_LOGTYPE_LINK
||
1019 log_info
->ul_type
> MAC_LOGTYPE_FLOW
)
1022 if (log_info
->ul_onoff
) {
1023 err
= mac_start_logusage(log_info
->ul_type
,
1024 log_info
->ul_interval
);
1026 mac_stop_logusage(log_info
->ul_type
);
1032 * Process a DLDIOC_ADDFLOW request.
1036 drv_ioc_addflow(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1038 dld_ioc_addflow_t
*afp
= karg
;
1040 return (dld_add_flow(afp
->af_linkid
, afp
->af_name
,
1041 &afp
->af_flow_desc
, &afp
->af_resource_props
));
1045 * Process a DLDIOC_REMOVEFLOW request.
1049 drv_ioc_removeflow(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1051 dld_ioc_removeflow_t
*rfp
= karg
;
1053 return (dld_remove_flow(rfp
->rf_name
));
1057 * Process a DLDIOC_MODIFYFLOW request.
1061 drv_ioc_modifyflow(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1063 dld_ioc_modifyflow_t
*mfp
= karg
;
1065 return (dld_modify_flow(mfp
->mf_name
, &mfp
->mf_resource_props
));
1069 * Process a DLDIOC_WALKFLOW request.
1073 drv_ioc_walkflow(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1075 dld_ioc_walkflow_t
*wfp
= karg
;
1077 return (dld_walk_flow(wfp
, arg
, cred
));
1081 * Check for GLDv3 autopush information. There are three cases:
1083 * 1. If devp points to a GLDv3 datalink and it has autopush configuration,
1084 * fill dlap in with that information and return 0.
1086 * 2. If devp points to a GLDv3 datalink but it doesn't have autopush
1087 * configuration, then replace devp with the physical device (if one
1088 * exists) and return 1. This allows stropen() to find the old-school
1089 * per-driver autopush configuration. (For softmac, the result is that
1090 * the softmac dev_t is replaced with the legacy device's dev_t).
1092 * 3. If neither of the above apply, don't touch the args and return -1.
1095 dld_autopush(dev_t
*devp
, struct dlautopush
*dlap
)
1098 datalink_id_t linkid
;
1101 if (!GLDV3_DRV(getmajor(*devp
)))
1105 * Find the linkid by the link's dev_t.
1107 if (dls_devnet_dev2linkid(*devp
, &linkid
) != 0)
1111 * Find the autopush configuration associated with the linkid.
1113 rw_enter(&dld_ap_hash_lock
, RW_READER
);
1114 if (mod_hash_find(dld_ap_hashp
, (mod_hash_key_t
)(uintptr_t)linkid
,
1115 (mod_hash_val_t
*)&dap
) == 0) {
1117 rw_exit(&dld_ap_hash_lock
);
1120 rw_exit(&dld_ap_hash_lock
);
1122 if (dls_devnet_phydev(linkid
, &phydev
) != 0)
1130 * Secure objects implementation
1135 drv_secobj_ctor(void *buf
, void *arg
, int kmflag
)
1137 bzero(buf
, sizeof (dld_secobj_t
));
1142 drv_secobj_init(void)
1144 rw_init(&drv_secobj_lock
, NULL
, RW_DEFAULT
, NULL
);
1145 drv_secobj_cachep
= kmem_cache_create("drv_secobj_cache",
1146 sizeof (dld_secobj_t
), 0, drv_secobj_ctor
, NULL
,
1147 NULL
, NULL
, NULL
, 0);
1148 drv_secobj_hash
= mod_hash_create_extended("drv_secobj_hash",
1149 SECOBJ_WEP_HASHSZ
, mod_hash_null_keydtor
, mod_hash_null_valdtor
,
1150 mod_hash_bystr
, NULL
, mod_hash_strkey_cmp
, KM_SLEEP
);
1154 drv_secobj_fini(void)
1156 mod_hash_destroy_hash(drv_secobj_hash
);
1157 kmem_cache_destroy(drv_secobj_cachep
);
1158 rw_destroy(&drv_secobj_lock
);
1163 drv_ioc_secobj_set(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1165 dld_ioc_secobj_set_t
*ssp
= karg
;
1166 dld_secobj_t
*sobjp
, *objp
;
1169 sobjp
= &ssp
->ss_obj
;
1171 if (sobjp
->so_class
!= DLD_SECOBJ_CLASS_WEP
&&
1172 sobjp
->so_class
!= DLD_SECOBJ_CLASS_WPA
)
1175 if (sobjp
->so_name
[DLD_SECOBJ_NAME_MAX
- 1] != '\0' ||
1176 sobjp
->so_len
> DLD_SECOBJ_VAL_MAX
)
1179 rw_enter(&drv_secobj_lock
, RW_WRITER
);
1180 err
= mod_hash_find(drv_secobj_hash
, (mod_hash_key_t
)sobjp
->so_name
,
1181 (mod_hash_val_t
*)&objp
);
1183 if ((ssp
->ss_flags
& DLD_SECOBJ_OPT_CREATE
) != 0) {
1184 rw_exit(&drv_secobj_lock
);
1188 ASSERT(err
== MH_ERR_NOTFOUND
);
1189 if ((ssp
->ss_flags
& DLD_SECOBJ_OPT_CREATE
) == 0) {
1190 rw_exit(&drv_secobj_lock
);
1193 objp
= kmem_cache_alloc(drv_secobj_cachep
, KM_SLEEP
);
1194 (void) strlcpy(objp
->so_name
, sobjp
->so_name
,
1195 DLD_SECOBJ_NAME_MAX
);
1197 VERIFY(mod_hash_insert(drv_secobj_hash
,
1198 (mod_hash_key_t
)objp
->so_name
, (mod_hash_val_t
)objp
) == 0);
1200 bcopy(sobjp
->so_val
, objp
->so_val
, sobjp
->so_len
);
1201 objp
->so_len
= sobjp
->so_len
;
1202 objp
->so_class
= sobjp
->so_class
;
1203 rw_exit(&drv_secobj_lock
);
1207 typedef struct dld_secobj_state
{
1212 dld_secobj_t
*ss_objp
;
1213 } dld_secobj_state_t
;
1217 drv_secobj_walker(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
1219 dld_secobj_state_t
*statep
= arg
;
1220 dld_secobj_t
*sobjp
= (dld_secobj_t
*)val
;
1222 if (statep
->ss_free
< sizeof (dld_secobj_t
)) {
1223 statep
->ss_rc
= ENOSPC
;
1224 return (MH_WALK_TERMINATE
);
1226 if (ddi_copyout(sobjp
, statep
->ss_objp
, sizeof (*sobjp
),
1227 statep
->ss_mode
) != 0) {
1228 statep
->ss_rc
= EFAULT
;
1229 return (MH_WALK_TERMINATE
);
1232 statep
->ss_free
-= sizeof (dld_secobj_t
);
1234 return (MH_WALK_CONTINUE
);
1239 drv_ioc_secobj_get(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1241 dld_ioc_secobj_get_t
*sgp
= karg
;
1242 dld_secobj_t
*sobjp
, *objp
;
1245 sobjp
= &sgp
->sg_obj
;
1246 if (sobjp
->so_name
[DLD_SECOBJ_NAME_MAX
- 1] != '\0')
1249 rw_enter(&drv_secobj_lock
, RW_READER
);
1250 if (sobjp
->so_name
[0] != '\0') {
1251 err
= mod_hash_find(drv_secobj_hash
,
1252 (mod_hash_key_t
)sobjp
->so_name
, (mod_hash_val_t
*)&objp
);
1254 ASSERT(err
== MH_ERR_NOTFOUND
);
1255 rw_exit(&drv_secobj_lock
);
1258 bcopy(objp
->so_val
, sobjp
->so_val
, objp
->so_len
);
1259 sobjp
->so_len
= objp
->so_len
;
1260 sobjp
->so_class
= objp
->so_class
;
1263 dld_secobj_state_t state
;
1265 state
.ss_free
= sgp
->sg_size
- sizeof (dld_ioc_secobj_get_t
);
1268 state
.ss_mode
= mode
;
1269 state
.ss_objp
= (dld_secobj_t
*)((uchar_t
*)arg
+
1270 sizeof (dld_ioc_secobj_get_t
));
1272 mod_hash_walk(drv_secobj_hash
, drv_secobj_walker
, &state
);
1273 if (state
.ss_rc
!= 0) {
1274 rw_exit(&drv_secobj_lock
);
1275 return (state
.ss_rc
);
1277 sgp
->sg_count
= state
.ss_count
;
1279 rw_exit(&drv_secobj_lock
);
1285 drv_ioc_secobj_unset(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
,
1288 dld_ioc_secobj_unset_t
*sup
= karg
;
1293 if (sup
->su_name
[DLD_SECOBJ_NAME_MAX
- 1] != '\0')
1296 rw_enter(&drv_secobj_lock
, RW_WRITER
);
1297 err
= mod_hash_find(drv_secobj_hash
, (mod_hash_key_t
)sup
->su_name
,
1298 (mod_hash_val_t
*)&objp
);
1300 ASSERT(err
== MH_ERR_NOTFOUND
);
1301 rw_exit(&drv_secobj_lock
);
1304 VERIFY(mod_hash_remove(drv_secobj_hash
, (mod_hash_key_t
)sup
->su_name
,
1305 (mod_hash_val_t
*)&val
) == 0);
1306 ASSERT(objp
== (dld_secobj_t
*)val
);
1308 kmem_cache_free(drv_secobj_cachep
, objp
);
1309 rw_exit(&drv_secobj_lock
);
1315 drv_ioc_gettran(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
,
1319 mac_perim_handle_t mph
= NULL
;
1320 dls_dl_handle_t dlh
= NULL
;
1321 dls_link_t
*dlp
= NULL
;
1322 dld_ioc_gettran_t
*dgt
= karg
;
1324 if ((ret
= mac_perim_enter_by_linkid(dgt
->dgt_linkid
, &mph
)) != 0)
1327 if ((ret
= dls_devnet_hold_link(dgt
->dgt_linkid
, &dlh
, &dlp
)) != 0)
1331 * Make sure that this link belongs to the zone.
1333 if (crgetzoneid(cred
) != dls_devnet_getownerzid(dlh
)) {
1338 if (dgt
->dgt_tran_id
== DLDIOC_GETTRAN_GETNTRAN
) {
1339 ret
= mac_transceiver_count(dlp
->dl_mh
, &dgt
->dgt_tran_id
);
1341 ret
= mac_transceiver_info(dlp
->dl_mh
, dgt
->dgt_tran_id
,
1342 &dgt
->dgt_present
, &dgt
->dgt_usable
);
1346 if (dlh
!= NULL
&& dlp
!= NULL
) {
1347 dls_devnet_rele_link(dlh
, dlp
);
1351 mac_perim_exit(mph
);
1359 drv_ioc_readtran(void *karg
, intptr_t arg
, int mode
, cred_t
*cred
,
1363 mac_perim_handle_t mph
= NULL
;
1364 dls_dl_handle_t dlh
= NULL
;
1365 dls_link_t
*dlp
= NULL
;
1366 dld_ioc_tranio_t
*dti
= karg
;
1371 * Be strict for the moment
1373 if (dti
->dti_nbytes
!= 256 || dti
->dti_off
!= 0)
1376 if ((ret
= mac_perim_enter_by_linkid(dti
->dti_linkid
, &mph
)) != 0)
1379 if ((ret
= dls_devnet_hold_link(dti
->dti_linkid
, &dlh
, &dlp
)) != 0)
1383 * Make sure that this link belongs to the zone.
1385 if (crgetzoneid(cred
) != dls_devnet_getownerzid(dlh
)) {
1390 bzero(buf
, sizeof (buf
));
1391 if ((ret
= mac_transceiver_read(dlp
->dl_mh
, dti
->dti_tran_id
,
1392 dti
->dti_page
, buf
, dti
->dti_nbytes
, dti
->dti_off
, &nr
)) == 0) {
1393 dti
->dti_nbytes
= nr
;
1394 ret
= ddi_copyout(buf
, (void *)(uintptr_t)dti
->dti_buf
,
1395 sizeof (buf
), mode
);
1399 if (dlh
!= NULL
&& dlp
!= NULL
) {
1400 dls_devnet_rele_link(dlh
, dlp
);
1404 mac_perim_exit(mph
);
1411 * Note that ioctls that modify links have a NULL di_priv_func(), as
1412 * privileges can only be checked after we know the class of the link being
1413 * modified (due to class-specific fine-grained privileges such as
1414 * sys_iptun_config).
1416 static dld_ioc_info_t drv_ioc_list
[] = {
1417 {DLDIOC_ATTR
, DLDCOPYINOUT
, sizeof (dld_ioc_attr_t
),
1418 drv_ioc_attr
, NULL
},
1419 {DLDIOC_PHYS_ATTR
, DLDCOPYINOUT
, sizeof (dld_ioc_phys_attr_t
),
1420 drv_ioc_phys_attr
, NULL
},
1421 {DLDIOC_SECOBJ_SET
, DLDCOPYIN
, sizeof (dld_ioc_secobj_set_t
),
1422 drv_ioc_secobj_set
, secpolicy_dl_config
},
1423 {DLDIOC_SECOBJ_GET
, DLDCOPYINOUT
, sizeof (dld_ioc_secobj_get_t
),
1424 drv_ioc_secobj_get
, secpolicy_dl_config
},
1425 {DLDIOC_SECOBJ_UNSET
, DLDCOPYIN
, sizeof (dld_ioc_secobj_unset_t
),
1426 drv_ioc_secobj_unset
, secpolicy_dl_config
},
1427 {DLDIOC_DOORSERVER
, DLDCOPYIN
, sizeof (dld_ioc_door_t
),
1428 drv_ioc_doorserver
, secpolicy_dl_config
},
1429 {DLDIOC_RENAME
, DLDCOPYIN
, sizeof (dld_ioc_rename_t
),
1430 drv_ioc_rename
, NULL
},
1431 {DLDIOC_MACADDRGET
, DLDCOPYINOUT
, sizeof (dld_ioc_macaddrget_t
),
1432 drv_ioc_macaddrget
, NULL
},
1433 {DLDIOC_ADDFLOW
, DLDCOPYIN
, sizeof (dld_ioc_addflow_t
),
1434 drv_ioc_addflow
, secpolicy_dl_config
},
1435 {DLDIOC_REMOVEFLOW
, DLDCOPYIN
, sizeof (dld_ioc_removeflow_t
),
1436 drv_ioc_removeflow
, secpolicy_dl_config
},
1437 {DLDIOC_MODIFYFLOW
, DLDCOPYIN
, sizeof (dld_ioc_modifyflow_t
),
1438 drv_ioc_modifyflow
, secpolicy_dl_config
},
1439 {DLDIOC_WALKFLOW
, DLDCOPYINOUT
, sizeof (dld_ioc_walkflow_t
),
1440 drv_ioc_walkflow
, NULL
},
1441 {DLDIOC_USAGELOG
, DLDCOPYIN
, sizeof (dld_ioc_usagelog_t
),
1442 drv_ioc_usagelog
, secpolicy_dl_config
},
1443 {DLDIOC_SETMACPROP
, DLDCOPYIN
, sizeof (dld_ioc_macprop_t
),
1444 drv_ioc_setprop
, NULL
},
1445 {DLDIOC_GETMACPROP
, DLDCOPYIN
, sizeof (dld_ioc_macprop_t
),
1446 drv_ioc_getprop
, NULL
},
1447 {DLDIOC_GETHWGRP
, DLDCOPYINOUT
, sizeof (dld_ioc_hwgrpget_t
),
1448 drv_ioc_hwgrpget
, NULL
},
1449 {DLDIOC_GETTRAN
, DLDCOPYINOUT
, sizeof (dld_ioc_gettran_t
),
1450 drv_ioc_gettran
, NULL
},
1451 {DLDIOC_READTRAN
, DLDCOPYINOUT
, sizeof (dld_ioc_tranio_t
),
1452 drv_ioc_readtran
, NULL
}
1455 typedef struct dld_ioc_modentry
{
1456 uint16_t dim_modid
; /* Top 16 bits of ioctl command */
1457 char *dim_modname
; /* Module to be loaded */
1458 int ctrl_node_inst
; /* Ctrl node instance */
1459 dld_ioc_info_t
*dim_list
; /* array of ioctl structures */
1460 uint_t dim_count
; /* number of elements in dim_list */
1461 } dld_ioc_modentry_t
;
1464 * For all modules except for dld, dim_list and dim_count are assigned
1465 * when the modules register their ioctls in dld_ioc_register(). We
1466 * can statically initialize dld's ioctls in-line here; there's no
1467 * need for it to call dld_ioc_register() itself. ctrl_node_inst controls
1468 * whether an instance of the device will be held or the driver. If set to
1469 * a non-negative integer, device instance specified in ctrl_node_inst will
1470 * be held; so dld_ioc_register() _must_ be called in xxx_attach() routine of
1471 * the driver. If set to -1, driver will be held; so dld_ioc_register() _must_
1472 * be called in xxx_init() routine of the driver.
1474 static dld_ioc_modentry_t dld_ioc_modtable
[] = {
1475 {DLD_IOC
, "dld", 0, drv_ioc_list
, DLDIOCCNT(drv_ioc_list
)},
1476 {AGGR_IOC
, "aggr", 0, NULL
, 0},
1477 {VNIC_IOC
, "vnic", 0, NULL
, 0},
1478 {SIMNET_IOC
, "simnet", 0, NULL
, 0},
1479 {BRIDGE_IOC
, "bridge", 0, NULL
, 0},
1480 {IPTUN_IOC
, "iptun", 0, NULL
, 0},
1481 {IBPART_IOC
, "ibp", -1, NULL
, 0}
1483 #define DLDIOC_CNT \
1484 (sizeof (dld_ioc_modtable) / sizeof (dld_ioc_modentry_t))
1486 static dld_ioc_modentry_t
*
1487 dld_ioc_findmod(uint16_t modid
)
1491 for (i
= 0; i
< DLDIOC_CNT
; i
++) {
1492 if (modid
== dld_ioc_modtable
[i
].dim_modid
)
1493 return (&dld_ioc_modtable
[i
]);
1499 dld_ioc_register(uint16_t modid
, dld_ioc_info_t
*list
, uint_t count
)
1501 dld_ioc_modentry_t
*dim
= dld_ioc_findmod(modid
);
1506 dim
->dim_list
= list
;
1507 dim
->dim_count
= count
;
1512 dld_ioc_unregister(uint16_t modid
)
1514 VERIFY(dld_ioc_register(modid
, NULL
, 0) == 0);
1518 * The general design with GLDv3 ioctls is that all ioctls issued
1519 * through /dev/dld go through this drv_ioctl() function. This
1520 * function handles all ioctls on behalf of modules listed in
1523 * When an ioctl is received, this function looks for the associated
1524 * module-id-specific ioctl information using dld_ioc_findmod(). The
1525 * call to ddi_hold_driver() or ddi_hold_devi_by_instance() on the
1526 * associated device will cause the kernel module responsible for the
1527 * ioctl to be loaded if it's not already loaded, which should result
1528 * in that module calling dld_ioc_register(), thereby filling in the
1529 * dim_list containing the details for the ioctl being processed.
1531 * This function can then perform operations such as copyin() data and
1532 * do credential checks based on the registered ioctl information,
1533 * then issue the callback function di_func() registered by the
1534 * responsible module. Upon return, the appropriate copyout()
1535 * operation can be performed and the operation completes.
1539 drv_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*cred
, int *rvalp
)
1541 dld_ioc_modentry_t
*dim
;
1542 dld_ioc_info_t
*info
;
1543 dev_info_t
*dip
= NULL
;
1544 struct dev_ops
*dops
= NULL
;
1550 if ((dim
= dld_ioc_findmod(DLD_IOC_MODID(cmd
))) == NULL
)
1553 major
= ddi_name_to_major(dim
->dim_modname
);
1555 if (dim
->ctrl_node_inst
== -1) {
1557 * No dedicated instance to process ioctls.
1558 * dld_ioc_register() is called in xxx_init().
1560 dops
= ddi_hold_driver(major
);
1563 * Dedicated instance to handle ioctl.
1564 * dld_ioc_register() is called in xxx_attach().
1566 dip
= ddi_hold_devi_by_instance(major
, dim
->ctrl_node_inst
, 0);
1569 if ((dip
== NULL
&& dops
== NULL
) || dim
->dim_list
== NULL
) {
1574 for (i
= 0; i
< dim
->dim_count
; i
++) {
1575 if (cmd
== dim
->dim_list
[i
].di_cmd
)
1578 if (i
== dim
->dim_count
) {
1583 info
= &dim
->dim_list
[i
];
1585 if (info
->di_priv_func
!= NULL
&&
1586 (err
= info
->di_priv_func(cred
)) != 0)
1589 sz
= info
->di_argsize
;
1590 if ((buf
= kmem_zalloc(sz
, KM_NOSLEEP
)) == NULL
) {
1595 if ((info
->di_flags
& DLDCOPYIN
) &&
1596 ddi_copyin((void *)arg
, buf
, sz
, mode
) != 0) {
1601 err
= info
->di_func(buf
, arg
, mode
, cred
, rvalp
);
1603 if ((info
->di_flags
& DLDCOPYOUT
) &&
1604 ddi_copyout(buf
, (void *)arg
, sz
, mode
) != 0 && err
== 0)
1611 ddi_release_devi(dip
);
1613 ddi_rele_driver(major
);