t_open.c revision 1219:f89f56c2d9ac
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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
24/*	  All Rights Reserved  	*/
25
26/*
27 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.5.3.3 */
32
33#include "mt.h"
34#include <stdlib.h>
35#include <string.h>
36#include <strings.h>
37#include <unistd.h>
38#include <errno.h>
39#include <stropts.h>
40#include <sys/stream.h>
41#define	_SUN_TPI_VERSION 2
42#include <sys/tihdr.h>
43#include <sys/timod.h>
44#include <sys/stat.h>
45#include <xti.h>
46#include <fcntl.h>
47#include <signal.h>
48#include <assert.h>
49#include <syslog.h>
50#include <limits.h>
51#include "tx.h"
52
53/*
54 * If _tx_open is called for transport that doesn't understand T_CAPABILITY_REQ
55 * TPI message, call to _t_create may fail the first time it is called with
56 * given transport (in the rare case when transport shuts down the stream with
57 * M_ERROR in reply to unknown T_CAPABILITY_REQ). In this case we may reopen the
58 * stream again since timod will emulate T_CAPABILITY_REQ behaviour.
59 *
60 * _t_create sends T_CAPABILITY_REQ through TI_CAPABILITY ioctl.
61 */
62
63int
64_tx_open(const char *path, int flags, struct t_info *info, int api_semantics)
65{
66	int retval, fd, sv_errno;
67	int sv_terrno;
68	int sv_errno_global;
69	struct _ti_user *tiptr;
70	sigset_t mask;
71	int t_create_first_attempt = 1;
72	int ticap_ioctl_failed = 0;
73
74	if (!(flags & O_RDWR)) {
75		t_errno = TBADFLAG;
76		return (-1);
77	}
78
79	sv_errno_global = errno;
80	sv_terrno = t_errno;
81
82retry:
83	if ((fd = open(path, flags)) < 0) {
84		t_errno = TSYSERR;
85		if (_T_IS_XTI(api_semantics) && errno == ENOENT)
86			/* XTI only */
87			t_errno = TBADNAME;
88		return (-1);
89	}
90	/*
91	 * is module already pushed
92	 */
93	do {
94		retval = ioctl(fd, I_FIND, "timod");
95	} while (retval < 0 && errno == EINTR);
96
97	if (retval < 0) {
98		sv_errno = errno;
99
100		t_errno = TSYSERR;
101		(void) close(fd);
102		errno = sv_errno;
103		return (-1);
104	}
105
106	if (retval == 0) {
107		/*
108		 * "timod" not already on stream, then push it
109		 */
110		do {
111			/*
112			 * Assumes (correctly) that I_PUSH  is
113			 * atomic w.r.t signals (EINTR error)
114			 */
115			retval = ioctl(fd, I_PUSH, "timod");
116		} while (retval < 0 && errno == EINTR);
117
118		if (retval < 0) {
119			int sv_errno = errno;
120
121			t_errno = TSYSERR;
122			(void) close(fd);
123			errno = sv_errno;
124			return (-1);
125		}
126	}
127
128	/*
129	 * _t_create() requires that all signals be blocked.
130	 * Note that sig_mutex_lock() only defers signals, it does not
131	 * block them, so interruptible syscalls could still get EINTR.
132	 */
133	(void) thr_sigsetmask(SIG_SETMASK, &fillset, &mask);
134	sig_mutex_lock(&_ti_userlock);
135	/*
136	 * Call to _t_create may fail either because transport doesn't
137	 * understand T_CAPABILITY_REQ or for some other reason. It is nearly
138	 * impossible to distinguish between these cases so it is implicitly
139	 * assumed that it is always save to close and reopen the same stream
140	 * and that open/close doesn't have side effects. _t_create may fail
141	 * only once if its' failure is caused by unimplemented
142	 * T_CAPABILITY_REQ.
143	 */
144	tiptr = _t_create(fd, info, api_semantics, &ticap_ioctl_failed);
145	if (tiptr == NULL) {
146		/*
147		 * If _t_create failed due to fail of ti_capability_req we may
148		 * try to reopen the stream in the hope that timod will emulate
149		 * TI_CAPABILITY and it will succeed when called again.
150		 */
151		if (t_create_first_attempt == 1 && ticap_ioctl_failed == 1) {
152			t_create_first_attempt = 0;
153			(void) close(fd);
154			errno = sv_errno_global;
155			t_errno = sv_terrno;
156			sig_mutex_unlock(&_ti_userlock);
157			(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
158			goto retry;
159		} else {
160			int sv_errno = errno;
161			(void) close(fd);
162			sig_mutex_unlock(&_ti_userlock);
163			(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
164			errno = sv_errno;
165			return (-1);
166		}
167	}
168
169	/*
170	 * _t_create synchronizes state witk kernel timod and
171	 * already sets it to T_UNBND - what it needs to be
172	 * be on T_OPEN event. No _T_TX_NEXTSTATE needed here.
173	 */
174	sig_mutex_unlock(&_ti_userlock);
175	(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
176
177	do {
178		retval = ioctl(fd, I_FLUSH, FLUSHRW);
179	} while (retval < 0 && errno == EINTR);
180
181	/*
182	 * We ignore other error cases (retval < 0) - assumption is
183	 * that I_FLUSH failures is temporary (e.g. ENOSR) or
184	 * otherwise benign failure on a this newly opened file
185	 * descriptor and not a critical failure.
186	 */
187
188	return (fd);
189}
190