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