xref: /titanic_53/usr/src/cmd/ldmad/ldma_device.c (revision 49bfb42b00abac0958a1308f4233e366fd083366)
1*49bfb42bSAlexandre Chartre /*
2*49bfb42bSAlexandre Chartre  * CDDL HEADER START
3*49bfb42bSAlexandre Chartre  *
4*49bfb42bSAlexandre Chartre  * The contents of this file are subject to the terms of the
5*49bfb42bSAlexandre Chartre  * Common Development and Distribution License (the "License").
6*49bfb42bSAlexandre Chartre  * You may not use this file except in compliance with the License.
7*49bfb42bSAlexandre Chartre  *
8*49bfb42bSAlexandre Chartre  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*49bfb42bSAlexandre Chartre  * or http://www.opensolaris.org/os/licensing.
10*49bfb42bSAlexandre Chartre  * See the License for the specific language governing permissions
11*49bfb42bSAlexandre Chartre  * and limitations under the License.
12*49bfb42bSAlexandre Chartre  *
13*49bfb42bSAlexandre Chartre  * When distributing Covered Code, include this CDDL HEADER in each
14*49bfb42bSAlexandre Chartre  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*49bfb42bSAlexandre Chartre  * If applicable, add the following below this CDDL HEADER, with the
16*49bfb42bSAlexandre Chartre  * fields enclosed by brackets "[]" replaced with your own identifying
17*49bfb42bSAlexandre Chartre  * information: Portions Copyright [yyyy] [name of copyright owner]
18*49bfb42bSAlexandre Chartre  *
19*49bfb42bSAlexandre Chartre  * CDDL HEADER END
20*49bfb42bSAlexandre Chartre  */
21*49bfb42bSAlexandre Chartre 
22*49bfb42bSAlexandre Chartre /*
23*49bfb42bSAlexandre Chartre  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*49bfb42bSAlexandre Chartre  * Use is subject to license terms.
25*49bfb42bSAlexandre Chartre  */
26*49bfb42bSAlexandre Chartre 
27*49bfb42bSAlexandre Chartre /*
28*49bfb42bSAlexandre Chartre  * Logical Domains Device Agent
29*49bfb42bSAlexandre Chartre  */
30*49bfb42bSAlexandre Chartre 
31*49bfb42bSAlexandre Chartre #include <errno.h>
32*49bfb42bSAlexandre Chartre #include <fcntl.h>
33*49bfb42bSAlexandre Chartre #include <libdladm.h>
34*49bfb42bSAlexandre Chartre #include <libdllink.h>
35*49bfb42bSAlexandre Chartre #include <libds.h>
36*49bfb42bSAlexandre Chartre #include <stdio.h>
37*49bfb42bSAlexandre Chartre #include <stdlib.h>
38*49bfb42bSAlexandre Chartre #include <strings.h>
39*49bfb42bSAlexandre Chartre #include <unistd.h>
40*49bfb42bSAlexandre Chartre #include <sys/param.h>
41*49bfb42bSAlexandre Chartre #include <sys/types.h>
42*49bfb42bSAlexandre Chartre #include <sys/stat.h>
43*49bfb42bSAlexandre Chartre 
44*49bfb42bSAlexandre Chartre #include "ldma.h"
45*49bfb42bSAlexandre Chartre 
46*49bfb42bSAlexandre Chartre #define	LDMA_MODULE	LDMA_NAME_DEVICE
47*49bfb42bSAlexandre Chartre 
48*49bfb42bSAlexandre Chartre #define	LDMA_NVERSIONS	(sizeof (ldma_versions) / sizeof (ds_ver_t))
49*49bfb42bSAlexandre Chartre #define	LDMA_NHANDLERS	(sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t))
50*49bfb42bSAlexandre Chartre 
51*49bfb42bSAlexandre Chartre static ldm_msg_func_t ldma_dev_validate_path;
52*49bfb42bSAlexandre Chartre static ldm_msg_func_t ldma_dev_validate_nic;
53*49bfb42bSAlexandre Chartre 
54*49bfb42bSAlexandre Chartre static ds_ver_t ldma_versions[] = { { 1, 0 } };
55*49bfb42bSAlexandre Chartre 
56*49bfb42bSAlexandre Chartre static ldma_msg_handler_t ldma_handlers[] = {
57*49bfb42bSAlexandre Chartre 	{ LDMA_MSGDEV_VALIDATE_PATH,	ldma_dev_validate_path },
58*49bfb42bSAlexandre Chartre 	{ LDMA_MSGDEV_VALIDATE_NIC,	ldma_dev_validate_nic }
59*49bfb42bSAlexandre Chartre };
60*49bfb42bSAlexandre Chartre 
61*49bfb42bSAlexandre Chartre ldma_agent_info_t ldma_device_info = {
62*49bfb42bSAlexandre Chartre 	LDMA_NAME_DEVICE,
63*49bfb42bSAlexandre Chartre 	ldma_versions, LDMA_NVERSIONS,
64*49bfb42bSAlexandre Chartre 	ldma_handlers, LDMA_NHANDLERS
65*49bfb42bSAlexandre Chartre };
66*49bfb42bSAlexandre Chartre 
67*49bfb42bSAlexandre Chartre /*ARGSUSED*/
68*49bfb42bSAlexandre Chartre static ldma_request_status_t
69*49bfb42bSAlexandre Chartre ldma_dev_validate_path(ds_ver_t *ver, ldma_message_header_t *request,
70*49bfb42bSAlexandre Chartre     size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
71*49bfb42bSAlexandre Chartre {
72*49bfb42bSAlexandre Chartre 	ldma_message_header_t *reply = NULL;
73*49bfb42bSAlexandre Chartre 	ldma_request_status_t status;
74*49bfb42bSAlexandre Chartre 	struct stat st;
75*49bfb42bSAlexandre Chartre 	char *path = NULL;
76*49bfb42bSAlexandre Chartre 	uint32_t *path_type, reply_dlen;
77*49bfb42bSAlexandre Chartre 	uint32_t plen;
78*49bfb42bSAlexandre Chartre 	int fd;
79*49bfb42bSAlexandre Chartre 
80*49bfb42bSAlexandre Chartre 	plen = request->msg_info;
81*49bfb42bSAlexandre Chartre 	if (plen == 0 || plen > MAXPATHLEN || plen > request_dlen) {
82*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_INVALID;
83*49bfb42bSAlexandre Chartre 		goto done;
84*49bfb42bSAlexandre Chartre 	}
85*49bfb42bSAlexandre Chartre 
86*49bfb42bSAlexandre Chartre 	path = malloc(plen + 1);
87*49bfb42bSAlexandre Chartre 	if (path == NULL) {
88*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_FAILED;
89*49bfb42bSAlexandre Chartre 		goto done;
90*49bfb42bSAlexandre Chartre 	}
91*49bfb42bSAlexandre Chartre 
92*49bfb42bSAlexandre Chartre 	(void) strncpy(path, LDMA_HDR2DATA(request), plen);
93*49bfb42bSAlexandre Chartre 	path[plen] = '\0';
94*49bfb42bSAlexandre Chartre 
95*49bfb42bSAlexandre Chartre 	LDMA_DBG("VALIDATE_PATH(%s)", path);
96*49bfb42bSAlexandre Chartre 
97*49bfb42bSAlexandre Chartre 	reply_dlen = sizeof (uint32_t);
98*49bfb42bSAlexandre Chartre 	reply = ldma_alloc_result_msg(request, reply_dlen);
99*49bfb42bSAlexandre Chartre 	if (reply == NULL) {
100*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_FAILED;
101*49bfb42bSAlexandre Chartre 		goto done;
102*49bfb42bSAlexandre Chartre 	}
103*49bfb42bSAlexandre Chartre 
104*49bfb42bSAlexandre Chartre 	/* LINTED E_BAD_PTR_CAST_ALIGN */
105*49bfb42bSAlexandre Chartre 	path_type = (uint32_t *)(LDMA_HDR2DATA(reply));
106*49bfb42bSAlexandre Chartre 
107*49bfb42bSAlexandre Chartre 	reply->msg_info = 0x0;
108*49bfb42bSAlexandre Chartre 
109*49bfb42bSAlexandre Chartre 	/* check if path exists */
110*49bfb42bSAlexandre Chartre 	if (stat(path, &st) != 0) {
111*49bfb42bSAlexandre Chartre 
112*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_PATH(%s): stat failed with error %d",
113*49bfb42bSAlexandre Chartre 		    path, errno);
114*49bfb42bSAlexandre Chartre 
115*49bfb42bSAlexandre Chartre 		switch (errno) {
116*49bfb42bSAlexandre Chartre 
117*49bfb42bSAlexandre Chartre 		case EACCES:
118*49bfb42bSAlexandre Chartre 		case ELOOP:
119*49bfb42bSAlexandre Chartre 		case ENOENT:
120*49bfb42bSAlexandre Chartre 		case ENOLINK:
121*49bfb42bSAlexandre Chartre 		case ENOTDIR:
122*49bfb42bSAlexandre Chartre 			/* path is inaccessible, the request is completed */
123*49bfb42bSAlexandre Chartre 			status = LDMA_REQ_COMPLETED;
124*49bfb42bSAlexandre Chartre 			break;
125*49bfb42bSAlexandre Chartre 
126*49bfb42bSAlexandre Chartre 		case ENAMETOOLONG:
127*49bfb42bSAlexandre Chartre 			status = LDMA_REQ_INVALID;
128*49bfb42bSAlexandre Chartre 			break;
129*49bfb42bSAlexandre Chartre 
130*49bfb42bSAlexandre Chartre 		default:
131*49bfb42bSAlexandre Chartre 			/* request has failed */
132*49bfb42bSAlexandre Chartre 			status = LDMA_REQ_FAILED;
133*49bfb42bSAlexandre Chartre 			break;
134*49bfb42bSAlexandre Chartre 		}
135*49bfb42bSAlexandre Chartre 
136*49bfb42bSAlexandre Chartre 		goto done;
137*49bfb42bSAlexandre Chartre 	}
138*49bfb42bSAlexandre Chartre 
139*49bfb42bSAlexandre Chartre 	status = LDMA_REQ_COMPLETED;
140*49bfb42bSAlexandre Chartre 
141*49bfb42bSAlexandre Chartre 	reply->msg_info |= LDMA_DEVPATH_EXIST;
142*49bfb42bSAlexandre Chartre 
143*49bfb42bSAlexandre Chartre 	LDMA_DBG("VALIDATE_PATH(%s): file mode = 0x%x", path, st.st_mode);
144*49bfb42bSAlexandre Chartre 
145*49bfb42bSAlexandre Chartre 	switch (st.st_mode & S_IFMT) {
146*49bfb42bSAlexandre Chartre 
147*49bfb42bSAlexandre Chartre 	case S_IFREG:
148*49bfb42bSAlexandre Chartre 		*path_type = LDMA_DEVPATH_TYPE_FILE;
149*49bfb42bSAlexandre Chartre 		break;
150*49bfb42bSAlexandre Chartre 
151*49bfb42bSAlexandre Chartre 	case S_IFCHR:
152*49bfb42bSAlexandre Chartre 	case S_IFBLK:
153*49bfb42bSAlexandre Chartre 		*path_type = LDMA_DEVPATH_TYPE_DEVICE;
154*49bfb42bSAlexandre Chartre 		break;
155*49bfb42bSAlexandre Chartre 
156*49bfb42bSAlexandre Chartre 	default:
157*49bfb42bSAlexandre Chartre 		/* we don't advertise other types (fifo, directory...) */
158*49bfb42bSAlexandre Chartre 		*path_type = 0;
159*49bfb42bSAlexandre Chartre 	}
160*49bfb42bSAlexandre Chartre 
161*49bfb42bSAlexandre Chartre 	/* check if path can be opened read/write */
162*49bfb42bSAlexandre Chartre 	if ((fd = open(path, O_RDWR)) != -1) {
163*49bfb42bSAlexandre Chartre 		reply->msg_info |= LDMA_DEVPATH_OPENRW | LDMA_DEVPATH_OPENRO;
164*49bfb42bSAlexandre Chartre 		(void) close(fd);
165*49bfb42bSAlexandre Chartre 	} else {
166*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_PATH(%s): open RDWR failed with error %d",
167*49bfb42bSAlexandre Chartre 		    path, errno);
168*49bfb42bSAlexandre Chartre 
169*49bfb42bSAlexandre Chartre 		/* check if path can be opened read only */
170*49bfb42bSAlexandre Chartre 		if ((fd = open(path, O_RDONLY)) != -1) {
171*49bfb42bSAlexandre Chartre 			reply->msg_info |= LDMA_DEVPATH_OPENRO;
172*49bfb42bSAlexandre Chartre 			(void) close(fd);
173*49bfb42bSAlexandre Chartre 		} else {
174*49bfb42bSAlexandre Chartre 			LDMA_DBG("VALIDATE_PATH(%s): open RDONLY failed "
175*49bfb42bSAlexandre Chartre 			    "with error %d", path, errno);
176*49bfb42bSAlexandre Chartre 		}
177*49bfb42bSAlexandre Chartre 	}
178*49bfb42bSAlexandre Chartre 
179*49bfb42bSAlexandre Chartre done:
180*49bfb42bSAlexandre Chartre 	if (status != LDMA_REQ_COMPLETED) {
181*49bfb42bSAlexandre Chartre 		/*
182*49bfb42bSAlexandre Chartre 		 * We don't provide a reply message if the request has not
183*49bfb42bSAlexandre Chartre 		 * been completed. The LDoms agent daemon will send an
184*49bfb42bSAlexandre Chartre 		 * appropriate reply based on the return code of this function.
185*49bfb42bSAlexandre Chartre 		 */
186*49bfb42bSAlexandre Chartre 		free(reply);
187*49bfb42bSAlexandre Chartre 		reply = NULL;
188*49bfb42bSAlexandre Chartre 		reply_dlen = 0;
189*49bfb42bSAlexandre Chartre 
190*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_PATH(%s): return error %d",
191*49bfb42bSAlexandre Chartre 		    (path)? path : "<none>", status);
192*49bfb42bSAlexandre Chartre 	} else {
193*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_PATH(%s): return status=0x%x type=0x%x",
194*49bfb42bSAlexandre Chartre 		    path, reply->msg_info, *path_type);
195*49bfb42bSAlexandre Chartre 	}
196*49bfb42bSAlexandre Chartre 
197*49bfb42bSAlexandre Chartre 	free(path);
198*49bfb42bSAlexandre Chartre 	*replyp = reply;
199*49bfb42bSAlexandre Chartre 	*reply_dlenp = reply_dlen;
200*49bfb42bSAlexandre Chartre 
201*49bfb42bSAlexandre Chartre 	return (status);
202*49bfb42bSAlexandre Chartre }
203*49bfb42bSAlexandre Chartre 
204*49bfb42bSAlexandre Chartre /*
205*49bfb42bSAlexandre Chartre  * We check that the device is a network interface (NIC) using libdladm.
206*49bfb42bSAlexandre Chartre  */
207*49bfb42bSAlexandre Chartre /*ARGSUSED*/
208*49bfb42bSAlexandre Chartre static ldma_request_status_t
209*49bfb42bSAlexandre Chartre ldma_dev_validate_nic(ds_ver_t *ver, ldma_message_header_t *request,
210*49bfb42bSAlexandre Chartre     size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
211*49bfb42bSAlexandre Chartre {
212*49bfb42bSAlexandre Chartre 	dladm_handle_t dlhandle;
213*49bfb42bSAlexandre Chartre 	datalink_id_t linkid;
214*49bfb42bSAlexandre Chartre 	uint32_t flag, media;
215*49bfb42bSAlexandre Chartre 	datalink_class_t class;
216*49bfb42bSAlexandre Chartre 	ldma_message_header_t *reply = NULL;
217*49bfb42bSAlexandre Chartre 	ldma_request_status_t status;
218*49bfb42bSAlexandre Chartre 	char *nic = NULL;
219*49bfb42bSAlexandre Chartre 	uint32_t nlen, reply_dlen;
220*49bfb42bSAlexandre Chartre 
221*49bfb42bSAlexandre Chartre 	nlen = request->msg_info;
222*49bfb42bSAlexandre Chartre 	if (nlen == 0 || nlen > MAXPATHLEN || nlen > request_dlen) {
223*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_INVALID;
224*49bfb42bSAlexandre Chartre 		goto done;
225*49bfb42bSAlexandre Chartre 	}
226*49bfb42bSAlexandre Chartre 
227*49bfb42bSAlexandre Chartre 	nic = malloc(nlen + 1);
228*49bfb42bSAlexandre Chartre 	if (nic == NULL) {
229*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_FAILED;
230*49bfb42bSAlexandre Chartre 		goto done;
231*49bfb42bSAlexandre Chartre 	}
232*49bfb42bSAlexandre Chartre 
233*49bfb42bSAlexandre Chartre 	(void) strncpy(nic, LDMA_HDR2DATA(request), nlen);
234*49bfb42bSAlexandre Chartre 	nic[nlen] = '\0';
235*49bfb42bSAlexandre Chartre 
236*49bfb42bSAlexandre Chartre 	LDMA_DBG("VALIDATE_NIC(%s)", nic);
237*49bfb42bSAlexandre Chartre 
238*49bfb42bSAlexandre Chartre 	reply_dlen = 0;
239*49bfb42bSAlexandre Chartre 	reply = ldma_alloc_result_msg(request, reply_dlen);
240*49bfb42bSAlexandre Chartre 	if (reply == NULL) {
241*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_FAILED;
242*49bfb42bSAlexandre Chartre 		goto done;
243*49bfb42bSAlexandre Chartre 	}
244*49bfb42bSAlexandre Chartre 
245*49bfb42bSAlexandre Chartre 	reply->msg_info = 0x0;
246*49bfb42bSAlexandre Chartre 
247*49bfb42bSAlexandre Chartre 	if (dladm_open(&dlhandle) != DLADM_STATUS_OK) {
248*49bfb42bSAlexandre Chartre 		status = LDMA_REQ_FAILED;
249*49bfb42bSAlexandre Chartre 		goto done;
250*49bfb42bSAlexandre Chartre 	}
251*49bfb42bSAlexandre Chartre 
252*49bfb42bSAlexandre Chartre 	if (dladm_name2info(dlhandle, nic, &linkid, &flag, &class,
253*49bfb42bSAlexandre Chartre 	    &media) != DLADM_STATUS_OK) {
254*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_NIC(%s): name2info failed", nic);
255*49bfb42bSAlexandre Chartre 	} else {
256*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_NIC(%s): media=0x%x", nic, media);
257*49bfb42bSAlexandre Chartre 		reply->msg_info = LDMA_DEVNIC_EXIST;
258*49bfb42bSAlexandre Chartre 	}
259*49bfb42bSAlexandre Chartre 
260*49bfb42bSAlexandre Chartre 	dladm_close(dlhandle);
261*49bfb42bSAlexandre Chartre 
262*49bfb42bSAlexandre Chartre 	status = LDMA_REQ_COMPLETED;
263*49bfb42bSAlexandre Chartre 
264*49bfb42bSAlexandre Chartre done:
265*49bfb42bSAlexandre Chartre 	if (status != LDMA_REQ_COMPLETED) {
266*49bfb42bSAlexandre Chartre 		/*
267*49bfb42bSAlexandre Chartre 		 * We don't provide a reply message if the request has not
268*49bfb42bSAlexandre Chartre 		 * been completed. The LDoms agent daemon will send an
269*49bfb42bSAlexandre Chartre 		 * appropriate reply based on the return code of this function.
270*49bfb42bSAlexandre Chartre 		 */
271*49bfb42bSAlexandre Chartre 		free(reply);
272*49bfb42bSAlexandre Chartre 		reply = NULL;
273*49bfb42bSAlexandre Chartre 		reply_dlen = 0;
274*49bfb42bSAlexandre Chartre 
275*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_NIC(%s): return error %d",
276*49bfb42bSAlexandre Chartre 		    (nic)? nic : "<none>", status);
277*49bfb42bSAlexandre Chartre 	} else {
278*49bfb42bSAlexandre Chartre 		LDMA_DBG("VALIDATE_NIC(%s): return status=0x%x",
279*49bfb42bSAlexandre Chartre 		    nic, reply->msg_info);
280*49bfb42bSAlexandre Chartre 	}
281*49bfb42bSAlexandre Chartre 
282*49bfb42bSAlexandre Chartre 	free(nic);
283*49bfb42bSAlexandre Chartre 	*replyp = reply;
284*49bfb42bSAlexandre Chartre 	*reply_dlenp = reply_dlen;
285*49bfb42bSAlexandre Chartre 
286*49bfb42bSAlexandre Chartre 	return (status);
287*49bfb42bSAlexandre Chartre }
288