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 2008 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_sorecv(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_sorecv(so, &iov, 1, len)) != 0) { 159 return (err); 160 } 161 162 /* Successful receive */ 163 return (0); 164 } 165 166 /* 167 * smb_iov_sorecv - Receives an iovec from a connection 168 * 169 * This function gets the data asked for from the socket. It will return 170 * only when all the requested data has been retrieved or if an error 171 * occurs. 172 * 173 * Returns 0 for success, the socket errno value if sorecvmsg fails, and 174 * -1 if sorecvmsg returns success but uio_resid != 0 175 */ 176 int 177 smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len) 178 { 179 struct msghdr msg; 180 struct uio uio; 181 int error; 182 183 ASSERT(iop != NULL); 184 185 /* Initialization of the message header. */ 186 bzero(&msg, sizeof (msg)); 187 msg.msg_iov = iop; 188 msg.msg_flags = MSG_WAITALL; 189 msg.msg_iovlen = iovlen; 190 191 /* Initialization of the uio structure. */ 192 bzero(&uio, sizeof (uio)); 193 uio.uio_iov = iop; 194 uio.uio_iovcnt = iovlen; 195 uio.uio_segflg = UIO_SYSSPACE; 196 uio.uio_resid = total_len; 197 198 if ((error = sorecvmsg(so, &msg, &uio)) == 0) { 199 /* Received data */ 200 if (uio.uio_resid == 0) { 201 /* All requested data received. Success */ 202 return (0); 203 } else { 204 /* Not all data was sent. Failure */ 205 return (-1); 206 } 207 } 208 209 /* Receive failed */ 210 return (error); 211 } 212 213 /* 214 * smb_net_txl_constructor 215 * 216 * Transmit list constructor 217 */ 218 void 219 smb_net_txl_constructor(smb_txlst_t *txl) 220 { 221 ASSERT(txl->tl_magic != SMB_TXLST_MAGIC); 222 223 mutex_init(&txl->tl_mutex, NULL, MUTEX_DEFAULT, NULL); 224 list_create(&txl->tl_list, sizeof (smb_txbuf_t), 225 offsetof(smb_txbuf_t, tb_lnd)); 226 txl->tl_active = B_FALSE; 227 txl->tl_magic = SMB_TXLST_MAGIC; 228 } 229 230 /* 231 * smb_net_txl_destructor 232 * 233 * Transmit list destructor 234 */ 235 void 236 smb_net_txl_destructor(smb_txlst_t *txl) 237 { 238 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC); 239 240 txl->tl_magic = 0; 241 list_destroy(&txl->tl_list); 242 mutex_destroy(&txl->tl_mutex); 243 } 244 245 /* 246 * smb_net_txb_alloc 247 * 248 * Transmit buffer allocator 249 */ 250 smb_txbuf_t * 251 smb_net_txb_alloc(void) 252 { 253 smb_txbuf_t *txb; 254 255 txb = kmem_alloc(sizeof (smb_txbuf_t), KM_SLEEP); 256 257 bzero(&txb->tb_lnd, sizeof (txb->tb_lnd)); 258 txb->tb_len = 0; 259 txb->tb_magic = SMB_TXBUF_MAGIC; 260 261 return (txb); 262 } 263 264 /* 265 * smb_net_txb_free 266 * 267 * Transmit buffer deallocator 268 */ 269 void 270 smb_net_txb_free(smb_txbuf_t *txb) 271 { 272 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 273 ASSERT(!list_link_active(&txb->tb_lnd)); 274 275 txb->tb_magic = 0; 276 kmem_free(txb, sizeof (smb_txbuf_t)); 277 } 278 279 /* 280 * smb_net_txb_send 281 * 282 * This routine puts the transmit buffer passed in on the wire. If another 283 * thread is already draining the transmit list, the transmit buffer is 284 * queued and the routine returns immediately. 285 */ 286 int 287 smb_net_txb_send(struct sonode *so, smb_txlst_t *txl, smb_txbuf_t *txb) 288 { 289 list_t local; 290 int rc = 0; 291 iovec_t iov; 292 struct msghdr msg; 293 struct uio uio; 294 295 ASSERT(txl->tl_magic == SMB_TXLST_MAGIC); 296 297 mutex_enter(&txl->tl_mutex); 298 list_insert_tail(&txl->tl_list, txb); 299 if (txl->tl_active) { 300 mutex_exit(&txl->tl_mutex); 301 return (0); 302 } 303 304 txl->tl_active = B_TRUE; 305 list_create(&local, sizeof (smb_txbuf_t), 306 offsetof(smb_txbuf_t, tb_lnd)); 307 308 while (!list_is_empty(&txl->tl_list)) { 309 list_move_tail(&local, &txl->tl_list); 310 mutex_exit(&txl->tl_mutex); 311 while ((txb = list_head(&local)) != NULL) { 312 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 313 list_remove(&local, txb); 314 315 iov.iov_base = (void *)txb->tb_data; 316 iov.iov_len = txb->tb_len; 317 318 bzero(&msg, sizeof (msg)); 319 msg.msg_iov = &iov; 320 msg.msg_flags = MSG_WAITALL; 321 msg.msg_iovlen = 1; 322 323 bzero(&uio, sizeof (uio)); 324 uio.uio_iov = &iov; 325 uio.uio_iovcnt = 1; 326 uio.uio_segflg = UIO_SYSSPACE; 327 uio.uio_resid = txb->tb_len; 328 329 rc = sosendmsg(so, &msg, &uio); 330 331 smb_net_txb_free(txb); 332 333 if ((rc == 0) && (uio.uio_resid == 0)) 334 continue; 335 336 if (rc == 0) 337 rc = -1; 338 339 while ((txb = list_head(&local)) != NULL) { 340 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 341 list_remove(&local, txb); 342 smb_net_txb_free(txb); 343 } 344 break; 345 } 346 mutex_enter(&txl->tl_mutex); 347 348 if (rc == 0) 349 continue; 350 351 while ((txb = list_head(&txl->tl_list)) != NULL) { 352 ASSERT(txb->tb_magic == SMB_TXBUF_MAGIC); 353 list_remove(&txl->tl_list, txb); 354 smb_net_txb_free(txb); 355 } 356 break; 357 } 358 txl->tl_active = B_FALSE; 359 mutex_exit(&txl->tl_mutex); 360 361 return (rc); 362 } 363