1d62bc4baSyz /*
2d62bc4baSyz * CDDL HEADER START
3d62bc4baSyz *
4d62bc4baSyz * The contents of this file are subject to the terms of the
5d62bc4baSyz * Common Development and Distribution License (the "License").
6d62bc4baSyz * You may not use this file except in compliance with the License.
7d62bc4baSyz *
8d62bc4baSyz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz * See the License for the specific language governing permissions
11d62bc4baSyz * and limitations under the License.
12d62bc4baSyz *
13d62bc4baSyz * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz *
19d62bc4baSyz * CDDL HEADER END
20d62bc4baSyz */
21d62bc4baSyz
22d62bc4baSyz /*
2332715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24d62bc4baSyz */
25d62bc4baSyz
26d62bc4baSyz /*
27d62bc4baSyz * Main door handler functions used by dlmgmtd to process the different door
28d62bc4baSyz * call requests. Door call requests can come from the user-land applications,
29024b0a25Sseb * or from the kernel.
302b24ab6bSSebastien Roy *
312b24ab6bSSebastien Roy * Note on zones handling:
322b24ab6bSSebastien Roy *
332b24ab6bSSebastien Roy * There are two zoneid's associated with a link. One is the zoneid of the
342b24ab6bSSebastien Roy * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and
352b24ab6bSSebastien Roy * the other is the zoneid of the zone where the link is currently assigned
362b24ab6bSSebastien Roy * (the "zone" link property). The two can be different if a datalink is
372b24ab6bSSebastien Roy * created in the global zone and subsequently assigned to a non-global zone
382b24ab6bSSebastien Roy * via zonecfg or via explicitly setting the "zone" link property.
392b24ab6bSSebastien Roy *
402b24ab6bSSebastien Roy * Door clients can see links that were created in their zone, and links that
412b24ab6bSSebastien Roy * are currently assigned to their zone. Door clients in a zone can only
422b24ab6bSSebastien Roy * modify links that were created in their zone.
432b24ab6bSSebastien Roy *
442b24ab6bSSebastien Roy * The datalink ID space is global, while each zone has its own datalink name
452b24ab6bSSebastien Roy * space. This allows each zone to have complete freedom over the names that
462b24ab6bSSebastien Roy * they assign to links created within the zone.
47d62bc4baSyz */
48d62bc4baSyz
49d62bc4baSyz #include <assert.h>
50d62bc4baSyz #include <alloca.h>
51024b0a25Sseb #include <errno.h>
52024b0a25Sseb #include <priv_utils.h>
53024b0a25Sseb #include <stdlib.h>
54d62bc4baSyz #include <strings.h>
550dc974a9SCathy Zhou #include <syslog.h>
560dc974a9SCathy Zhou #include <sys/sysevent/eventdefs.h>
572b24ab6bSSebastien Roy #include <zone.h>
580dc974a9SCathy Zhou #include <libsysevent.h>
59d62bc4baSyz #include <libdlmgmt.h>
600dc974a9SCathy Zhou #include <librcm.h>
61d62bc4baSyz #include "dlmgmt_impl.h"
62d62bc4baSyz
6332715170SCathy Zhou typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t,
6432715170SCathy Zhou ucred_t *);
65024b0a25Sseb
66024b0a25Sseb typedef struct dlmgmt_door_info_s {
67024b0a25Sseb uint_t di_cmd;
68024b0a25Sseb size_t di_reqsz;
69024b0a25Sseb size_t di_acksz;
70024b0a25Sseb dlmgmt_door_handler_t *di_handler;
71024b0a25Sseb } dlmgmt_door_info_t;
72024b0a25Sseb
732b24ab6bSSebastien Roy /*
742b24ab6bSSebastien Roy * Check if the caller has the required privileges to operate on a link of the
752b24ab6bSSebastien Roy * given class.
762b24ab6bSSebastien Roy */
772b24ab6bSSebastien Roy static int
dlmgmt_checkprivs(datalink_class_t class,ucred_t * cred)782b24ab6bSSebastien Roy dlmgmt_checkprivs(datalink_class_t class, ucred_t *cred)
792b24ab6bSSebastien Roy {
802b24ab6bSSebastien Roy const priv_set_t *eset;
812b24ab6bSSebastien Roy
822b24ab6bSSebastien Roy eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
832b24ab6bSSebastien Roy if (eset != NULL && ((class == DATALINK_CLASS_IPTUN &&
842b24ab6bSSebastien Roy priv_ismember(eset, PRIV_SYS_IPTUN_CONFIG)) ||
852b24ab6bSSebastien Roy priv_ismember(eset, PRIV_SYS_DL_CONFIG) ||
862b24ab6bSSebastien Roy priv_ismember(eset, PRIV_SYS_NET_CONFIG)))
872b24ab6bSSebastien Roy return (0);
882b24ab6bSSebastien Roy return (EACCES);
892b24ab6bSSebastien Roy }
90024b0a25Sseb
91d62bc4baSyz static dlmgmt_link_t *
dlmgmt_getlink_by_dev(char * devname,zoneid_t zoneid)922b24ab6bSSebastien Roy dlmgmt_getlink_by_dev(char *devname, zoneid_t zoneid)
93d62bc4baSyz {
94d62bc4baSyz dlmgmt_link_t *linkp = avl_first(&dlmgmt_id_avl);
95d62bc4baSyz
96d62bc4baSyz for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
972b24ab6bSSebastien Roy if (link_is_visible(linkp, zoneid) &&
982b24ab6bSSebastien Roy (linkp->ll_class == DATALINK_CLASS_PHYS) &&
99d62bc4baSyz linkattr_equal(&(linkp->ll_head), FDEVNAME, devname,
100d62bc4baSyz strlen(devname) + 1)) {
101d62bc4baSyz return (linkp);
102d62bc4baSyz }
103d62bc4baSyz }
104d62bc4baSyz return (NULL);
105d62bc4baSyz }
106d62bc4baSyz
1070dc974a9SCathy Zhou /*
1080dc974a9SCathy Zhou * Post the EC_DATALINK sysevent for the given linkid. This sysevent will
1090dc974a9SCathy Zhou * be consumed by the datalink sysevent module.
1100dc974a9SCathy Zhou */
1110dc974a9SCathy Zhou static void
dlmgmt_post_sysevent(const char * subclass,datalink_id_t linkid,boolean_t reconfigured)1125093e103SCathy Zhou dlmgmt_post_sysevent(const char *subclass, datalink_id_t linkid,
1135093e103SCathy Zhou boolean_t reconfigured)
1140dc974a9SCathy Zhou {
1150dc974a9SCathy Zhou nvlist_t *nvl = NULL;
1160dc974a9SCathy Zhou sysevent_id_t eid;
1170dc974a9SCathy Zhou int err;
1180dc974a9SCathy Zhou
1190dc974a9SCathy Zhou if (((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0) ||
1205093e103SCathy Zhou ((err = nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid)) != 0) ||
1215093e103SCathy Zhou ((err = nvlist_add_boolean_value(nvl, RCM_NV_RECONFIGURED,
1225093e103SCathy Zhou reconfigured)) != 0)) {
1230dc974a9SCathy Zhou goto done;
1240dc974a9SCathy Zhou }
1250dc974a9SCathy Zhou
1260dc974a9SCathy Zhou if (sysevent_post_event(EC_DATALINK, (char *)subclass, SUNW_VENDOR,
1270dc974a9SCathy Zhou (char *)progname, nvl, &eid) == -1) {
1280dc974a9SCathy Zhou err = errno;
1290dc974a9SCathy Zhou }
1300dc974a9SCathy Zhou
1310dc974a9SCathy Zhou done:
1320dc974a9SCathy Zhou if (err != 0) {
1330dc974a9SCathy Zhou dlmgmt_log(LOG_WARNING, "dlmgmt_post_sysevent(%d) failed: %s",
1340dc974a9SCathy Zhou linkid, strerror(err));
1350dc974a9SCathy Zhou }
1360dc974a9SCathy Zhou nvlist_free(nvl);
1370dc974a9SCathy Zhou }
1380dc974a9SCathy Zhou
13932715170SCathy Zhou /* ARGSUSED */
140d62bc4baSyz static void
dlmgmt_upcall_create(void * argp,void * retp,size_t * sz,zoneid_t zoneid,ucred_t * cred)14132715170SCathy Zhou dlmgmt_upcall_create(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
14232715170SCathy Zhou ucred_t *cred)
143d62bc4baSyz {
144024b0a25Sseb dlmgmt_upcall_arg_create_t *create = argp;
145024b0a25Sseb dlmgmt_create_retval_t *retvalp = retp;
146d62bc4baSyz datalink_class_t class;
147d62bc4baSyz uint32_t media;
148d62bc4baSyz dlmgmt_link_t *linkp;
149d62bc4baSyz char link[MAXLINKNAMELEN];
150d62bc4baSyz uint32_t flags;
1518a1c9a22SCathy Zhou int err = 0;
152d62bc4baSyz boolean_t created = B_FALSE;
1535093e103SCathy Zhou boolean_t reconfigured = B_FALSE;
154d62bc4baSyz
155d62bc4baSyz /*
156d62bc4baSyz * Determine whether this link is persistent. Note that this request
157d62bc4baSyz * is coming from kernel so this link must be active.
158d62bc4baSyz */
159d62bc4baSyz flags = DLMGMT_ACTIVE | (create->ld_persist ? DLMGMT_PERSIST : 0);
160d62bc4baSyz
161d62bc4baSyz class = create->ld_class;
162d62bc4baSyz media = create->ld_media;
163d62bc4baSyz
164d62bc4baSyz /*
165d62bc4baSyz * Hold the writer lock to update the link table.
166d62bc4baSyz */
167d62bc4baSyz dlmgmt_table_lock(B_TRUE);
168d62bc4baSyz
1692b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(class, cred)) != 0)
1702b24ab6bSSebastien Roy goto done;
1712b24ab6bSSebastien Roy
172d62bc4baSyz /*
173d62bc4baSyz * Check to see whether this is the reattachment of an existing
174d62bc4baSyz * physical link. If so, return its linkid.
175d62bc4baSyz */
1762b24ab6bSSebastien Roy if ((class == DATALINK_CLASS_PHYS) && (linkp =
1772b24ab6bSSebastien Roy dlmgmt_getlink_by_dev(create->ld_devname, zoneid)) != NULL) {
1788a1c9a22SCathy Zhou if (linkattr_equal(&(linkp->ll_head), FPHYMAJ,
1798a1c9a22SCathy Zhou &create->ld_phymaj, sizeof (uint64_t)) &&
1808a1c9a22SCathy Zhou linkattr_equal(&(linkp->ll_head), FPHYINST,
1818a1c9a22SCathy Zhou &create->ld_phyinst, sizeof (uint64_t)) &&
1828a1c9a22SCathy Zhou (linkp->ll_flags & flags) == flags) {
1838a1c9a22SCathy Zhou /*
1848a1c9a22SCathy Zhou * If nothing has been changed, directly return.
1858a1c9a22SCathy Zhou */
1868a1c9a22SCathy Zhou goto noupdate;
1878a1c9a22SCathy Zhou }
1888a1c9a22SCathy Zhou
189d62bc4baSyz err = linkattr_set(&(linkp->ll_head), FPHYMAJ,
190d62bc4baSyz &create->ld_phymaj, sizeof (uint64_t), DLADM_TYPE_UINT64);
191d62bc4baSyz if (err != 0)
192d62bc4baSyz goto done;
193d62bc4baSyz
194d62bc4baSyz err = linkattr_set(&(linkp->ll_head), FPHYINST,
195d62bc4baSyz &create->ld_phyinst, sizeof (uint64_t), DLADM_TYPE_UINT64);
196d62bc4baSyz if (err != 0)
197d62bc4baSyz goto done;
198d62bc4baSyz
1995093e103SCathy Zhou /*
2005093e103SCathy Zhou * This is a device that is dynamic reconfigured.
2015093e103SCathy Zhou */
2025093e103SCathy Zhou if ((linkp->ll_flags & DLMGMT_ACTIVE) == 0)
2035093e103SCathy Zhou reconfigured = B_TRUE;
2045093e103SCathy Zhou
2052b24ab6bSSebastien Roy if ((err = link_activate(linkp)) != 0)
2062b24ab6bSSebastien Roy goto done;
207d62bc4baSyz linkp->ll_flags |= flags;
208d62bc4baSyz linkp->ll_gen++;
2095093e103SCathy Zhou
210d62bc4baSyz goto done;
211d62bc4baSyz }
212d62bc4baSyz
213d62bc4baSyz if ((err = dlmgmt_create_common(create->ld_devname, class, media,
2142b24ab6bSSebastien Roy zoneid, flags, &linkp)) == EEXIST) {
215d62bc4baSyz /*
216d62bc4baSyz * The link name already exists. Return error if this is a
217d62bc4baSyz * non-physical link (in that case, the link name must be
218d62bc4baSyz * the same as the given name).
219d62bc4baSyz */
220d62bc4baSyz if (class != DATALINK_CLASS_PHYS)
221d62bc4baSyz goto done;
222d62bc4baSyz
223d62bc4baSyz /*
224d62bc4baSyz * The physical link's name already exists, request
225d62bc4baSyz * a suggested link name: net<nextppa>
226d62bc4baSyz */
2272b24ab6bSSebastien Roy err = dlmgmt_generate_name("net", link, MAXLINKNAMELEN, zoneid);
228d62bc4baSyz if (err != 0)
229d62bc4baSyz goto done;
230d62bc4baSyz
2312b24ab6bSSebastien Roy err = dlmgmt_create_common(link, class, media, zoneid, flags,
2322b24ab6bSSebastien Roy &linkp);
233d62bc4baSyz }
234d62bc4baSyz
235d62bc4baSyz if (err != 0)
236d62bc4baSyz goto done;
237d62bc4baSyz
238d62bc4baSyz created = B_TRUE;
239d62bc4baSyz
240d62bc4baSyz /*
241d62bc4baSyz * This is a new link. Only need to persist link attributes for
242d62bc4baSyz * physical links.
243d62bc4baSyz */
244d62bc4baSyz if (class == DATALINK_CLASS_PHYS &&
245d62bc4baSyz (((err = linkattr_set(&linkp->ll_head, FDEVNAME, create->ld_devname,
246d62bc4baSyz strlen(create->ld_devname) + 1, DLADM_TYPE_STR)) != 0) ||
247d62bc4baSyz ((err = linkattr_set(&linkp->ll_head, FPHYMAJ, &create->ld_phymaj,
248d62bc4baSyz sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0) ||
249d62bc4baSyz ((err = linkattr_set(&linkp->ll_head, FPHYINST, &create->ld_phyinst,
250d62bc4baSyz sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0))) {
251d62bc4baSyz (void) dlmgmt_destroy_common(linkp, flags);
252d62bc4baSyz }
253d62bc4baSyz
254d62bc4baSyz done:
2552b24ab6bSSebastien Roy if ((err == 0) && ((err = dlmgmt_write_db_entry(linkp->ll_link, linkp,
256d62bc4baSyz linkp->ll_flags)) != 0) && created) {
257