xref: /illumos-gate/usr/src/cmd/isns/isnsd/server.c (revision fcf3ce44)
1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte 
22*fcf3ce44SJohn Forte /*
23*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*fcf3ce44SJohn Forte  * Use is subject to license terms.
25*fcf3ce44SJohn Forte  */
26*fcf3ce44SJohn Forte 
27*fcf3ce44SJohn Forte #include <stdlib.h>
28*fcf3ce44SJohn Forte #include <stdio.h>
29*fcf3ce44SJohn Forte #include <sys/types.h>
30*fcf3ce44SJohn Forte #include <sys/socket.h>
31*fcf3ce44SJohn Forte #include <netinet/in.h>
32*fcf3ce44SJohn Forte #include <arpa/inet.h>
33*fcf3ce44SJohn Forte #include <unistd.h>
34*fcf3ce44SJohn Forte #include <string.h>
35*fcf3ce44SJohn Forte #include <pthread.h>
36*fcf3ce44SJohn Forte #include <poll.h>
37*fcf3ce44SJohn Forte #ifdef DEBUG
38*fcf3ce44SJohn Forte #include <time.h>
39*fcf3ce44SJohn Forte #endif
40*fcf3ce44SJohn Forte 
41*fcf3ce44SJohn Forte #include "isns_server.h"
42*fcf3ce44SJohn Forte #include "isns_cache.h"
43*fcf3ce44SJohn Forte #include "isns_pdu.h"
44*fcf3ce44SJohn Forte #include "isns_msgq.h"
45*fcf3ce44SJohn Forte #include "isns_func.h"
46*fcf3ce44SJohn Forte #include "isns_log.h"
47*fcf3ce44SJohn Forte #include "isns_provider.h"
48*fcf3ce44SJohn Forte 
49*fcf3ce44SJohn Forte /* external functions */
50*fcf3ce44SJohn Forte #ifdef DEBUG
51*fcf3ce44SJohn Forte extern void dump_pdu1(isns_pdu_t *);
52*fcf3ce44SJohn Forte extern int verbose_tc;
53*fcf3ce44SJohn Forte #endif
54*fcf3ce44SJohn Forte 
55*fcf3ce44SJohn Forte extern boolean_t time_to_exit;
56*fcf3ce44SJohn Forte 
57*fcf3ce44SJohn Forte void *
isns_connection(void * arg)58*fcf3ce44SJohn Forte isns_connection(
59*fcf3ce44SJohn Forte 	void *arg
60*fcf3ce44SJohn Forte )
61*fcf3ce44SJohn Forte {
62*fcf3ce44SJohn Forte 	int status = 0;
63*fcf3ce44SJohn Forte 
64*fcf3ce44SJohn Forte 	conn_arg_t *conn;
65*fcf3ce44SJohn Forte 
66*fcf3ce44SJohn Forte 	isns_pdu_t *pdu, *combined_pdu, *new_combined_pdu;
67*fcf3ce44SJohn Forte 	uint8_t *payload_ptr;
68*fcf3ce44SJohn Forte 	size_t pdu_sz;
69*fcf3ce44SJohn Forte 
70*fcf3ce44SJohn Forte 	conn = (conn_arg_t *)arg;
71*fcf3ce44SJohn Forte 
72*fcf3ce44SJohn Forte 	conn->out_packet.pdu = NULL;
73*fcf3ce44SJohn Forte 	conn->out_packet.sz = 0;
74*fcf3ce44SJohn Forte 	combined_pdu = NULL;
75*fcf3ce44SJohn Forte 	pdu = NULL;
76*fcf3ce44SJohn Forte 
77*fcf3ce44SJohn Forte 	while (status == 0 &&
78*fcf3ce44SJohn Forte 	    time_to_exit == B_FALSE &&
79*fcf3ce44SJohn Forte 	    isns_rcv_pdu(conn->so, &pdu, &pdu_sz, ISNS_RCV_TIMEOUT) > 0) {
80*fcf3ce44SJohn Forte 		uint16_t flags = pdu->flags;
81*fcf3ce44SJohn Forte 		if (ISNS_MSG_RECEIVED_ENABLED()) {
82*fcf3ce44SJohn Forte 			char buf[INET6_ADDRSTRLEN];
83*fcf3ce44SJohn Forte 			struct sockaddr_storage *ssp = &conn->ss;
84*fcf3ce44SJohn Forte 			struct sockaddr_in *sinp = (struct sockaddr_in *)ssp;
85*fcf3ce44SJohn Forte 			if (ssp->ss_family == AF_INET) {
86*fcf3ce44SJohn Forte 				(void) inet_ntop(AF_INET,
87*fcf3ce44SJohn Forte 				    (void *)&(sinp->sin_addr),
88*fcf3ce44SJohn Forte 				    buf, sizeof (buf));
89*fcf3ce44SJohn Forte 			} else {
90*fcf3ce44SJohn Forte 				(void) inet_ntop(AF_INET6,
91*fcf3ce44SJohn Forte 				    (void *)&(sinp->sin_addr),
92*fcf3ce44SJohn Forte 				    buf, sizeof (buf));
93*fcf3ce44SJohn Forte 			}
94*fcf3ce44SJohn Forte 			ISNS_MSG_RECEIVED((uintptr_t)buf);
95*fcf3ce44SJohn Forte 		}
96*fcf3ce44SJohn Forte 
97*fcf3ce44SJohn Forte 		if ((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) {
98*fcf3ce44SJohn Forte 			if (combined_pdu != NULL || pdu->seq != 0) {
99*fcf3ce44SJohn Forte 				goto conn_done;
100*fcf3ce44SJohn Forte 			}
101*fcf3ce44SJohn Forte 			combined_pdu = pdu;
102*fcf3ce44SJohn Forte 			pdu = NULL;
103*fcf3ce44SJohn Forte 		} else {
104*fcf3ce44SJohn Forte 			if (combined_pdu == NULL ||
105*fcf3ce44SJohn Forte 			    combined_pdu->func_id != pdu->func_id ||
106*fcf3ce44SJohn Forte 			    combined_pdu->xid != pdu->xid ||
107*fcf3ce44SJohn Forte 			    (combined_pdu->seq + 1) != pdu->seq) {
108*fcf3ce44SJohn Forte 				/* expect the first pdu, the same tranx id */
109*fcf3ce44SJohn Forte 				/* and the next sequence id */
110*fcf3ce44SJohn Forte 				goto conn_done;
111*fcf3ce44SJohn Forte 			}
112*fcf3ce44SJohn Forte 			new_combined_pdu = (isns_pdu_t *)malloc(
113*fcf3ce44SJohn Forte 			    ISNSP_HEADER_SIZE +
114*fcf3ce44SJohn Forte 			    combined_pdu->payload_len +
115*fcf3ce44SJohn Forte 			    pdu->payload_len);
116*fcf3ce44SJohn Forte 			if (new_combined_pdu == NULL) {
117*fcf3ce44SJohn Forte 				goto conn_done;
118*fcf3ce44SJohn Forte 			}
119*fcf3ce44SJohn Forte 			(void) memcpy((void *)new_combined_pdu,
120*fcf3ce44SJohn Forte 			    (void *)combined_pdu,
121*fcf3ce44SJohn Forte 			    ISNSP_HEADER_SIZE + combined_pdu->payload_len);
122*fcf3ce44SJohn Forte 			payload_ptr = new_combined_pdu->payload +
123*fcf3ce44SJohn Forte 			    combined_pdu->payload_len;
124*fcf3ce44SJohn Forte 			(void) memcpy((void *)payload_ptr,
125*fcf3ce44SJohn Forte 			    (void *)pdu->payload,
126*fcf3ce44SJohn Forte 			    pdu->payload_len);
127*fcf3ce44SJohn Forte 			new_combined_pdu->seq = pdu->seq;
128*fcf3ce44SJohn Forte 			free(combined_pdu);
129*fcf3ce44SJohn Forte 			combined_pdu = new_combined_pdu;
130*fcf3ce44SJohn Forte 			free(pdu);
131*fcf3ce44SJohn Forte 			pdu = NULL;
132*fcf3ce44SJohn Forte 		}
133*fcf3ce44SJohn Forte 		if ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU) {
134*fcf3ce44SJohn Forte #ifdef DEBUG
135*fcf3ce44SJohn Forte 			time_t t;
136*fcf3ce44SJohn Forte 			clock_t c;
137*fcf3ce44SJohn Forte 
138*fcf3ce44SJohn Forte 			dump_pdu1(combined_pdu);
139*fcf3ce44SJohn Forte 
140*fcf3ce44SJohn Forte 			if (verbose_tc != 0) {
141*fcf3ce44SJohn Forte 				t = time(NULL);
142*fcf3ce44SJohn Forte 				c = clock();
143*fcf3ce44SJohn Forte 			}
144*fcf3ce44SJohn Forte #endif
145*fcf3ce44SJohn Forte 
146*fcf3ce44SJohn Forte 			conn->in_packet.pdu = combined_pdu;
147*fcf3ce44SJohn Forte 			conn->out_packet.pl = 0;
148*fcf3ce44SJohn Forte 			conn->ec = 0;
149*fcf3ce44SJohn Forte 
150*fcf3ce44SJohn Forte 			if (packet_split_verify(conn) == 0) {
151*fcf3ce44SJohn Forte 				(void) cache_lock(conn->lock);
152*fcf3ce44SJohn Forte 				status = conn->handler(conn);
153*fcf3ce44SJohn Forte 				conn->ec = cache_unlock(conn->lock, conn->ec);
154*fcf3ce44SJohn Forte 			}
155*fcf3ce44SJohn Forte 
156*fcf3ce44SJohn Forte 			switch (status) {
157*fcf3ce44SJohn Forte 			case -1:
158*fcf3ce44SJohn Forte 				/* error */
159*fcf3ce44SJohn Forte 				break;
160*fcf3ce44SJohn Forte 			case 0:
161*fcf3ce44SJohn Forte 				status = isns_response(conn);
162*fcf3ce44SJohn Forte 
163*fcf3ce44SJohn Forte 				isnslog(LOG_DEBUG, "isns_connection",
164*fcf3ce44SJohn Forte 				    "Response status: %d.", status);
165*fcf3ce44SJohn Forte 				if (ISNS_MSG_RESPONDED_ENABLED()) {
166*fcf3ce44SJohn Forte 					char buf[INET6_ADDRSTRLEN];
167*fcf3ce44SJohn Forte 					struct sockaddr_storage *ssp =
168*fcf3ce44SJohn Forte 					    &conn->ss;
169*fcf3ce44SJohn Forte 					struct sockaddr_in *sinp =
170*fcf3ce44SJohn Forte 					    (struct sockaddr_in *)ssp;
171*fcf3ce44SJohn Forte 					if (ssp->ss_family == AF_INET) {
172*fcf3ce44SJohn Forte 						(void) inet_ntop(AF_INET,
173*fcf3ce44SJohn Forte 						    (void *)&(sinp->sin_addr),
174*fcf3ce44SJohn Forte 						    buf, sizeof (buf));
175*fcf3ce44SJohn Forte 					} else {
176*fcf3ce44SJohn Forte 						(void) inet_ntop(AF_INET6,
177*fcf3ce44SJohn Forte 						    (void *)&(sinp->sin_addr),
178*fcf3ce44SJohn Forte 						    buf, sizeof (buf));
179*fcf3ce44SJohn Forte 					}
180*fcf3ce44SJohn Forte 					ISNS_MSG_RESPONDED((uintptr_t)buf);
181*fcf3ce44SJohn Forte 				}
182*fcf3ce44SJohn Forte 				break;
183*fcf3ce44SJohn Forte 			default:
184*fcf3ce44SJohn Forte 				/* no need to send response message */
185*fcf3ce44SJohn Forte 				status = 0;
186*fcf3ce44SJohn Forte 				break;
187*fcf3ce44SJohn Forte 			}
188*fcf3ce44SJohn Forte 
189*fcf3ce44SJohn Forte #ifdef DEBUG
190*fcf3ce44SJohn Forte 			if (verbose_tc != 0) {
191*fcf3ce44SJohn Forte 				t = time(NULL) - t;
192*fcf3ce44SJohn Forte 				c = clock() - c;
193*fcf3ce44SJohn Forte 				printf("time %d clock %.4lf -msg response\n",
194*fcf3ce44SJohn Forte 				    t, c / (double)CLOCKS_PER_SEC);
195*fcf3ce44SJohn Forte 			}
196*fcf3ce44SJohn Forte #endif
197*fcf3ce44SJohn Forte 			free(combined_pdu);
198*fcf3ce44SJohn Forte 			combined_pdu = NULL;
199*fcf3ce44SJohn Forte 		}
200*fcf3ce44SJohn Forte 	}
201*fcf3ce44SJohn Forte 
202*fcf3ce44SJohn Forte conn_done:
203*fcf3ce44SJohn Forte 	if (pdu != NULL) {
204*fcf3ce44SJohn Forte 		free(pdu);
205*fcf3ce44SJohn Forte 	}
206*fcf3ce44SJohn Forte 	if (combined_pdu != NULL) {
207*fcf3ce44SJohn Forte 		free(combined_pdu);
208*fcf3ce44SJohn Forte 	}
209*fcf3ce44SJohn Forte 	(void) close(conn->so);
210*fcf3ce44SJohn Forte 	(void) free(conn->out_packet.pdu);
211*fcf3ce44SJohn Forte 	(void) free(conn);
212*fcf3ce44SJohn Forte 
213*fcf3ce44SJohn Forte 	/* decrease the thread ref count */
214*fcf3ce44SJohn Forte 	dec_thr_count();
215*fcf3ce44SJohn Forte 
216*fcf3ce44SJohn Forte 	return (NULL);
217*fcf3ce44SJohn Forte }
218*fcf3ce44SJohn Forte 
219*fcf3ce44SJohn Forte /* the iSNS server port watcher */
220*fcf3ce44SJohn Forte 
221*fcf3ce44SJohn Forte void *
isns_port_watcher(void * arg)222*fcf3ce44SJohn Forte isns_port_watcher(
223*fcf3ce44SJohn Forte 	/* LINTED E_FUNC_ARG_UNUSED */
224*fcf3ce44SJohn Forte 	void *arg
225*fcf3ce44SJohn Forte )
226*fcf3ce44SJohn Forte {
227*fcf3ce44SJohn Forte 	int s, f;
228*fcf3ce44SJohn Forte 	int opt = 1;
229*fcf3ce44SJohn Forte 	struct sockaddr_in sin;
230*fcf3ce44SJohn Forte 	struct sockaddr_in *sinp;
231*fcf3ce44SJohn Forte 	struct sockaddr_storage *ssp;
232*fcf3ce44SJohn Forte 	socklen_t sslen;
233*fcf3ce44SJohn Forte 	char buf[INET6_ADDRSTRLEN];
234*fcf3ce44SJohn Forte 	pthread_t tid;
235*fcf3ce44SJohn Forte 	struct pollfd fds;
236*fcf3ce44SJohn Forte 	int poll_ret;
237*fcf3ce44SJohn Forte 
238*fcf3ce44SJohn Forte 	conn_arg_t *conn;
239*fcf3ce44SJohn Forte 
240*fcf3ce44SJohn Forte 	if ((s = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
241*fcf3ce44SJohn Forte 		/* IPv4 */
242*fcf3ce44SJohn Forte 		isnslog(LOG_DEBUG, "isns_port_watcher", "IPv4 socket created.");
243*fcf3ce44SJohn Forte 		(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&opt,
244*fcf3ce44SJohn Forte 		    sizeof (opt));
245*fcf3ce44SJohn Forte 
246*fcf3ce44SJohn Forte 		sin.sin_family		= AF_INET;
247*fcf3ce44SJohn Forte 		sin.sin_port		= htons(ISNS_DEFAULT_SERVER_PORT);
248*fcf3ce44SJohn Forte 		sin.sin_addr.s_addr	= htonl(INADDR_ANY);
249*fcf3ce44SJohn Forte 
250*fcf3ce44SJohn Forte 		if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
251*fcf3ce44SJohn Forte 			isnslog(LOG_DEBUG, "isns_port_watcher",
252*fcf3ce44SJohn Forte 			    "binding on server port failed: %%m");
253*fcf3ce44SJohn Forte 			goto watch_failed;
254*fcf3ce44SJohn Forte 		}
255*fcf3ce44SJohn Forte 		isnslog(LOG_DEBUG, "isns_port_watcher",
256*fcf3ce44SJohn Forte 		    "successful binding on server port.");
257*fcf3ce44SJohn Forte 	} else {
258*fcf3ce44SJohn Forte 		isnslog(LOG_DEBUG, "isns_port_watcher",
259*fcf3ce44SJohn Forte 		    "cannot create socket: %%m.");
260*fcf3ce44SJohn Forte 		goto watch_failed;
261*fcf3ce44SJohn Forte 	}
262*fcf3ce44SJohn Forte 
263*fcf3ce44SJohn Forte 	if (listen(s, 5) < 0) {
264*fcf3ce44SJohn Forte 		isnslog(LOG_DEBUG, "isns_port_watcher",
265*fcf3ce44SJohn Forte 		    "listening on server port failed: %%m.");
266*fcf3ce44SJohn Forte 		goto watch_failed;
267*fcf3ce44SJohn Forte 	}
268*fcf3ce44SJohn Forte 	isnslog(LOG_DEBUG, "isns_port_watcher", "listening on server port ok.");
269*fcf3ce44SJohn Forte 
270*fcf3ce44SJohn Forte 	fds.fd = s;
271*fcf3ce44SJohn Forte 	fds.events = (POLLIN | POLLRDNORM);
272*fcf3ce44SJohn Forte 	fds.revents = 0;
273*fcf3ce44SJohn Forte 
274*fcf3ce44SJohn Forte 	/* waiting for connections */
275*fcf3ce44SJohn Forte 	for (;;) {
276*fcf3ce44SJohn Forte 		if (time_to_exit) {
277*fcf3ce44SJohn Forte 			return (NULL);
278*fcf3ce44SJohn Forte 		}
279*fcf3ce44SJohn Forte 
280*fcf3ce44SJohn Forte 		poll_ret = poll(&fds, 1, 1000);
281*fcf3ce44SJohn Forte 		if (poll_ret <= 0) {
282*fcf3ce44SJohn Forte 			continue;
283*fcf3ce44SJohn Forte 		}
284*fcf3ce44SJohn Forte 
285*fcf3ce44SJohn Forte 		/* allocate a connection argument */
286*fcf3ce44SJohn Forte 		conn = (conn_arg_t *)malloc(sizeof (conn_arg_t));
287*fcf3ce44SJohn Forte 		if (conn == NULL) {
288*fcf3ce44SJohn Forte 			isnslog(LOG_DEBUG, "isns_port_watcher",
289*fcf3ce44SJohn Forte 			    "malloc() failed.");
290*fcf3ce44SJohn Forte 			goto watch_failed;
291*fcf3ce44SJohn Forte 		}
292*fcf3ce44SJohn Forte 		ssp = &conn->ss;
293*fcf3ce44SJohn Forte 		sslen = sizeof (conn->ss);
294*fcf3ce44SJohn Forte 		f = accept(s, (struct sockaddr *)ssp, &sslen);
295*fcf3ce44SJohn Forte 		if (f < 0) {
296*fcf3ce44SJohn Forte 			isnslog(LOG_DEBUG, "isns_port_watcher",
297*fcf3ce44SJohn Forte 			    "accepting connection failed: %%m.");
298*fcf3ce44SJohn Forte 			goto watch_failed;
299*fcf3ce44SJohn Forte 		}
300*fcf3ce44SJohn Forte 		sinp = (struct sockaddr_in *)ssp;
301*fcf3ce44SJohn Forte 		if (ssp->ss_family == AF_INET) {
302*fcf3ce44SJohn Forte 			(void) inet_ntop(AF_INET, (void *)&(sinp->sin_addr),
303*fcf3ce44SJohn Forte 			    buf, sizeof (buf));
304*fcf3ce44SJohn Forte 		} else {
305*fcf3ce44SJohn Forte 			(void) inet_ntop(AF_INET6, (void *)&(sinp->sin_addr),
306*fcf3ce44SJohn Forte 			    buf, sizeof (buf));
307*fcf3ce44SJohn Forte 		}
308*fcf3ce44SJohn Forte 		isnslog(LOG_DEBUG, "isns_port_watcher",
309*fcf3ce44SJohn Forte 		    "connection from %s:%d.", buf,
310*fcf3ce44SJohn Forte 		    sinp->sin_port);
311*fcf3ce44SJohn Forte 
312*fcf3ce44SJohn Forte 		if (ISNS_CONNECTION_ACCEPTED_ENABLED()) {
313*fcf3ce44SJohn Forte 			ISNS_CONNECTION_ACCEPTED((uintptr_t)buf);
314*fcf3ce44SJohn Forte 		}
315*fcf3ce44SJohn Forte 
316*fcf3ce44SJohn Forte 		conn->so = f;
317*fcf3ce44SJohn Forte 		/* create an isns connection */
318*fcf3ce44SJohn Forte 		if (pthread_create(&tid, NULL,
319*fcf3ce44SJohn Forte 		    isns_connection, (void *)conn) != 0) {
320*fcf3ce44SJohn Forte 			(void) close(f);
321*fcf3ce44SJohn Forte 			(void) free(conn);
322*fcf3ce44SJohn Forte 			isnslog(LOG_DEBUG, "isns_port_watcher",
323*fcf3ce44SJohn Forte 			    "pthread_create() failed.");
324*fcf3ce44SJohn Forte 		} else {
325*fcf3ce44SJohn Forte 			/* increase the thread ref count */
326*fcf3ce44SJohn Forte 			inc_thr_count();
327*fcf3ce44SJohn Forte 		}
328*fcf3ce44SJohn Forte 	}
329*fcf3ce44SJohn Forte 
330*fcf3ce44SJohn Forte watch_failed:
331*fcf3ce44SJohn Forte 	shutdown_server();
332*fcf3ce44SJohn Forte 	return (NULL);
333*fcf3ce44SJohn Forte }
334*fcf3ce44SJohn Forte 
335*fcf3ce44SJohn Forte static uint16_t xid = 0;
336*fcf3ce44SJohn Forte static pthread_mutex_t xid_mtx = PTHREAD_MUTEX_INITIALIZER;
337*fcf3ce44SJohn Forte uint16_t
get_server_xid()338*fcf3ce44SJohn Forte get_server_xid(
339*fcf3ce44SJohn Forte )
340*fcf3ce44SJohn Forte {
341*fcf3ce44SJohn Forte 	uint16_t tmp;
342*fcf3ce44SJohn Forte 
343*fcf3ce44SJohn Forte 	(void) pthread_mutex_lock(&xid_mtx);
344*fcf3ce44SJohn Forte 	tmp = ++ xid;
345*fcf3ce44SJohn Forte 	(void) pthread_mutex_unlock(&xid_mtx);
346*fcf3ce44SJohn Forte 
347*fcf3ce44SJohn Forte 	return (tmp);
348*fcf3ce44SJohn Forte }
349