xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rds/rds_ioctl.c (revision 676abcb77c26296424298b37b96d2bce39ab25e5)
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 /*
22721fffe3SKacheong 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
rds_do_ip_ioctl(int cmd,int len,void * arg)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
rds_capable_interface(struct lifreq * lifrp)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 
109*676abcb7SDan McDonald 	return (
110*676abcb7SDan McDonald 	    ddi_parse_dlen(ifname, drv, MAXLINKNAMELEN, &ppa) == DDI_SUCCESS &&
111e11c3f44Smeem 	    rds_transport_ops->rds_transport_if_lookup_by_name(drv));
112e11c3f44Smeem }
113e11c3f44Smeem 
114e11c3f44Smeem /*
115e11c3f44Smeem  * Issue an SIOCGLIFCONF down to IP and return the result in `lifcp'.
116e11c3f44Smeem  * lifcp->lifc_buf is dynamically allocated to be *bufsizep bytes.
117c1f8b08eSagiri  */
118c1f8b08eSagiri static int
rds_do_lifconf(struct lifconf * lifcp,uint_t * bufsizep)119e11c3f44Smeem rds_do_lifconf(struct lifconf *lifcp, uint_t *bufsizep)
120b86efd96Sagiri {
121e11c3f44Smeem 	int err;
122e11c3f44Smeem 	int nifs;
123b86efd96Sagiri 
124e11c3f44Smeem 	if ((err = rds_do_ip_ioctl(SIOCGIFNUM, sizeof (int), &nifs)) != 0)
125e11c3f44Smeem 		return (err);
126b86efd96Sagiri 
127b86efd96Sagiri 	/*
128e11c3f44Smeem 	 * Pad the interface count to account for additional interfaces that
129e11c3f44Smeem 	 * may have been configured between the SIOCGLIFNUM and SIOCGLIFCONF.
130b86efd96Sagiri 	 */
131e11c3f44Smeem 	nifs += 4;
132b86efd96Sagiri 
133e11c3f44Smeem 	bzero(lifcp, sizeof (struct lifconf));
134e11c3f44Smeem 	lifcp->lifc_family = AF_INET;
135e11c3f44Smeem 	lifcp->lifc_len = *bufsizep = (nifs * sizeof (struct lifreq));
136e11c3f44Smeem 	lifcp->lifc_buf = kmem_zalloc(*bufsizep, KM_NOSLEEP);
137e11c3f44Smeem 	if (lifcp->lifc_buf == NULL)
138e11c3f44Smeem 		return (ENOMEM);
139b86efd96Sagiri 
140e11c3f44Smeem 	err = rds_do_ip_ioctl(SIOCGLIFCONF, sizeof (struct lifconf), lifcp);
141e11c3f44Smeem 	if (err != 0) {
142e11c3f44Smeem 		kmem_free(lifcp->lifc_buf, *bufsizep);
143e11c3f44Smeem 		return (err);
1448257fab9Sagiri 	}
145c1f8b08eSagiri 	return (0);
146b86efd96Sagiri }
147b86efd96Sagiri 
148b86efd96Sagiri void
rds_ioctl_copyin_done(queue_t * q,mblk_t * mp)149b86efd96Sagiri rds_ioctl_copyin_done(queue_t *q, mblk_t *mp)
150b86efd96Sagiri {
151e11c3f44Smeem 	void	*addr;
152b86efd96Sagiri 	mblk_t	*mp1;
153b86efd96Sagiri 	int	err = 0;
154e11c3f44Smeem 	struct	iocblk *iocp = (void *)mp->b_rptr;
155b86efd96Sagiri 
156b86efd96Sagiri 	if (!(mp1 = mp->b_cont) || !(mp1 = mp1->b_cont)) {
157b86efd96Sagiri 		err = EPROTO;
158b86efd96Sagiri 		goto done;
159b86efd96Sagiri 	}
160b86efd96Sagiri 
161e11c3f44Smeem 	addr = mp1->b_rptr;
162b86efd96Sagiri 
163b86efd96Sagiri 	switch (iocp->ioc_cmd) {
164b86efd96Sagiri 	case SIOCGIFNUM: {
165e11c3f44Smeem 		uint_t bufsize;
166e11c3f44Smeem 		struct lifconf lifc;
167e11c3f44Smeem 		struct lifreq *lifrp;
168e11c3f44Smeem 		int i, nifs, retval = 0;
169b86efd96Sagiri 
170e11c3f44Smeem 		if ((err = rds_do_lifconf(&lifc, &bufsize)) != 0)
171b86efd96Sagiri 			break;
172b86efd96Sagiri 
173e11c3f44Smeem 		nifs = lifc.lifc_len / sizeof (struct lifreq);
174e11c3f44Smeem 		for (lifrp = lifc.lifc_req, i = 0; i < nifs; i++, lifrp++) {
175e11c3f44Smeem 			if (strlen(lifrp->lifr_name) <= IFNAMSIZ &&
176e11c3f44Smeem 			    rds_capable_interface(lifrp)) {
177e11c3f44Smeem 				retval++;
178e11c3f44Smeem 			}
179e11c3f44Smeem 		}
180e11c3f44Smeem 		*((int *)addr) = retval;
181e11c3f44Smeem 		kmem_free(lifc.lifc_buf, bufsize);
182b86efd96Sagiri 		break;
183b86efd96Sagiri 	}
184b86efd96Sagiri 
185b86efd96Sagiri 	case O_SIOCGIFCONF:
186b86efd96Sagiri 	case SIOCGIFCONF: {
187b86efd96Sagiri 		STRUCT_HANDLE(ifconf, ifc);
188b86efd96Sagiri 		caddr_t ubuf_addr;
189b86efd96Sagiri 		int	ubuf_size;
190e11c3f44Smeem 		uint_t	bufsize;
191e11c3f44Smeem 		int	i, nifs;
192e11c3f44Smeem 		struct lifconf lifc;
193e11c3f44Smeem 		struct lifreq *lifrp;
194e11c3f44Smeem 		struct ifreq *ifrp;
195b86efd96Sagiri 
196e11c3f44Smeem 		STRUCT_SET_HANDLE(ifc, iocp->ioc_flag, (struct ifconf *)addr);
197b86efd96Sagiri 		ubuf_size = STRUCT_FGET(ifc, ifc_len);
198b86efd96Sagiri 		ubuf_addr = STRUCT_FGETP(ifc, ifc_buf);
199b86efd96Sagiri 
200e11c3f44Smeem 		if ((err = rds_do_lifconf(&lifc, &bufsize)) != 0)
201b86efd96Sagiri 			break;
202b86efd96Sagiri 
203b86efd96Sagiri 		mp1 = mi_copyout_alloc(q, mp, ubuf_addr, ubuf_size, B_FALSE);
204b86efd96Sagiri 		if (mp1 == NULL) {
205b86efd96Sagiri 			err = ENOMEM;
206e11c3f44Smeem 			kmem_free(lifc.lifc_buf, bufsize);
207b86efd96Sagiri 			break;
208b86efd96Sagiri 		}
209b86efd96Sagiri 
210e11c3f44Smeem 		ifrp = (void *)mp1->b_rptr;
211e11c3f44Smeem 		nifs = lifc.lifc_len / sizeof (struct lifreq);
212e11c3f44Smeem 		for (lifrp = lifc.lifc_req, i = 0; i < nifs &&
213e11c3f44Smeem 		    MBLKTAIL(mp1) >= sizeof (struct ifreq); i++, lifrp++) {
214e11c3f44Smeem 			/*
215e11c3f44Smeem 			 * Skip entries that are impossible to return with
216e11c3f44Smeem 			 * SIOCGIFCONF, or not RDS-capable.
217e11c3f44Smeem 			 */
218e11c3f44Smeem 			if (strlen(lifrp->lifr_name) > IFNAMSIZ ||
219e11c3f44Smeem 			    !rds_capable_interface(lifrp)) {
220e11c3f44Smeem 				continue;
221b86efd96Sagiri 			}
222b86efd96Sagiri 
223e11c3f44Smeem 			ifrp->ifr_addr = *(struct sockaddr *)&lifrp->lifr_addr;
224e11c3f44Smeem 			ifrp->ifr_addr.sa_family = AF_INET_OFFLOAD;
225e11c3f44Smeem 			(void) strlcpy(ifrp->ifr_name, lifrp->lifr_name,
226e11c3f44Smeem 			    IFNAMSIZ);
227e11c3f44Smeem 			ifrp++;
228e11c3f44Smeem 			mp1->b_wptr += sizeof (struct ifreq);
229b86efd96Sagiri 		}
230e11c3f44Smeem 
231e11c3f44Smeem 		STRUCT_FSET(ifc, ifc_len, MBLKL(mp1));
232e11c3f44Smeem 		kmem_free(lifc.lifc_buf, bufsize);
233b86efd96Sagiri 		break;
234e11c3f44Smeem 	}
235b86efd96Sagiri 	case SIOCGIFMTU:
236b86efd96Sagiri 	case SIOCGIFFLAGS:
237e11c3f44Smeem 		err = rds_do_ip_ioctl(iocp->ioc_cmd, sizeof (struct ifreq),
238e11c3f44Smeem 		    addr);
239b86efd96Sagiri 		break;
240b86efd96Sagiri 
241e11c3f44Smeem 	case TI_GETMYNAME: {
242b86efd96Sagiri 		rds_t *rds;
243b86efd96Sagiri 		STRUCT_HANDLE(strbuf, sb);
244b86efd96Sagiri 		ipaddr_t	v4addr;
245b86efd96Sagiri 		uint16_t port;
246b86efd96Sagiri 		int addrlen;
247b86efd96Sagiri 		sin_t *sin;
248b86efd96Sagiri 
249b86efd96Sagiri 		STRUCT_SET_HANDLE(sb,
250e11c3f44Smeem 		    ((struct iocblk *)(uintptr_t)mp->b_rptr)->ioc_flag, addr);
251b86efd96Sagiri 		rds = (rds_t *)q->q_ptr;
252b86efd96Sagiri 		ASSERT(rds->rds_family == AF_INET_OFFLOAD);
253b86efd96Sagiri 		addrlen = sizeof (sin_t);
254b86efd96Sagiri 		v4addr = rds->rds_src;
255b86efd96Sagiri 		port = rds->rds_port;
256b86efd96Sagiri 		mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), addrlen,
257b86efd96Sagiri 		    B_TRUE);
258b86efd96Sagiri 		if (mp1 == NULL)
259b86efd96Sagiri 			return;
260b86efd96Sagiri 		STRUCT_FSET(sb, len, (int)sizeof (sin_t));
261b86efd96Sagiri 		sin = (sin_t *)(uintptr_t)mp1->b_rptr;
262b86efd96Sagiri 		mp1->b_wptr = (uchar_t *)&sin[1];
263b86efd96Sagiri 		*sin = sin_null;
264b86efd96Sagiri 		sin->sin_family = AF_INET_OFFLOAD;
265b86efd96Sagiri 		sin->sin_addr.s_addr = v4addr;
266b86efd96Sagiri 		sin->sin_port = port;
267b86efd96Sagiri 
268b86efd96Sagiri 	}
269b86efd96Sagiri 		break;
270b86efd96Sagiri 	default:
271b86efd96Sagiri 		err = EOPNOTSUPP;
272b86efd96Sagiri 		break;
273b86efd96Sagiri 	}
274b86efd96Sagiri 	if (err == 0) {
275b86efd96Sagiri 		mi_copyout(q, mp);
276b86efd96Sagiri 		return;
277b86efd96Sagiri 	}
278b86efd96Sagiri done:
279b86efd96Sagiri 	mi_copy_done(q, mp, err);
280b86efd96Sagiri }
281b86efd96Sagiri 
282b86efd96Sagiri void
rds_ioctl_copyin_setup(queue_t * q,mblk_t * mp)283b86efd96Sagiri rds_ioctl_copyin_setup(queue_t *q, mblk_t *mp)
284b86efd96Sagiri {
285b86efd96Sagiri 	struct iocblk *iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
286b86efd96Sagiri 	int	copyin_size;
287b86efd96Sagiri 
288b86efd96Sagiri 	if (mp->b_cont == NULL) {
289b86efd96Sagiri 		iocp->ioc_error = EINVAL;
290b86efd96Sagiri 		mp->b_datap->db_type = M_IOCNAK;
291b86efd96Sagiri 		iocp->ioc_count = 0;
292b86efd96Sagiri 		qreply(q, mp);
293b86efd96Sagiri 		return;
294b86efd96Sagiri 	}
295b86efd96Sagiri 
296b86efd96Sagiri 	switch (iocp->ioc_cmd) {
297b86efd96Sagiri 	case O_SIOCGIFCONF:
298b86efd96Sagiri 	case SIOCGIFCONF:
299b86efd96Sagiri 		if (iocp->ioc_count == TRANSPARENT)
300b86efd96Sagiri 			copyin_size = SIZEOF_STRUCT(ifconf, iocp->ioc_flag);
301b86efd96Sagiri 		else
302b86efd96Sagiri 			copyin_size = iocp->ioc_count;
303b86efd96Sagiri 		break;
304b86efd96Sagiri 
305b86efd96Sagiri 	case SIOCGIFNUM:
306b86efd96Sagiri 		copyin_size = sizeof (int);
307b86efd96Sagiri 		break;
308b86efd96Sagiri 	case SIOCGIFFLAGS:
309b86efd96Sagiri 	case SIOCGIFMTU:
310b86efd96Sagiri 		copyin_size = sizeof (struct ifreq);
311b86efd96Sagiri 		break;
312b86efd96Sagiri 	case TI_GETMYNAME:
313b86efd96Sagiri 		copyin_size = SIZEOF_STRUCT(strbuf, iocp->ioc_flag);
314b86efd96Sagiri 		break;
315b86efd96Sagiri 	}
316b86efd96Sagiri 	mi_copyin(q, mp, NULL, copyin_size);
317b86efd96Sagiri }
318b86efd96Sagiri 
319b86efd96Sagiri void
rds_ioctl(queue_t * q,mblk_t * mp)320b86efd96Sagiri rds_ioctl(queue_t *q, mblk_t *mp)
321b86efd96Sagiri {
322b86efd96Sagiri 	struct iocblk *iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
323b86efd96Sagiri 
324b86efd96Sagiri 
325b86efd96Sagiri 	switch (iocp->ioc_cmd) {
326b86efd96Sagiri 		case O_SIOCGIFCONF:
327b86efd96Sagiri 		case SIOCGIFCONF:
328b86efd96Sagiri 		case SIOCGIFNUM:
329b86efd96Sagiri 		case SIOCGIFMTU:
330b86efd96Sagiri 		case SIOCGIFFLAGS:
331b86efd96Sagiri 		case TI_GETMYNAME:
332b86efd96Sagiri 			rds_ioctl_copyin_setup(q, mp);
333b86efd96Sagiri 			break;
334b86efd96Sagiri 		default:
335b86efd96Sagiri 			cmn_err(CE_CONT, "rds_wput unsupported IOCTL \n");
336b86efd96Sagiri 			miocnak(q, mp, 0, ENOTSUP);
337b86efd96Sagiri 			break;
338b86efd96Sagiri 	}
339b86efd96Sagiri }
340b86efd96Sagiri 
341b86efd96Sagiri boolean_t
rds_verify_bind_address(ipaddr_t addr)342b86efd96Sagiri rds_verify_bind_address(ipaddr_t addr)
343b86efd96Sagiri {
344e11c3f44Smeem 	int i, nifs;
345e11c3f44Smeem 	uint_t bufsize;
346e11c3f44Smeem 	struct lifconf lifc;
347e11c3f44Smeem 	struct lifreq *lifrp;
348e11c3f44Smeem 	struct sockaddr_in *sinp;
349e11c3f44Smeem 	boolean_t retval = B_FALSE;
350b86efd96Sagiri 
351e11c3f44Smeem 	if (rds_do_lifconf(&lifc, &bufsize) != 0)
352e11c3f44Smeem 		return (B_FALSE);
353b86efd96Sagiri 
354e11c3f44Smeem 	nifs = lifc.lifc_len / sizeof (struct lifreq);
355e11c3f44Smeem 	for (lifrp = lifc.lifc_req, i = 0; i < nifs; i++, lifrp++) {
356e11c3f44Smeem 		sinp = (struct sockaddr_in *)&lifrp->lifr_addr;
357e11c3f44Smeem 		if (rds_capable_interface(lifrp) &&
358e11c3f44Smeem 		    sinp->sin_addr.s_addr == addr) {
359e11c3f44Smeem 			retval = B_TRUE;
360b86efd96Sagiri 			break;
361b86efd96Sagiri 		}
362b86efd96Sagiri 	}
363b86efd96Sagiri 
364e11c3f44Smeem 	kmem_free(lifc.lifc_buf, bufsize);
365e11c3f44Smeem 	return (retval);
366b86efd96Sagiri }
367