10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*132Srobinson 230Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 240Sstevel@tonic-gate /* All Rights Reserved */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 27*132Srobinson * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 280Sstevel@tonic-gate * Use is subject to license terms. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5.3.3 */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include "mt.h" 34*132Srobinson #include <stdlib.h> 35*132Srobinson #include <string.h> 36*132Srobinson #include <strings.h> 370Sstevel@tonic-gate #include <unistd.h> 380Sstevel@tonic-gate #include <errno.h> 390Sstevel@tonic-gate #include <stropts.h> 40*132Srobinson #include <sys/stream.h> 410Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 42*132Srobinson #include <sys/tihdr.h> 430Sstevel@tonic-gate #include <sys/timod.h> 44*132Srobinson #include <sys/stat.h> 450Sstevel@tonic-gate #include <xti.h> 46*132Srobinson #include <fcntl.h> 470Sstevel@tonic-gate #include <signal.h> 48*132Srobinson #include <assert.h> 490Sstevel@tonic-gate #include <syslog.h> 50*132Srobinson #include <limits.h> 510Sstevel@tonic-gate #include "tx.h" 520Sstevel@tonic-gate 530Sstevel@tonic-gate /* 540Sstevel@tonic-gate * If _tx_open is called for transport that doesn't understand T_CAPABILITY_REQ 550Sstevel@tonic-gate * TPI message, call to _t_create may fail the first time it is called with 560Sstevel@tonic-gate * given transport (in the rare case when transport shuts down the stream with 570Sstevel@tonic-gate * M_ERROR in reply to unknown T_CAPABILITY_REQ). In this case we may reopen the 580Sstevel@tonic-gate * stream again since timod will emulate T_CAPABILITY_REQ behaviour. 590Sstevel@tonic-gate * 600Sstevel@tonic-gate * _t_create sends T_CAPABILITY_REQ through TI_CAPABILITY ioctl. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate int 640Sstevel@tonic-gate _tx_open(const char *path, int flags, struct t_info *info, int api_semantics) 650Sstevel@tonic-gate { 660Sstevel@tonic-gate int retval, fd, sv_errno; 670Sstevel@tonic-gate int sv_terrno; 680Sstevel@tonic-gate int sv_errno_global; 690Sstevel@tonic-gate struct _ti_user *tiptr; 700Sstevel@tonic-gate sigset_t mask; 710Sstevel@tonic-gate int t_create_first_attempt = 1; 720Sstevel@tonic-gate int ticap_ioctl_failed = 0; 730Sstevel@tonic-gate 740Sstevel@tonic-gate if (!(flags & O_RDWR)) { 750Sstevel@tonic-gate t_errno = TBADFLAG; 760Sstevel@tonic-gate return (-1); 770Sstevel@tonic-gate } 780Sstevel@tonic-gate 790Sstevel@tonic-gate sv_errno_global = errno; 800Sstevel@tonic-gate sv_terrno = t_errno; 810Sstevel@tonic-gate 820Sstevel@tonic-gate retry: 830Sstevel@tonic-gate if ((fd = open(path, flags)) < 0) { 840Sstevel@tonic-gate t_errno = TSYSERR; 850Sstevel@tonic-gate if (_T_IS_XTI(api_semantics) && errno == ENOENT) 860Sstevel@tonic-gate /* XTI only */ 870Sstevel@tonic-gate t_errno = TBADNAME; 880Sstevel@tonic-gate return (-1); 890Sstevel@tonic-gate } 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * is module already pushed 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate do { 940Sstevel@tonic-gate retval = _ioctl(fd, I_FIND, "timod"); 950Sstevel@tonic-gate } while (retval < 0 && errno == EINTR); 960Sstevel@tonic-gate 970Sstevel@tonic-gate if (retval < 0) { 980Sstevel@tonic-gate sv_errno = errno; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate t_errno = TSYSERR; 1010Sstevel@tonic-gate (void) close(fd); 1020Sstevel@tonic-gate errno = sv_errno; 1030Sstevel@tonic-gate return (-1); 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate if (retval == 0) { 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * "timod" not already on stream, then push it 1090Sstevel@tonic-gate */ 1100Sstevel@tonic-gate do { 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * Assumes (correctly) that I_PUSH is 1130Sstevel@tonic-gate * atomic w.r.t signals (EINTR error) 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate retval = _ioctl(fd, I_PUSH, "timod"); 1160Sstevel@tonic-gate } while (retval < 0 && errno == EINTR); 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate if (retval < 0) { 1190Sstevel@tonic-gate int sv_errno = errno; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate t_errno = TSYSERR; 1220Sstevel@tonic-gate (void) close(fd); 1230Sstevel@tonic-gate errno = sv_errno; 1240Sstevel@tonic-gate return (-1); 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate } 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate /* 1290Sstevel@tonic-gate * _t_create() requires that all signals be blocked. 1300Sstevel@tonic-gate * Note that sig_mutex_lock() only defers signals, it does not 1310Sstevel@tonic-gate * block them, so interruptible syscalls could still get EINTR. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &fillset, &mask); 1340Sstevel@tonic-gate sig_mutex_lock(&_ti_userlock); 1350Sstevel@tonic-gate /* 1360Sstevel@tonic-gate * Call to _t_create may fail either because transport doesn't 1370Sstevel@tonic-gate * understand T_CAPABILITY_REQ or for some other reason. It is nearly 1380Sstevel@tonic-gate * impossible to distinguish between these cases so it is implicitly 1390Sstevel@tonic-gate * assumed that it is always save to close and reopen the same stream 1400Sstevel@tonic-gate * and that open/close doesn't have side effects. _t_create may fail 1410Sstevel@tonic-gate * only once if its' failure is caused by unimplemented 1420Sstevel@tonic-gate * T_CAPABILITY_REQ. 1430Sstevel@tonic-gate */ 1440Sstevel@tonic-gate tiptr = _t_create(fd, info, api_semantics, &ticap_ioctl_failed); 1450Sstevel@tonic-gate if (tiptr == NULL) { 1460Sstevel@tonic-gate /* 1470Sstevel@tonic-gate * If _t_create failed due to fail of ti_capability_req we may 1480Sstevel@tonic-gate * try to reopen the stream in the hope that timod will emulate 1490Sstevel@tonic-gate * TI_CAPABILITY and it will succeed when called again. 1500Sstevel@tonic-gate */ 1510Sstevel@tonic-gate if (t_create_first_attempt == 1 && ticap_ioctl_failed == 1) { 1520Sstevel@tonic-gate t_create_first_attempt = 0; 1530Sstevel@tonic-gate (void) close(fd); 1540Sstevel@tonic-gate errno = sv_errno_global; 1550Sstevel@tonic-gate t_errno = sv_terrno; 1560Sstevel@tonic-gate sig_mutex_unlock(&_ti_userlock); 1570Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 1580Sstevel@tonic-gate goto retry; 1590Sstevel@tonic-gate } else { 1600Sstevel@tonic-gate int sv_errno = errno; 1610Sstevel@tonic-gate (void) close(fd); 1620Sstevel@tonic-gate sig_mutex_unlock(&_ti_userlock); 1630Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 1640Sstevel@tonic-gate errno = sv_errno; 1650Sstevel@tonic-gate return (-1); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * _t_create synchronizes state witk kernel timod and 1710Sstevel@tonic-gate * already sets it to T_UNBND - what it needs to be 1720Sstevel@tonic-gate * be on T_OPEN event. No _T_TX_NEXTSTATE needed here. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate sig_mutex_unlock(&_ti_userlock); 1750Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate do { 1780Sstevel@tonic-gate retval = _ioctl(fd, I_FLUSH, FLUSHRW); 1790Sstevel@tonic-gate } while (retval < 0 && errno == EINTR); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * We ignore other error cases (retval < 0) - assumption is 1830Sstevel@tonic-gate * that I_FLUSH failures is temporary (e.g. ENOSR) or 1840Sstevel@tonic-gate * otherwise benign failure on a this newly opened file 1850Sstevel@tonic-gate * descriptor and not a critical failure. 1860Sstevel@tonic-gate */ 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate return (fd); 1890Sstevel@tonic-gate } 190