xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rds/rds_ioctl.c (revision 721fffe35d40e548a5a58dc53a2ec9c6762172d9)
1b86efd96Sagiri /*
2b86efd96Sagiri  * CDDL HEADER START
3b86efd96Sagiri  *
4b86efd96Sagiri  * The contents of this file are subject to the terms of the
5b86efd96Sagiri  * Common Development and Distribution License (the "License").
6b86efd96Sagiri  * You may not use this file except in compliance with the License.
7b86efd96Sagiri  *
8b86efd96Sagiri  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b86efd96Sagiri  * or http://www.opensolaris.org/os/licensing.
10b86efd96Sagiri  * See the License for the specific language governing permissions
11b86efd96Sagiri  * and limitations under the License.
12b86efd96Sagiri  *
13b86efd96Sagiri  * When distributing Covered Code, include this CDDL HEADER in each
14b86efd96Sagiri  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b86efd96Sagiri  * If applicable, add the following below this CDDL HEADER, with the
16b86efd96Sagiri  * fields enclosed by brackets "[]" replaced with your own identifying
17b86efd96Sagiri  * information: Portions Copyright [yyyy] [name of copyright owner]
18b86efd96Sagiri  *
19b86efd96Sagiri  * CDDL HEADER END
20b86efd96Sagiri  */
21b86efd96Sagiri /*
22*721fffe3SKacheong Poon  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23b86efd96Sagiri  * Use is subject to license terms.
24b86efd96Sagiri  */
25b86efd96Sagiri 
26b86efd96Sagiri #include <sys/sockio.h>
27b86efd96Sagiri #include <sys/stream.h>
28b86efd96Sagiri #include <sys/errno.h>
29b86efd96Sagiri #include <sys/cmn_err.h>
30b86efd96Sagiri #include <sys/strsun.h>
31b86efd96Sagiri #include <inet/common.h>
32b86efd96Sagiri #include <net/if.h>
33e11c3f44Smeem #include <net/if_types.h>
34b86efd96Sagiri #include <inet/mi.h>
35b86efd96Sagiri #include <sys/t_kuser.h>
36b86efd96Sagiri #include <sys/stropts.h>
37b86efd96Sagiri #include <sys/pathname.h>
38b86efd96Sagiri #include <sys/kstr.h>
39b86efd96Sagiri #include <sys/timod.h>
40e11c3f44Smeem #include <sys/sunddi.h>
41b86efd96Sagiri #include <sys/ib/clients/rds/rds.h>
42b86efd96Sagiri #include <sys/ib/clients/rds/rds_transport.h>
43b86efd96Sagiri 
44b86efd96Sagiri /*
45b86efd96Sagiri  * Just pass the ioctl to IP and the result to the caller.
46b86efd96Sagiri  */
47b86efd96Sagiri int
48e11c3f44Smeem rds_do_ip_ioctl(int cmd, int len, void *arg)
49b86efd96Sagiri {
50af4c679fSSean McEnroe 	vnode_t	*kkvp, *vp;
51b86efd96Sagiri 	TIUSER	*tiptr;
52b86efd96Sagiri 	struct	strioctl iocb;
53c1f8b08eSagiri 	k_sigset_t smask;
54b86efd96Sagiri 	int	err = 0;
55b86efd96Sagiri 
56af4c679fSSean McEnroe 	if (lookupname("/dev/udp", UIO_SYSSPACE, FOLLOW, NULLVPP, &kkvp) == 0) {
57af4c679fSSean McEnroe 		if (t_kopen((file_t *)NULL, kkvp->v_rdev, FREAD|FWRITE,
58b86efd96Sagiri 		    &tiptr, CRED()) == 0) {
59b86efd96Sagiri 			vp = tiptr->fp->f_vnode;
60b86efd96Sagiri 		} else {
61af4c679fSSean McEnroe 			VN_RELE(kkvp);
62b86efd96Sagiri 			return (EPROTO);
63b86efd96Sagiri 		}
64b86efd96Sagiri 	} else {
65b86efd96Sagiri 		return (EPROTO);
66b86efd96Sagiri 	}
67b86efd96Sagiri 
68b86efd96Sagiri 	iocb.ic_cmd = cmd;
69b86efd96Sagiri 	iocb.ic_timout = 0;
70b86efd96Sagiri 	iocb.ic_len = len;
71e11c3f44Smeem 	iocb.ic_dp = (caddr_t)arg;
72c1f8b08eSagiri 	sigintr(&smask, 0);
73b86efd96Sagiri 	err = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
74c1f8b08eSagiri 	sigunintr(&smask);
75b86efd96Sagiri 	(void) t_kclose(tiptr, 0);
76af4c679fSSean McEnroe 	VN_RELE(kkvp);
77b86efd96Sagiri 	return (err);
78b86efd96Sagiri }
79b86efd96Sagiri 
80c1f8b08eSagiri /*
81e11c3f44Smeem  * Check if the IP interface named by `lifrp' is RDS-capable.
82e11c3f44Smeem  */
83e11c3f44Smeem static boolean_t
84e11c3f44Smeem rds_capable_interface(struct lifreq *lifrp)
85e11c3f44Smeem {
86e11c3f44Smeem 	char	ifname[LIFNAMSIZ];
87e11c3f44Smeem 	char	drv[MAXLINKNAMELEN];
88e11c3f44Smeem 	uint_t	ppa;
89e11c3f44Smeem 	char 	*cp;
90e11c3f44Smeem 
91e11c3f44Smeem 	if (lifrp->lifr_type == IFT_IB)
92e11c3f44Smeem 		return (B_TRUE);
93e11c3f44Smeem 
94e11c3f44Smeem 	/*
95e11c3f44Smeem 	 * Strip off the logical interface portion before getting
96e11c3f44Smeem 	 * intimate with the name.
97e11c3f44Smeem 	 */
98e11c3f44Smeem 	(void) strlcpy(ifname, lifrp->lifr_name, LIFNAMSIZ);
99e11c3f44Smeem 	if ((cp = strchr(ifname, ':')) != NULL)
100e11c3f44Smeem 		*cp = '\0';
101e11c3f44Smeem 
102e11c3f44Smeem 	if (strcmp("lo0", ifname) == 0) {
103e11c3f44Smeem 		/*
104e11c3f44Smeem 		 * loopback is considered RDS-capable
105e11c3f44Smeem 		 */
106e11c3f44Smeem 		return (B_TRUE);
107e11c3f44Smeem 	}
108e11c3f44Smeem 
109e11c3f44Smeem 	return (ddi_parse(ifname, drv, &ppa) == DDI_SUCCESS &&
110e11c3f44Smeem 	    rds_transport_ops->rds_transport_if_lookup_by_name(drv));
111e11c3f44Smeem }
112e11c3f44Smeem 
113e11c3f44Smeem /*
114e11c3f44Smeem  * Issue an SIOCGLIFCONF down to IP and return the result in `lifcp'.
115e11c3f44Smeem  * lifcp->lifc_buf is dynamically allocated to be *bufsizep bytes.
116c1f8b08eSagiri  */
117c1f8b08eSagiri static int
118e11c3f44Smeem rds_do_lifconf(struct lifconf *lifcp, uint_t *bufsizep)
119b86efd96Sagiri {
120e11c3f44Smeem 	int err;
121e11c3f44Smeem 	int nifs;
122b86efd96Sagiri 
123e11c3f44Smeem 	if ((err = rds_do_ip_ioctl(SIOCGIFNUM, sizeof (int), &nifs)) != 0)
124e11c3f44Smeem 		return (err);
125b86efd96Sagiri 
126b86efd96Sagiri 	/*
127e11c3f44Smeem 	 * Pad the interface count to account for additional interfaces that
128e11c3f44Smeem 	 * may have been configured between the SIOCGLIFNUM and SIOCGLIFCONF.
129b86efd96Sagiri 	 */
130e11c3f44Smeem 	nifs += 4;
131b86efd96Sagiri 
132e11c3f44Smeem 	bzero(lifcp, sizeof (struct lifconf));
133e11c3f44Smeem 	lifcp->lifc_family = AF_INET;
134e11c3f44Smeem 	lifcp->lifc_len = *bufsizep = (nifs * sizeof (struct lifreq));
135e11c3f44Smeem 	lifcp->lifc_buf = kmem_zalloc(*bufsizep, KM_NOSLEEP);
136e11c3f44Smeem 	if (lifcp->lifc_buf == NULL)
137e11c3f44Smeem 		return (ENOMEM);
138b86efd96Sagiri 
139e11c3f44Smeem 	err = rds_do_ip_ioctl(SIOCGLIFCONF, sizeof (struct lifconf), lifcp);
140e11c3f44Smeem 	if (err != 0) {
141e11c3f44Smeem 		kmem_free(lifcp->lifc_buf, *bufsizep);
142e11c3f44Smeem 		return (err);
1438257fab9Sagiri 	}
144c1f8b08eSagiri 	return (0);
145b86efd96Sagiri }
146b86efd96Sagiri 
147b86efd96Sagiri void
148b86efd96Sagiri rds_ioctl_copyin_done(queue_t *q, mblk_t *mp)
149b86efd96Sagiri {
150e11c3f44Smeem 	void	*addr;
151b86efd96Sagiri 	mblk_t	*mp1;
152b86efd96Sagiri 	int	err = 0;
153e11c3f44Smeem 	struct	iocblk *iocp = (void *)mp->b_rptr;
154b86efd96Sagiri 
155b86efd96Sagiri 	if (!(mp1 = mp->b_cont) || !(mp1 = mp1->b_cont)) {
156b86efd96Sagiri 		err = EPROTO;
157b86efd96Sagiri 		goto done;
158b86efd96Sagiri 	}
159b86efd96Sagiri 
160e11c3f44Smeem 	addr = mp1->b_rptr;
161b86efd96Sagiri 
162b86efd96Sagiri 	switch (iocp->ioc_cmd) {
163b86efd96Sagiri 	case SIOCGIFNUM: {
164e11c3f44Smeem 		uint_t bufsize;
165e11c3f44Smeem 		struct lifconf lifc;
166e11c3f44Smeem 		struct lifreq *lifrp;
167e11c3f44Smeem 		int i, nifs, retval = 0;
168b86efd96Sagiri 
169e11c3f44Smeem 		if ((err = rds_do_lifconf(&lifc, &bufsize)) != 0)
170b86efd96Sagiri 			break;
171b86efd96Sagiri 
172e11c3f44Smeem 		nifs = lifc.lifc_len / sizeof (struct lifreq);
173e11c3f44Smeem 		for (lifrp = lifc.lifc_req, i = 0; i < nifs; i++, lifrp++) {
174e11c3f44Smeem 			if (strlen(lifrp->lifr_name) <= IFNAMSIZ &&
175e11c3f44Smeem 			    rds_capable_interface(lifrp)) {
176e11c3f44Smeem 				retval++;
177e11c3f44Smeem 			}
178e11c3f44Smeem 		}
179e11c3f44Smeem 		*((int *)addr) = retval;
180e11c3f44Smeem 		kmem_free(lifc.lifc_buf, bufsize);
181b86efd96Sagiri 		break;
182b86efd96Sagiri 	}
183b86efd96Sagiri 
184b86efd96Sagiri 	case O_SIOCGIFCONF:
185b86efd96Sagiri 	case SIOCGIFCONF: {
186b86efd96Sagiri 		STRUCT_HANDLE(ifconf, ifc);
187b86efd96Sagiri 		caddr_t ubuf_addr;
188b86efd96Sagiri 		int	ubuf_size;
189e11c3f44Smeem 		uint_t	bufsize;
190e11c3f44Smeem 		int 	i, nifs;
191e11c3f44Smeem 		struct lifconf lifc;
192e11c3f44Smeem 		struct lifreq *lifrp;
193e11c3f44Smeem 		struct ifreq *ifrp;
194b86efd96Sagiri 
195e11c3f44Smeem 		STRUCT_SET_HANDLE(ifc, iocp->ioc_flag, (struct ifconf *)addr);
196b86efd96Sagiri 		ubuf_size = STRUCT_FGET(ifc, ifc_len);
197b86efd96Sagiri 		ubuf_addr = STRUCT_FGETP(ifc, ifc_buf);
198b86efd96Sagiri 
199e11c3f44Smeem 		if ((err = rds_do_lifconf(&lifc, &bufsize)) != 0)
200b86efd96Sagiri 			break;
201b86efd96Sagiri 
202b86efd96Sagiri 		mp1 = mi_copyout_alloc(q, mp, ubuf_addr, ubuf_size, B_FALSE);
203b86efd96Sagiri 		if (mp1 == NULL) {
204b86efd96Sagiri 			err = ENOMEM;
205e11c3f44Smeem 			kmem_free(lifc.lifc_buf, bufsize);
206b86efd96Sagiri 			break;
207b86efd96Sagiri 		}
208b86efd96Sagiri 
209e11c3f44Smeem 		ifrp = (void *)mp1->b_rptr;
210e11c3f44Smeem 		nifs = lifc.lifc_len / sizeof (struct lifreq);
211e11c3f44Smeem 		for (lifrp = lifc.lifc_req, i = 0; i < nifs &&
212e11c3f44Smeem 		    MBLKTAIL(mp1) >= sizeof (struct ifreq); i++, lifrp++) {
213e11c3f44Smeem 			/*
214e11c3f44Smeem 			 * Skip entries that are impossible to return with
215e11c3f44Smeem 			 * SIOCGIFCONF, or not RDS-capable.
216e11c3f44Smeem 			 */
217e11c3f44Smeem 			if (strlen(lifrp->lifr_name) > IFNAMSIZ ||
218e11c3f44Smeem 			    !rds_capable_interface(lifrp)) {
219e11c3f44Smeem 				continue;
220b86efd96Sagiri 			}
221b86efd96Sagiri 
222e11c3f44Smeem 			ifrp->ifr_addr = *(struct sockaddr *)&lifrp->lifr_addr;
223e11c3f44Smeem 			ifrp->ifr_addr.sa_family = AF_INET_OFFLOAD;
224e11c3f44Smeem 			(void) strlcpy(ifrp->ifr_name, lifrp->lifr_name,
225e11c3f44Smeem 			    IFNAMSIZ);
226e11c3f44Smeem 			ifrp++;
227e11c3f44Smeem 			mp1->b_wptr += sizeof (struct ifreq);
228b86efd96Sagiri 		}
229e11c3f44Smeem 
230e11c3f44Smeem 		STRUCT_FSET(ifc, ifc_len, MBLKL(mp1));
231e11c3f44Smeem 		kmem_free(lifc.lifc_buf, bufsize);
232b86efd96Sagiri 		break;
233e11c3f44Smeem 	}
234b86efd96Sagiri 	case SIOCGIFMTU:
235b86efd96Sagiri 	case SIOCGIFFLAGS:
236e11c3f44Smeem 		err = rds_do_ip_ioctl(iocp->ioc_cmd, sizeof (struct ifreq),
237e11c3f44Smeem 		    addr);
238b86efd96Sagiri 		break;
239b86efd96Sagiri 
240e11c3f44Smeem 	case TI_GETMYNAME: {
241b86efd96Sagiri 		rds_t *rds;
242b86efd96Sagiri 		STRUCT_HANDLE(strbuf, sb);
243b86efd96Sagiri 		ipaddr_t	v4addr;
244b86efd96Sagiri 		uint16_t port;
245b86efd96Sagiri 		int addrlen;
246b86efd96Sagiri 		sin_t *sin;
247b86efd96Sagiri 
248b86efd96Sagiri 		STRUCT_SET_HANDLE(sb,
249e11c3f44Smeem 		    ((struct iocblk *)(uintptr_t)mp->b_rptr)->ioc_flag, addr);
250b86efd96Sagiri 		rds = (rds_t *)q->q_ptr;
251b86efd96Sagiri 		ASSERT(rds->rds_family == AF_INET_OFFLOAD);
252b86efd96Sagiri 		addrlen = sizeof (sin_t);
253b86efd96Sagiri 		v4addr = rds->rds_src;
254b86efd96Sagiri 		port = rds->rds_port;
255b86efd96Sagiri 		mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), addrlen,
256b86efd96Sagiri 		    B_TRUE);
257b86efd96Sagiri 		if (mp1 == NULL)
258b86efd96Sagiri 			return;
259b86efd96Sagiri 		STRUCT_FSET(sb, len, (int)sizeof (sin_t));
260b86efd96Sagiri 		sin = (sin_t *)(uintptr_t)mp1->b_rptr;
261b86efd96Sagiri 		mp1->b_wptr = (uchar_t *)&sin[1];
262b86efd96Sagiri 		*sin = sin_null;
263b86efd96Sagiri 		sin->sin_family = AF_INET_OFFLOAD;
264b86efd96Sagiri 		sin->sin_addr.s_addr = v4addr;
265b86efd96Sagiri 		sin->sin_port = port;
266b86efd96Sagiri 
267b86efd96Sagiri 	}
268b86efd96Sagiri 		break;
269b86efd96Sagiri 	default:
270b86efd96Sagiri 		err = EOPNOTSUPP;
271b86efd96Sagiri 		break;
272b86efd96Sagiri 	}
273b86efd96Sagiri 	if (err == 0) {
274b86efd96Sagiri 		mi_copyout(q, mp);
275b86efd96Sagiri 		return;
276b86efd96Sagiri 	}
277b86efd96Sagiri done:
278b86efd96Sagiri 	mi_copy_done(q, mp, err);
279b86efd96Sagiri }
280b86efd96Sagiri 
281b86efd96Sagiri void
282b86efd96Sagiri rds_ioctl_copyin_setup(queue_t *q, mblk_t *mp)
283b86efd96Sagiri {
284b86efd96Sagiri 	struct iocblk *iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
285b86efd96Sagiri 	int	copyin_size;
286b86efd96Sagiri 
287b86efd96Sagiri 	if (mp->b_cont == NULL) {
288b86efd96Sagiri 		iocp->ioc_error = EINVAL;
289b86efd96Sagiri 		mp->b_datap->db_type = M_IOCNAK;
290b86efd96Sagiri 		iocp->ioc_count = 0;
291b86efd96Sagiri 		qreply(q, mp);
292b86efd96Sagiri 		return;
293b86efd96Sagiri 	}
294b86efd96Sagiri 
295b86efd96Sagiri 	switch (iocp->ioc_cmd) {
296b86efd96Sagiri 	case O_SIOCGIFCONF:
297b86efd96Sagiri 	case SIOCGIFCONF:
298b86efd96Sagiri 		if (iocp->ioc_count == TRANSPARENT)
299b86efd96Sagiri 			copyin_size = SIZEOF_STRUCT(ifconf, iocp->ioc_flag);
300b86efd96Sagiri 		else
301b86efd96Sagiri 			copyin_size = iocp->ioc_count;
302b86efd96Sagiri 		break;
303b86efd96Sagiri 
304b86efd96Sagiri 	case SIOCGIFNUM:
305b86efd96Sagiri 		copyin_size = sizeof (int);
306b86efd96Sagiri 		break;
307b86efd96Sagiri 	case SIOCGIFFLAGS:
308b86efd96Sagiri 	case SIOCGIFMTU:
309b86efd96Sagiri 		copyin_size = sizeof (struct ifreq);
310b86efd96Sagiri 		break;
311b86efd96Sagiri 	case TI_GETMYNAME:
312b86efd96Sagiri 		copyin_size = SIZEOF_STRUCT(strbuf, iocp->ioc_flag);
313b86efd96Sagiri 		break;
314b86efd96Sagiri 	}
315b86efd96Sagiri 	mi_copyin(q, mp, NULL, copyin_size);
316b86efd96Sagiri }
317b86efd96Sagiri 
318b86efd96Sagiri void
319b86efd96Sagiri rds_ioctl(queue_t *q, mblk_t *mp)
320b86efd96Sagiri {
321b86efd96Sagiri 	struct iocblk *iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
322b86efd96Sagiri 
323b86efd96Sagiri 
324b86efd96Sagiri 	switch (iocp->ioc_cmd) {
325b86efd96Sagiri 		case O_SIOCGIFCONF:
326b86efd96Sagiri 		case SIOCGIFCONF:
327b86efd96Sagiri 		case SIOCGIFNUM:
328b86efd96Sagiri 		case SIOCGIFMTU:
329b86efd96Sagiri 		case SIOCGIFFLAGS:
330b86efd96Sagiri 		case TI_GETMYNAME:
331b86efd96Sagiri 			rds_ioctl_copyin_setup(q, mp);
332b86efd96Sagiri 			break;
333b86efd96Sagiri 		default:
334b86efd96Sagiri 			cmn_err(CE_CONT, "rds_wput unsupported IOCTL \n");
335b86efd96Sagiri 			miocnak(q, mp, 0, ENOTSUP);
336b86efd96Sagiri 			break;
337b86efd96Sagiri 	}
338b86efd96Sagiri }
339b86efd96Sagiri 
340b86efd96Sagiri boolean_t
341b86efd96Sagiri rds_verify_bind_address(ipaddr_t addr)
342b86efd96Sagiri {
343e11c3f44Smeem 	int i, nifs;
344e11c3f44Smeem 	uint_t bufsize;
345e11c3f44Smeem 	struct lifconf lifc;
346e11c3f44Smeem 	struct lifreq *lifrp;
347e11c3f44Smeem 	struct sockaddr_in *sinp;
348e11c3f44Smeem 	boolean_t retval = B_FALSE;
349b86efd96Sagiri 
350e11c3f44Smeem 	if (rds_do_lifconf(&lifc, &bufsize) != 0)
351e11c3f44Smeem 		return (B_FALSE);
352b86efd96Sagiri 
353e11c3f44Smeem 	nifs = lifc.lifc_len / sizeof (struct lifreq);
354e11c3f44Smeem 	for (lifrp = lifc.lifc_req, i = 0; i < nifs; i++, lifrp++) {
355e11c3f44Smeem 		sinp = (struct sockaddr_in *)&lifrp->lifr_addr;
356e11c3f44Smeem 		if (rds_capable_interface(lifrp) &&
357e11c3f44Smeem 		    sinp->sin_addr.s_addr == addr) {
358e11c3f44Smeem 			retval = B_TRUE;
359b86efd96Sagiri 			break;
360b86efd96Sagiri 		}
361b86efd96Sagiri 	}
362b86efd96Sagiri 
363e11c3f44Smeem 	kmem_free(lifc.lifc_buf, bufsize);
364e11c3f44Smeem 	return (retval);
365b86efd96Sagiri }
366