1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/cpuvar.h> 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 #include <sys/time.h> 35 #include <sys/varargs.h> 36 #include <sys/modctl.h> 37 #include <sys/pathname.h> 38 #include <sys/fs/snode.h> 39 #include <sys/fs/dv_node.h> 40 #include <sys/vnode.h> 41 #undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */ 42 43 #include <smbsrv/smb_vops.h> 44 #include <smbsrv/smb.h> 45 #include <smbsrv/mlsvc.h> 46 #include <smbsrv/smbvar.h> 47 #include <smbsrv/smb_kproto.h> 48 49 /* 50 * SMB Network Socket API 51 * 52 * smb_socreate: Creates an socket based on domain/type. 53 * smb_soshutdown: Disconnect a socket created with smb_socreate 54 * smb_sodestroy: Release resources associated with a socket 55 * smb_sosend: Send the contents of a buffer on a socket 56 * smb_sorecv: Receive data into a buffer from a socket 57 * smb_iov_sosend: Send the contents of an iovec on a socket 58 * smb_iov_sorecv: Receive data into an iovec from a socket 59 */ 60 61 struct sonode * 62 smb_socreate(int domain, int type, int protocol) 63 { 64 vnode_t *dvp = NULL; 65 vnode_t *vp = NULL; 66 struct snode *csp = NULL; 67 int err = 0; 68 major_t maj; 69 70 if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) { 71 72 /* 73 * solookup calls sogetvp if the vp is not found in the cache. 74 * Since the call to sogetvp is hardwired to use USERSPACE 75 * and declared static we'll do the work here instead. 76 */ 77 err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp", 78 UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 79 if (err) 80 return (NULL); 81 82 /* Check that it is the correct vnode */ 83 if (vp->v_type != VCHR) { 84 VN_RELE(vp); 85 return (NULL); 86 } 87 88 csp = VTOS(VTOS(vp)->s_commonvp); 89 if (!(csp->s_flag & SDIPSET)) { 90 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 91 err = ddi_dev_pathname(vp->v_rdev, S_IFCHR, 92 pathname); 93 if (err == 0) { 94 err = devfs_lookupname(pathname, NULLVPP, 95 &dvp); 96 } 97 VN_RELE(vp); 98 kmem_free(pathname, MAXPATHLEN); 99 if (err != 0) { 100 return (NULL); 101 } 102 vp = dvp; 103 } 104 105 maj = getmajor(vp->v_rdev); 106 if (!STREAMSTAB(maj)) { 107 VN_RELE(vp); 108 return (NULL); 109 } 110 } 111 112 return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err)); 113 } 114 115 /* 116 * smb_soshutdown will disconnect the socket and prevent subsequent PDU 117 * reception and transmission. The sonode still exists but its state 118 * gets modified to indicate it is no longer connected. Calls to 119 * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used 120 * regain control of a thread stuck in smb_sorecv. 121 */ 122 void 123 smb_soshutdown(struct sonode *so) 124 { 125 (void) soshutdown(so, SHUT_RDWR); 126 } 127 128 /* 129 * smb_sodestroy releases all resources associated with a socket previously 130 * created with smb_socreate. The socket must be shutdown using smb_soshutdown 131 * before the socket is destroyed with smb_sodestroy, otherwise undefined 132 * behavior will result. 133 */ 134 void 135 smb_sodestroy(struct sonode *so) 136 { 137 vnode_t *vp = SOTOV(so); 138 139 (void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL); 140 VN_RELE(vp); 141 } 142 143 int 144 smb_sosend(struct sonode *so, void *msg, size_t len) 145 { 146 iovec_t iov; 147 int err; 148 149 ASSERT(so != NULL); 150 ASSERT(len != 0); 151 152 /* 153 * Fill in iovec and receive data 154 */ 155 iov.iov_base = msg; 156 iov.iov_len = len; 157 158 if ((err = smb_iov_sosend(so, &iov, 1, len)) != 0) { 159 return (err); 160 } 161 162 /* Successful receive */ 163 return (0); 164 } 165 166 int 167 smb_sorecv(struct sonode *so, void *msg, size_t len) 168 { 169 iovec_t iov; 170 int err; 171 172 ASSERT(so != NULL); 173 ASSERT(len != 0); 174 175 /* 176 * Fill in iovec and receive data 177 */ 178 iov.iov_base = msg; 179 iov.iov_len = len; 180 181 if ((err = smb_iov_sorecv(so, &iov, 1, len)) != 0) { 182 return (err); 183 } 184 185 /* Successful receive */ 186 return (0); 187 } 188 189 /* 190 * smb_iov_sosend - Sends an iovec on a connection. 191 * 192 * This function puts the data provided on the wire by calling sosendmsg. 193 * It will return only when all the data has been sent or if an error 194 * occurs. 195 * 196 * Returns 0 for success, the socket errno value if sosendmsg fails, and 197 * -1 if sosendmsg returns success but uio_resid != 0 198 */ 199 int 200 smb_iov_sosend(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len) 201 { 202 struct msghdr msg; 203 struct uio uio; 204 int error; 205 206 ASSERT(iop != NULL); 207 208 /* Initialization of the message header. */ 209 bzero(&msg, sizeof (msg)); 210 msg.msg_iov = iop; 211 msg.msg_flags = MSG_WAITALL; 212 msg.msg_iovlen = iovlen; 213 214 /* Initialization of the uio structure. */ 215 bzero(&uio, sizeof (uio)); 216 uio.uio_iov = iop; 217 uio.uio_iovcnt = iovlen; 218 uio.uio_segflg = UIO_SYSSPACE; 219 uio.uio_resid = total_len; 220 221 if ((error = sosendmsg(so, &msg, &uio)) == 0) { 222 /* Data sent */ 223 if (uio.uio_resid == 0) { 224 /* All data sent. Success. */ 225 return (0); 226 } else { 227 /* Not all data was sent. Failure */ 228 return (-1); 229 } 230 } 231 232 /* Send failed */ 233 return (error); 234 } 235 236 /* 237 * smb_iov_sorecv - Receives an iovec from a connection 238 * 239 * This function gets the data asked for from the socket. It will return 240 * only when all the requested data has been retrieved or if an error 241 * occurs. 242 * 243 * Returns 0 for success, the socket errno value if sorecvmsg fails, and 244 * -1 if sorecvmsg returns success but uio_resid != 0 245 */ 246 int 247 smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len) 248 { 249 struct msghdr msg; 250 struct uio uio; 251 int error; 252 253 ASSERT(iop != NULL); 254 255 /* Initialization of the message header. */ 256 bzero(&msg, sizeof (msg)); 257 msg.msg_iov = iop; 258 msg.msg_flags = MSG_WAITALL; 259 msg.msg_iovlen = iovlen; 260 261 /* Initialization of the uio structure. */ 262 bzero(&uio, sizeof (uio)); 263 uio.uio_iov = iop; 264 uio.uio_iovcnt = iovlen; 265 uio.uio_segflg = UIO_SYSSPACE; 266 uio.uio_resid = total_len; 267 268 if ((error = sorecvmsg(so, &msg, &uio)) == 0) { 269 /* Received data */ 270 if (uio.uio_resid == 0) { 271 /* All requested data received. Success */ 272 return (0); 273 } else { 274 /* Not all data was sent. Failure */ 275 return (-1); 276 } 277 } 278 279 /* Receive failed */ 280 return (error); 281 } 282