4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/sockio.h>
27 #include <sys/stream.h>
28 #include <sys/errno.h>
29 #include <sys/cmn_err.h>
30 #include <sys/strsun.h>
31 #include <inet/common.h>
33 #include <net/if_types.h>
35 #include <sys/t_kuser.h>
36 #include <sys/stropts.h>
37 #include <sys/pathname.h>
39 #include <sys/timod.h>
40 #include <sys/sunddi.h>
41 #include <sys/ib/clients/rds/rds.h>
42 #include <sys/ib/clients/rds/rds_transport.h>
45 * Just pass the ioctl to IP and the result to the caller.
48 rds_do_ip_ioctl(int cmd
, int len
, void *arg
)
56 if (lookupname("/dev/udp", UIO_SYSSPACE
, FOLLOW
, NULLVPP
, &kkvp
) == 0) {
57 if (t_kopen((file_t
*)NULL
, kkvp
->v_rdev
, FREAD
|FWRITE
,
58 &tiptr
, CRED()) == 0) {
59 vp
= tiptr
->fp
->f_vnode
;
71 iocb
.ic_dp
= (caddr_t
)arg
;
73 err
= kstr_ioctl(vp
, I_STR
, (intptr_t)&iocb
);
75 (void) t_kclose(tiptr
, 0);
81 * Check if the IP interface named by `lifrp' is RDS-capable.
84 rds_capable_interface(struct lifreq
*lifrp
)
86 char ifname
[LIFNAMSIZ
];
87 char drv
[MAXLINKNAMELEN
];
91 if (lifrp
->lifr_type
== IFT_IB
)
95 * Strip off the logical interface portion before getting
96 * intimate with the name.
98 (void) strlcpy(ifname
, lifrp
->lifr_name
, LIFNAMSIZ
);
99 if ((cp
= strchr(ifname
, ':')) != NULL
)
102 if (strcmp("lo0", ifname
) == 0) {
104 * loopback is considered RDS-capable
109 return (ddi_parse(ifname
, drv
, &ppa
) == DDI_SUCCESS
&&
110 rds_transport_ops
->rds_transport_if_lookup_by_name(drv
));
114 * Issue an SIOCGLIFCONF down to IP and return the result in `lifcp'.
115 * lifcp->lifc_buf is dynamically allocated to be *bufsizep bytes.
118 rds_do_lifconf(struct lifconf
*lifcp
, uint_t
*bufsizep
)
123 if ((err
= rds_do_ip_ioctl(SIOCGIFNUM
, sizeof (int), &nifs
)) != 0)
127 * Pad the interface count to account for additional interfaces that
128 * may have been configured between the SIOCGLIFNUM and SIOCGLIFCONF.
132 bzero(lifcp
, sizeof (struct lifconf
));
133 lifcp
->lifc_family
= AF_INET
;
134 lifcp
->lifc_len
= *bufsizep
= (nifs
* sizeof (struct lifreq
));
135 lifcp
->lifc_buf
= kmem_zalloc(*bufsizep
, KM_NOSLEEP
);
136 if (lifcp
->lifc_buf
== NULL
)
139 err
= rds_do_ip_ioctl(SIOCGLIFCONF
, sizeof (struct lifconf
), lifcp
);
141 kmem_free(lifcp
->lifc_buf
, *bufsizep
);
148 rds_ioctl_copyin_done(queue_t
*q
, mblk_t
*mp
)
153 struct iocblk
*iocp
= (void *)mp
->b_rptr
;
155 if (!(mp1
= mp
->b_cont
) || !(mp1
= mp1
->b_cont
)) {
162 switch (iocp
->ioc_cmd
) {
166 struct lifreq
*lifrp
;
167 int i
, nifs
, retval
= 0;
169 if ((err
= rds_do_lifconf(&lifc
, &bufsize
)) != 0)
172 nifs
= lifc
.lifc_len
/ sizeof (struct lifreq
);
173 for (lifrp
= lifc
.lifc_req
, i
= 0; i
< nifs
; i
++, lifrp
++) {
174 if (strlen(lifrp
->lifr_name
) <= IFNAMSIZ
&&
175 rds_capable_interface(lifrp
)) {
179 *((int *)addr
) = retval
;
180 kmem_free(lifc
.lifc_buf
, bufsize
);
186 STRUCT_HANDLE(ifconf
, ifc
);
192 struct lifreq
*lifrp
;
195 STRUCT_SET_HANDLE(ifc
, iocp
->ioc_flag
, (struct ifconf
*)addr
);
196 ubuf_size
= STRUCT_FGET(ifc
, ifc_len
);
197 ubuf_addr
= STRUCT_FGETP(ifc
, ifc_buf
);
199 if ((err
= rds_do_lifconf(&lifc
, &bufsize
)) != 0)
202 mp1
= mi_copyout_alloc(q
, mp
, ubuf_addr
, ubuf_size
, B_FALSE
);
205 kmem_free(lifc
.lifc_buf
, bufsize
);
209 ifrp
= (void *)mp1
->b_rptr
;
210 nifs
= lifc
.lifc_len
/ sizeof (struct lifreq
);
211 for (lifrp
= lifc
.lifc_req
, i
= 0; i
< nifs
&&
212 MBLKTAIL(mp1
) >= sizeof (struct ifreq
); i
++, lifrp
++) {
214 * Skip entries that are impossible to return with
215 * SIOCGIFCONF, or not RDS-capable.
217 if (strlen(lifrp
->lifr_name
) > IFNAMSIZ
||
218 !rds_capable_interface(lifrp
)) {
222 ifrp
->ifr_addr
= *(struct sockaddr
*)&lifrp
->lifr_addr
;
223 ifrp
->ifr_addr
.sa_family
= AF_INET_OFFLOAD
;
224 (void) strlcpy(ifrp
->ifr_name
, lifrp
->lifr_name
,
227 mp1
->b_wptr
+= sizeof (struct ifreq
);
230 STRUCT_FSET(ifc
, ifc_len
, MBLKL(mp1
));
231 kmem_free(lifc
.lifc_buf
, bufsize
);
236 err
= rds_do_ip_ioctl(iocp
->ioc_cmd
, sizeof (struct ifreq
),
242 STRUCT_HANDLE(strbuf
, sb
);
248 STRUCT_SET_HANDLE(sb
,
249 ((struct iocblk
*)(uintptr_t)mp
->b_rptr
)->ioc_flag
, addr
);
250 rds
= (rds_t
*)q
->q_ptr
;
251 ASSERT(rds
->rds_family
== AF_INET_OFFLOAD
);
252 addrlen
= sizeof (sin_t
);
253 v4addr
= rds
->rds_src
;
254 port
= rds
->rds_port
;
255 mp1
= mi_copyout_alloc(q
, mp
, STRUCT_FGETP(sb
, buf
), addrlen
,
259 STRUCT_FSET(sb
, len
, (int)sizeof (sin_t
));
260 sin
= (sin_t
*)(uintptr_t)mp1
->b_rptr
;
261 mp1
->b_wptr
= (uchar_t
*)&sin
[1];
263 sin
->sin_family
= AF_INET_OFFLOAD
;
264 sin
->sin_addr
.s_addr
= v4addr
;
265 sin
->sin_port
= port
;
278 mi_copy_done(q
, mp
, err
);
282 rds_ioctl_copyin_setup(queue_t
*q
, mblk_t
*mp
)
284 struct iocblk
*iocp
= (struct iocblk
*)(uintptr_t)mp
->b_rptr
;
287 if (mp
->b_cont
== NULL
) {
288 iocp
->ioc_error
= EINVAL
;
289 mp
->b_datap
->db_type
= M_IOCNAK
;
295 switch (iocp
->ioc_cmd
) {
298 if (iocp
->ioc_count
== TRANSPARENT
)
299 copyin_size
= SIZEOF_STRUCT(ifconf
, iocp
->ioc_flag
);
301 copyin_size
= iocp
->ioc_count
;
305 copyin_size
= sizeof (int);
309 copyin_size
= sizeof (struct ifreq
);
312 copyin_size
= SIZEOF_STRUCT(strbuf
, iocp
->ioc_flag
);
315 mi_copyin(q
, mp
, NULL
, copyin_size
);
319 rds_ioctl(queue_t
*q
, mblk_t
*mp
)
321 struct iocblk
*iocp
= (struct iocblk
*)(uintptr_t)mp
->b_rptr
;
324 switch (iocp
->ioc_cmd
) {
331 rds_ioctl_copyin_setup(q
, mp
);
334 cmn_err(CE_CONT
, "rds_wput unsupported IOCTL \n");
335 miocnak(q
, mp
, 0, ENOTSUP
);
341 rds_verify_bind_address(ipaddr_t addr
)
346 struct lifreq
*lifrp
;
347 struct sockaddr_in
*sinp
;
348 boolean_t retval
= B_FALSE
;
350 if (rds_do_lifconf(&lifc
, &bufsize
) != 0)
353 nifs
= lifc
.lifc_len
/ sizeof (struct lifreq
);
354 for (lifrp
= lifc
.lifc_req
, i
= 0; i
< nifs
; i
++, lifrp
++) {
355 sinp
= (struct sockaddr_in
*)&lifrp
->lifr_addr
;
356 if (rds_capable_interface(lifrp
) &&
357 sinp
->sin_addr
.s_addr
== addr
) {
363 kmem_free(lifc
.lifc_buf
, bufsize
);