15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*5970Sjb150015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw 275331Samw #pragma ident "%Z%%M% %I% %E% SMI" 285331Samw 295331Samw #include <sys/types.h> 305331Samw #include <sys/param.h> 315331Samw #include <sys/cpuvar.h> 325331Samw #include <sys/ddi.h> 335331Samw #include <sys/sunddi.h> 345331Samw #include <sys/time.h> 355331Samw #include <sys/varargs.h> 365331Samw #include <sys/modctl.h> 375331Samw #include <sys/pathname.h> 385331Samw #include <sys/fs/snode.h> 395331Samw #include <sys/fs/dv_node.h> 405331Samw #include <sys/vnode.h> 415331Samw #undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */ 425331Samw 435331Samw #include <smbsrv/smb_vops.h> 445331Samw #include <smbsrv/smb.h> 455331Samw #include <smbsrv/mlsvc.h> 465331Samw #include <smbsrv/smbvar.h> 475331Samw #include <smbsrv/smb_kproto.h> 485331Samw 495331Samw /* 505331Samw * SMB Network Socket API 515331Samw * 525331Samw * smb_socreate: Creates an socket based on domain/type. 535331Samw * smb_soshutdown: Disconnect a socket created with smb_socreate 545331Samw * smb_sodestroy: Release resources associated with a socket 555331Samw * smb_sosend: Send the contents of a buffer on a socket 565331Samw * smb_sorecv: Receive data into a buffer from a socket 575331Samw * smb_iov_sosend: Send the contents of an iovec on a socket 585331Samw * smb_iov_sorecv: Receive data into an iovec from a socket 595331Samw */ 605331Samw 615331Samw struct sonode * 625331Samw smb_socreate(int domain, int type, int protocol) 635331Samw { 645331Samw vnode_t *dvp = NULL; 655331Samw vnode_t *vp = NULL; 665331Samw struct snode *csp = NULL; 675331Samw int err = 0; 685331Samw major_t maj; 695331Samw 705331Samw if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) { 715331Samw 725331Samw /* 735331Samw * solookup calls sogetvp if the vp is not found in the cache. 745331Samw * Since the call to sogetvp is hardwired to use USERSPACE 755331Samw * and declared static we'll do the work here instead. 765331Samw */ 775331Samw err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp", 785331Samw UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 795331Samw if (err) 805331Samw return (NULL); 815331Samw 825331Samw /* Check that it is the correct vnode */ 835331Samw if (vp->v_type != VCHR) { 845331Samw VN_RELE(vp); 855331Samw return (NULL); 865331Samw } 875331Samw 885331Samw csp = VTOS(VTOS(vp)->s_commonvp); 895331Samw if (!(csp->s_flag & SDIPSET)) { 905331Samw char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 915331Samw err = ddi_dev_pathname(vp->v_rdev, S_IFCHR, 925331Samw pathname); 935331Samw if (err == 0) { 945331Samw err = devfs_lookupname(pathname, NULLVPP, 955331Samw &dvp); 965331Samw } 975331Samw VN_RELE(vp); 985331Samw kmem_free(pathname, MAXPATHLEN); 995331Samw if (err != 0) { 1005331Samw return (NULL); 1015331Samw } 1025331Samw vp = dvp; 1035331Samw } 1045331Samw 1055331Samw maj = getmajor(vp->v_rdev); 1065331Samw if (!STREAMSTAB(maj)) { 1075331Samw VN_RELE(vp); 1085331Samw return (NULL); 1095331Samw } 1105331Samw } 1115331Samw 1125331Samw return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err)); 1135331Samw } 1145331Samw 1155331Samw /* 1165331Samw * smb_soshutdown will disconnect the socket and prevent subsequent PDU 1175331Samw * reception and transmission. The sonode still exists but its state 1185331Samw * gets modified to indicate it is no longer connected. Calls to 1195331Samw * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used 1205331Samw * regain control of a thread stuck in smb_sorecv. 1215331Samw */ 1225331Samw void 1235331Samw smb_soshutdown(struct sonode *so) 1245331Samw { 1255331Samw (void) soshutdown(so, SHUT_RDWR); 1265331Samw } 1275331Samw 1285331Samw /* 1295331Samw * smb_sodestroy releases all resources associated with a socket previously 1305331Samw * created with smb_socreate. The socket must be shutdown using smb_soshutdown 1315331Samw * before the socket is destroyed with smb_sodestroy, otherwise undefined 1325331Samw * behavior will result. 1335331Samw */ 1345331Samw void 1355331Samw smb_sodestroy(struct sonode *so) 1365331Samw { 1375331Samw vnode_t *vp = SOTOV(so); 1385331Samw 1395331Samw (void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL); 1405331Samw VN_RELE(vp); 1415331Samw } 1425331Samw 1435331Samw int 1445331Samw smb_sorecv(struct sonode *so, void *msg, size_t len) 1455331Samw { 1465331Samw iovec_t iov; 1475331Samw int err; 1485331Samw 1495331Samw ASSERT(so != NULL); 1505331Samw ASSERT(len != 0); 1515331Samw 1525331Samw /* 1535331Samw * Fill in iovec and receive data 1545331Samw */ 1555331Samw iov.iov_base = msg; 1565331Samw iov.iov_len = len; 1575331Samw 1585331Samw if ((err = smb_iov_sorecv(so, &iov, 1, len)) != 0) { 1595331Samw return (err); 1605331Samw } 1615331Samw 1625331Samw /* Successful receive */ 1635331Samw return (0); 1645331Samw } 1655331Samw 1665331Samw /* 1675331Samw * smb_iov_sorecv - Receives an iovec from a connection 1685331Samw * 1695331Samw * This function gets the data asked for from the socket. It will return 1705331Samw * only when all the requested data has been retrieved or if an error 1715331Samw * occurs. 1725331Samw * 1735331Samw * Returns 0 for success, the socket errno value if sorecvmsg fails, and 1745331Samw * -1 if sorecvmsg returns success but uio_resid != 0 1755331Samw */ 1765331Samw int 1775331Samw smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len) 1785331Samw { 1795331Samw struct msghdr msg; 1805331Samw struct uio uio; 1815331Samw int error; 1825331Samw 1835331Samw ASSERT(iop != NULL); 1845331Samw 1855331Samw /* Initialization of the message header. */ 1865331Samw bzero(&msg, sizeof (msg)); 1875331Samw msg.msg_iov = iop; 1885331Samw msg.msg_flags = MSG_WAITALL; 1895331Samw msg.msg_iovlen = iovlen; 1905331Samw 1915331Samw /* Initialization of the uio structure. */ 1925331Samw bzero(&uio, sizeof (uio)); 1935331Samw uio.uio_iov = iop; 1945331Samw uio.uio_iovcnt = iovlen; 1955331Samw uio.uio_segflg = UIO_SYSSPACE; 1965331Samw uio.uio_resid = total_len; 1975331Samw 1985331Samw if ((error = sorecvmsg(so, &msg, &uio)) == 0) { 1995331Samw /* Received data */ 2005331Samw if (uio.uio_resid == 0) { 2015331Samw /* All requested data received. Success */ 2025331Samw return (0); 2035331Samw } else { 2045331Samw /* Not all data was sent. Failure */ 2055331Samw return (-1); 2065331Samw } 2075331Samw } 2085331Samw 2095331Samw /* Receive failed */ 2105331Samw return (error); 2115331Samw } 212*5970Sjb150015 213*5970Sjb150015 /* 214*5970Sjb150015 * smb_net_txl_constructor 215*5970Sjb150015 * 216*5970Sjb150015 * Transmit list constructor 217*5970Sjb150015 */ 218*5970Sjb150015 void 219*5970Sjb150015 smb_net_txl_constructor(smb_txlst_t *txl) 220*5970Sjb150015 { 221*5970Sjb150015 ASSERT(txl->tl_magic != SMB_TXLST_MAGIC); 222*5970Sjb150015 223*5970Sjb150015 mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL); 224*5970Sjb150015 list_create(&txl->tl_list, sizeof (smb_txbuf_t), 225*5970Sjb150015 offsetof(smb_txbuf_t, tb_lnd)); 226*5970Sjb150015 txl->tl_active = B_FALSE; 227*5970Sjb150015 txl->tl_magic = SMB_TXLST_MAGIC; 228*5970Sjb150015 } 229*5970Sjb150015 230*5970Sjb150015 /* 231*5970Sjb150015 * smb_net_txl_destructor 232*5970Sjb150015 * 233*5970Sjb150015 * Transmit list destructor 234*5970Sjb150015 */ 235*5970Sjb150015 void 236*5970Sjb150015 smb_net_txl_destructor(smb_txlst_t *txl) 237*5970Sjb150015 { 238*5970Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC); 239*5970Sjb150015 240*5970Sjb150015 txl->tl_magic = 0; 241*5970Sjb150015 list_destroy(&txl->tl_list); 242*5970Sjb150015 mutex_destroy(&txl->tl_mutex); 243*5970Sjb150015 } 244*5970Sjb150015 245*5970Sjb150015 /* 246*5970Sjb150015 * smb_net_txb_alloc 247*5970Sjb150015 * 248*5970Sjb150015 * Transmit buffer allocator 249*5970Sjb150015 */ 250*5970Sjb150015 smb_txbuf_t * 251*5970Sjb150015 smb_net_txb_alloc(void) 252*5970Sjb150015 { 253*5970Sjb150015 smb_txbuf_t *txb; 254*5970Sjb150015 255*5970Sjb150015 txb = kmem_alloc(sizeof (smb_txbuf_t), KM_SLEEP); 256*5970Sjb150015 257*5970Sjb150015 bzero(&txb->tb_lnd, sizeof (txb->tb_lnd)); 258*5970Sjb150015 txb->tb_len = 0; 259*5970Sjb150015 txb->tb_magic = SMB_TXBUF_MAGIC; 260*5970Sjb150015 261*5970Sjb150015 return (txb); 262*5970Sjb150015 } 263*5970Sjb150015 264*5970Sjb150015 /* 265*5970Sjb150015 * smb_net_txb_free 266*5970Sjb150015 * 267*5970Sjb150015 * Transmit buffer deallocator 268*5970Sjb150015 */ 269*5970Sjb150015 void 270*5970Sjb150015 smb_net_txb_free(smb_txbuf_t *txb) 271*5970Sjb150015 { 272*5970Sjb150015 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 273*5970Sjb150015 ASSERT(!list_link_active(&txb->tb_lnd)); 274*5970Sjb150015 275*5970Sjb150015 txb->tb_magic = 0; 276*5970Sjb150015 kmem_free(txb, sizeof (smb_txbuf_t)); 277*5970Sjb150015 } 278*5970Sjb150015 279*5970Sjb150015 /* 280*5970Sjb150015 * smb_net_txb_send 281*5970Sjb150015 * 282*5970Sjb150015 * This routine puts the transmit buffer passed in on the wire. If another 283*5970Sjb150015 * thread is already draining the transmit list, the transmit buffer is 284*5970Sjb150015 * queued and the routine returns immediately. 285*5970Sjb150015 */ 286*5970Sjb150015 int 287*5970Sjb150015 smb_net_txb_send(struct sonode *so, smb_txlst_t *txl, smb_txbuf_t *txb) 288*5970Sjb150015 { 289*5970Sjb150015 list_t local; 290*5970Sjb150015 int rc = 0; 291*5970Sjb150015 iovec_t iov; 292*5970Sjb150015 struct msghdr msg; 293*5970Sjb150015 struct uio uio; 294*5970Sjb150015 295*5970Sjb150015 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC); 296*5970Sjb150015 297*5970Sjb150015 mutex_enter(&txl->tl_mutex); 298*5970Sjb150015 list_insert_tail(&txl->tl_list, txb); 299*5970Sjb150015 if (txl->tl_active) { 300*5970Sjb150015 mutex_exit(&txl->tl_mutex); 301*5970Sjb150015 return (0); 302*5970Sjb150015 } 303*5970Sjb150015 304*5970Sjb150015 txl->tl_active = B_TRUE; 305*5970Sjb150015 list_create(&local, sizeof (smb_txbuf_t), 306*5970Sjb150015 offsetof(smb_txbuf_t, tb_lnd)); 307*5970Sjb150015 308*5970Sjb150015 while (!list_is_empty(&txl->tl_list)) { 309*5970Sjb150015 list_move_tail(&local, &txl->tl_list); 310*5970Sjb150015 mutex_exit(&txl->tl_mutex); 311*5970Sjb150015 while ((txb = list_head(&local)) != NULL) { 312*5970Sjb150015 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 313*5970Sjb150015 list_remove(&local, txb); 314*5970Sjb150015 315*5970Sjb150015 iov.iov_base = (void *)txb->tb_data; 316*5970Sjb150015 iov.iov_len = txb->tb_len; 317*5970Sjb150015 318*5970Sjb150015 bzero(&msg, sizeof (msg)); 319*5970Sjb150015 msg.msg_iov = &iov; 320*5970Sjb150015 msg.msg_flags = MSG_WAITALL; 321*5970Sjb150015 msg.msg_iovlen = 1; 322*5970Sjb150015 323*5970Sjb150015 bzero(&uio, sizeof (uio)); 324*5970Sjb150015 uio.uio_iov = &iov; 325*5970Sjb150015 uio.uio_iovcnt = 1; 326*5970Sjb150015 uio.uio_segflg = UIO_SYSSPACE; 327*5970Sjb150015 uio.uio_resid = txb->tb_len; 328*5970Sjb150015 329*5970Sjb150015 rc = sosendmsg(so, &msg, &uio); 330*5970Sjb150015 331*5970Sjb150015 smb_net_txb_free(txb); 332*5970Sjb150015 333*5970Sjb150015 if ((rc == 0) && (uio.uio_resid == 0)) 334*5970Sjb150015 continue; 335*5970Sjb150015 336*5970Sjb150015 if (rc == 0) 337*5970Sjb150015 rc = -1; 338*5970Sjb150015 339*5970Sjb150015 while ((txb = list_head(&local)) != NULL) { 340*5970Sjb150015 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 341*5970Sjb150015 list_remove(&local, txb); 342*5970Sjb150015 smb_net_txb_free(txb); 343*5970Sjb150015 } 344*5970Sjb150015 break; 345*5970Sjb150015 } 346*5970Sjb150015 mutex_enter(&txl->tl_mutex); 347*5970Sjb150015 348*5970Sjb150015 if (rc == 0) 349*5970Sjb150015 continue; 350*5970Sjb150015 351*5970Sjb150015 while ((txb = list_head(&txl->tl_list)) != NULL) { 352*5970Sjb150015 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 353*5970Sjb150015 list_remove(&txl->tl_list, txb); 354*5970Sjb150015 smb_net_txb_free(txb); 355*5970Sjb150015 } 356*5970Sjb150015 break; 357*5970Sjb150015 } 358*5970Sjb150015 txl->tl_active = B_FALSE; 359*5970Sjb150015 mutex_exit(&txl->tl_mutex); 360*5970Sjb150015 361*5970Sjb150015 return (rc); 362*5970Sjb150015 } 363