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