1943efbcgm/*
2943efbcgm * CDDL HEADER START
3943efbcgm *
4943efbcgm * The contents of this file are subject to the terms of the
5943efbcgm * Common Development and Distribution License (the "License").
6943efbcgm * You may not use this file except in compliance with the License.
7943efbcgm *
8943efbcgm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9943efbcgm * or http://www.opensolaris.org/os/licensing.
10943efbcgm * See the License for the specific language governing permissions
11943efbcgm * and limitations under the License.
12943efbcgm *
13943efbcgm * When distributing Covered Code, include this CDDL HEADER in each
14943efbcgm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15943efbcgm * If applicable, add the following below this CDDL HEADER, with the
16943efbcgm * fields enclosed by brackets "[]" replaced with your own identifying
17943efbcgm * information: Portions Copyright [yyyy] [name of copyright owner]
18943efbcgm *
19943efbcgm * CDDL HEADER END
20943efbcgm */
21943efbcgm
22943efbcgm/*
23943efbcgm * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24943efbcgm * Use is subject to license terms.
25943efbcgm */
26943efbcgm
27943efbcgm#pragma ident	"%Z%%M%	%I%	%E% SMI"
28943efbcgm
29943efbcgm#include <stdio.h>
30943efbcgm#include <string.h>
31943efbcgm#include <strings.h>
32943efbcgm#include <stdlib.h>
33943efbcgm#include <assert.h>
34943efbcgm#include <ctype.h>
35943efbcgm#include <errno.h>
36943efbcgm#include <sip.h>
37943efbcgm
38943efbcgm#include "sip_msg.h"
39943efbcgm#include "sip_miscdefs.h"
40943efbcgm#include "sip_xaction.h"
41943efbcgm#include "sip_dialog.h"
42943efbcgm
43943efbcgm#define	TIME_BUF_SIZE	50
44943efbcgm
45943efbcgm/*
46943efbcgm * Contains API's which enable/disable transaction or dialog logging,
47943efbcgm * API's which records/measures SIP Traffic.
48943efbcgm */
49943efbcgm/*
50943efbcgm * Needed for measuring SIP traffic counters.
51943efbcgm */
52943efbcgmsip_traffic_counters_t	sip_counters;
53943efbcgm
54943efbcgm/*
55943efbcgm * Needed for dialog/transaction logging.
56943efbcgm */
57943efbcgmsip_logfile_t trans_log;
58943efbcgmsip_logfile_t dialog_log;
59943efbcgm
60943efbcgm/*
61943efbcgm * This function increments the appropriate inbound/outbound counters for
62943efbcgm * SIP requests/responses.
63943efbcgm */
64943efbcgmvoid
65943efbcgmsip_measure_traffic(boolean_t is_request, sip_method_t method, int resp_code,
66943efbcgm    boolean_t outbound, int msg_size)
67943efbcgm{
68943efbcgm#ifdef	__solaris__
69943efbcgm	assert(mutex_held(&sip_counters.sip_counter_mutex));
70943efbcgm#endif
71943efbcgm	if (outbound)
72943efbcgm		sip_counters.sip_total_bytes_sent += msg_size;
73943efbcgm	else
74943efbcgm		sip_counters.sip_total_bytes_rcvd += msg_size;
75943efbcgm
76943efbcgm	if (is_request) {
77943efbcgm		if (outbound)
78943efbcgm			++sip_counters.sip_total_req_sent;
79943efbcgm		else
80943efbcgm			++sip_counters.sip_total_req_rcvd;
81943efbcgm		switch (method) {
82943efbcgm			case INVITE:
83943efbcgm				if (outbound)
84943efbcgm					++sip_counters.sip_invite_req_sent;
85943efbcgm				else
86943efbcgm					++sip_counters.sip_invite_req_rcvd;
87943efbcgm				break;
88943efbcgm			case ACK:
89943efbcgm				if (outbound)
90943efbcgm					++sip_counters.sip_ack_req_sent;
91943efbcgm				else
92943efbcgm					++sip_counters.sip_ack_req_rcvd;
93943efbcgm				break;
94943efbcgm			case OPTIONS:
95943efbcgm				if (outbound)
96943efbcgm					++sip_counters.sip_options_req_sent;
97943efbcgm				else
98943efbcgm					++sip_counters.sip_options_req_rcvd;
99943efbcgm				break;
100943efbcgm			case BYE:
101943efbcgm				if (outbound)
102943efbcgm					++sip_counters.sip_bye_req_sent;
103943efbcgm				else
104943efbcgm					++sip_counters.sip_bye_req_rcvd;
105943efbcgm				break;
106943efbcgm			case CANCEL:
107943efbcgm				if (outbound)
108943efbcgm					++sip_counters.sip_cancel_req_sent;
109943efbcgm				else
110943efbcgm					++sip_counters.sip_cancel_req_rcvd;
111943efbcgm				break;
112943efbcgm			case REGISTER:
113943efbcgm				if (outbound)
114943efbcgm					++sip_counters.sip_register_req_sent;
115943efbcgm				else
116943efbcgm					++sip_counters.sip_register_req_rcvd;
117943efbcgm				break;
118943efbcgm			case REFER:
119943efbcgm				if (outbound)
120943efbcgm					++sip_counters.sip_refer_req_sent;
121943efbcgm				else
122943efbcgm					++sip_counters.sip_refer_req_rcvd;
123943efbcgm				break;
124943efbcgm			case INFO:
125943efbcgm				if (outbound)
126943efbcgm					++sip_counters.sip_info_req_sent;
127943efbcgm				else
128943efbcgm					++sip_counters.sip_info_req_rcvd;
129943efbcgm				break;
130943efbcgm			case SUBSCRIBE:
131943efbcgm				if (outbound)
132943efbcgm					++sip_counters.sip_subscribe_req_sent;
133943efbcgm				else
134943efbcgm					++sip_counters.sip_subscribe_req_rcvd;
135943efbcgm				break;
136943efbcgm			case NOTIFY:
137943efbcgm				if (outbound)
138943efbcgm					++sip_counters.sip_notify_req_sent;
139943efbcgm				else
140943efbcgm					++sip_counters.sip_notify_req_rcvd;
141943efbcgm				break;
142943efbcgm			case PRACK:
143943efbcgm				if (outbound)
144943efbcgm					++sip_counters.sip_prack_req_sent;
145943efbcgm				else
146943efbcgm					++sip_counters.sip_prack_req_rcvd;
147943efbcgm				break;
148943efbcgm			default:
149943efbcgm				break;
150943efbcgm		}
151943efbcgm	} else {
152943efbcgm		if (outbound)
153943efbcgm			++sip_counters.sip_total_resp_sent;
154943efbcgm		else
155943efbcgm			++sip_counters.sip_total_resp_rcvd;
156943efbcgm		if (SIP_PROVISIONAL_RESP(resp_code)) {
157943efbcgm			if (outbound)
158943efbcgm				++sip_counters.sip_1xx_resp_sent;
159943efbcgm			else
160943efbcgm				++sip_counters.sip_1xx_resp_rcvd;
161943efbcgm		} else if (SIP_OK_RESP(resp_code)) {
162943efbcgm			if (outbound)
163943efbcgm				++sip_counters.sip_2xx_resp_sent;
164943efbcgm			else
165943efbcgm				++sip_counters.sip_2xx_resp_rcvd;
166943efbcgm		} else if (SIP_REDIRECT_RESP(resp_code)) {
167943efbcgm			if (outbound)
168943efbcgm				++sip_counters.sip_3xx_resp_sent;
169943efbcgm			else
170943efbcgm				++sip_counters.sip_3xx_resp_rcvd;
171943efbcgm		} else if (SIP_REQFAIL_RESP(resp_code)) {
172943efbcgm			if (outbound)
173943efbcgm				++sip_counters.sip_4xx_resp_sent;
174943efbcgm			else
175943efbcgm				++sip_counters.sip_4xx_resp_rcvd;
176943efbcgm		} else if (SIP_SRVFAIL_RESP(resp_code)) {
177943efbcgm			if (outbound)
178943efbcgm				++sip_counters.sip_5xx_resp_sent;
179943efbcgm			else
180943efbcgm				++sip_counters.sip_5xx_resp_rcvd;
181943efbcgm		} else if (SIP_GLOBFAIL_RESP(resp_code)) {
182943efbcgm			if (outbound)
183943efbcgm				++sip_counters.sip_6xx_resp_sent;
184943efbcgm			else
185943efbcgm				++sip_counters.sip_6xx_resp_rcvd;
186943efbcgm		}
187943efbcgm	}
188943efbcgm}
189943efbcgm
190943efbcgm/*
191943efbcgm * Enables Transaction logging. The flags argument controls the detail
192943efbcgm * of logging.
193943efbcgm */
194943efbcgmint
195943efbcgmsip_enable_trans_logging(FILE *logfile, int flags)
196943efbcgm{
197943efbcgm	if (logfile == NULL || flags != SIP_DETAIL_LOGGING)
198943efbcgm		return (EINVAL);
199943efbcgm
200943efbcgm	(void) pthread_mutex_lock(&trans_log.sip_logfile_mutex);
201943efbcgm	if (!trans_log.sip_logging_enabled) {
202943efbcgm		trans_log.sip_logfile = logfile;
203943efbcgm		trans_log.sip_logging_enabled = B_TRUE;
204943efbcgm	}
205943efbcgm	(void) pthread_mutex_unlock(&trans_log.sip_logfile_mutex);
206943efbcgm	return (0);
207943efbcgm}
208943efbcgm
209943efbcgm
210943efbcgm/*
211943efbcgm * Enables dialog logging. The flags argument controls the detail
212943efbcgm * of logging.
213943efbcgm */
214943efbcgmint
215943efbcgmsip_enable_dialog_logging(FILE *logfile, int flags)
216943efbcgm{
217943efbcgm	if (logfile == NULL || flags != SIP_DETAIL_LOGGING)
218943efbcgm		return (EINVAL);
219943efbcgm
220943efbcgm	(void) pthread_mutex_lock(&dialog_log.sip_logfile_mutex);
221943efbcgm	if (!dialog_log.sip_logging_enabled) {
222943efbcgm		dialog_log.sip_logfile = logfile;
223943efbcgm		dialog_log.sip_logging_enabled = B_TRUE;
224943efbcgm	}
225943efbcgm	(void) pthread_mutex_unlock(&dialog_log.sip_logfile_mutex);
226943efbcgm	return (0);
227943efbcgm}
228943efbcgm
229943efbcgmvoid
230943efbcgmsip_disable_trans_logging()
231943efbcgm{
232943efbcgm	(void) pthread_mutex_lock(&trans_log.sip_logfile_mutex);
233943efbcgm	if (trans_log.sip_logging_enabled)
234943efbcgm		trans_log.sip_logging_enabled = B_FALSE;
235943efbcgm	(void) pthread_mutex_unlock(&trans_log.sip_logfile_mutex);
236943efbcgm}
237943efbcgm
238943efbcgmvoid
239943efbcgmsip_disable_dialog_logging()
240943efbcgm{
241943efbcgm	(void) pthread_mutex_lock(&dialog_log.sip_logfile_mutex);
242943efbcgm	if (dialog_log.sip_logging_enabled)
243943efbcgm		dialog_log.sip_logging_enabled = B_FALSE;
244943efbcgm	(void) pthread_mutex_unlock(&dialog_log.sip_logfile_mutex);
245943efbcgm}
246943efbcgm
247943efbcgmstatic void
248943efbcgmsip_print_digest(uint16_t *digest, int len, FILE *fp)
249943efbcgm{
250943efbcgm	int	cnt;
251943efbcgm
252943efbcgm	for (cnt = 0; cnt < len; cnt++)
253943efbcgm		(void) fprintf(fp, "%u ", digest[cnt]);
254943efbcgm	(void) fprintf(fp, "\n\n");
255943efbcgm}
256943efbcgm
257943efbcgm/*
258943efbcgm * Logs all the messages exchanged within a transaction to the transaction
259943efbcgm * log file. Logged messages are then freed.
260943efbcgm */
261943efbcgmstatic void
262943efbcgmsip_write_xaction_to_log(void *obj)
263943efbcgm{
264943efbcgm	sip_xaction_t	*trans = (sip_xaction_t *)obj;
265943efbcgm	sip_log_t	*sip_log;
266943efbcgm	int		count;
267943efbcgm	sip_msg_chain_t	*msg_chain;
268943efbcgm	sip_msg_chain_t	*nmsg_chain;
269943efbcgm	char		timebuf[TIME_BUF_SIZE];
270943efbcgm	struct tm	tms;
271943efbcgm	FILE		*sip_trans_logfile = trans_log.sip_logfile;
272943efbcgm
273943efbcgm	assert(trans != NULL && sip_trans_logfile != NULL);
274943efbcgm	(void) fprintf(sip_trans_logfile, "************* Begin Transaction"
275943efbcgm	    " *************\n");
276943efbcgm	(void) fprintf(sip_trans_logfile, "Branchid\t\t: %s\n",
277943efbcgm	    trans->sip_xaction_branch_id);
278943efbcgm	(void) fprintf(sip_trans_logfile, "Digest\t\t\t: ");
279943efbcgm	sip_print_digest(trans->sip_xaction_hash_digest, 8, sip_trans_logfile);
280943efbcgm	(void) fprintf(sip_trans_logfile, "-----------------------------\n");
281943efbcgm	for (count = 0; count <= SIP_SRV_NONINV_TERMINATED; count++) {
282943efbcgm		sip_log = &trans->sip_xaction_log[count];
283943efbcgm		if (sip_log->sip_msgcnt == 0)
284943efbcgm			continue;
285943efbcgm		(void) fprintf(sip_trans_logfile, "Transaction State\t: %s\n\n",
286943efbcgm		    sip_get_xaction_state(count));
287943efbcgm		msg_chain = sip_log->sip_msgs;
288943efbcgm		while (msg_chain != NULL) {
289943efbcgm			nmsg_chain = msg_chain->next;
290943efbcgm			(void) strftime(timebuf, sizeof (timebuf), NULL,
291943efbcgm			    localtime_r(&msg_chain->msg_timestamp, &tms));
292943efbcgm			(void) fprintf(sip_trans_logfile, "%s| Message -"
293943efbcgm			    " %d\n%s", timebuf, msg_chain->msg_seq, msg_chain->
294943efbcgm			    sip_msg);
295943efbcgm			free(msg_chain->sip_msg);
296943efbcgm			free(msg_chain);
297943efbcgm			--sip_log->sip_msgcnt;
298943efbcgm			msg_chain = nmsg_chain;
299943efbcgm		}
300943efbcgm		(void) fprintf(sip_trans_logfile,
301943efbcgm		    "-----------------------------\n");
302943efbcgm		(trans->sip_xaction_log[count]).sip_msgs = NULL;
303943efbcgm	}
304943efbcgm	(void) fprintf(sip_trans_logfile, "************* End Transaction "
305943efbcgm	    "*************\n");
306943efbcgm	(void) fflush(sip_trans_logfile);
307943efbcgm}
308943efbcgm
309943efbcgm/*
310943efbcgm * Logs all the messages exchanged within a dialog to the dialog
311943efbcgm * log file. Logged messages are then freed.
312943efbcgm */
313943efbcgmstatic void
314943efbcgmsip_write_dlg_to_log(void *obj)
315943efbcgm{
316943efbcgm	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
317943efbcgm	sip_log_t	*sip_log;
318943efbcgm	int		count;
319943efbcgm	sip_msg_chain_t	*msg_chain;
320943efbcgm	sip_msg_chain_t	*nmsg_chain;
321943efbcgm	char		timebuf[TIME_BUF_SIZE];
322943efbcgm	struct tm	tms;
323943efbcgm	FILE		*sip_dialog_logfile = dialog_log.sip_logfile;
324943efbcgm
325943efbcgm	assert(dialog != NULL && sip_dialog_logfile != NULL);
326943efbcgm
327943efbcgm	(void) fprintf(sip_dialog_logfile, "************* Begin Dialog "
328943efbcgm	    "*************\n");
329943efbcgm	(void) fprintf(sip_dialog_logfile, "Digest\t\t\t: ");
330943efbcgm	sip_print_digest(dialog->sip_dlg_id, 8, sip_dialog_logfile);
331943efbcgm	(void) fprintf(sip_dialog_logfile, "-----------------------------\n");
332943efbcgm	for (count = 0; count <= SIP_DLG_DESTROYED; count++) {
333943efbcgm		sip_log = &dialog->sip_dlg_log[count];
334943efbcgm		if (sip_log->sip_msgcnt == 0)
335943efbcgm			continue;
336943efbcgm		(void) fprintf(sip_dialog_logfile, "Dialog State\t\t: %s\n\n",
337943efbcgm		    sip_get_dialog_state_str(count));
338943efbcgm		msg_chain = sip_log->sip_msgs;
339943efbcgm		while (msg_chain != NULL) {
340943efbcgm			nmsg_chain = msg_chain->next;
341943efbcgm			(void) strftime(timebuf, sizeof (timebuf), NULL,
342943efbcgm			    localtime_r(&msg_chain->msg_timestamp, &tms));
343943efbcgm			(void) fprintf(sip_dialog_logfile, "%s| Message -"
344943efbcgm			    " %d\n%s", timebuf, msg_chain->msg_seq, msg_chain->
345943efbcgm			    sip_msg);
346943efbcgm			free(msg_chain->sip_msg);
347943efbcgm			free(msg_chain);
348943efbcgm			--sip_log->sip_msgcnt;
349943efbcgm			msg_chain = nmsg_chain;
350943efbcgm		}
351943efbcgm		(void) fprintf(sip_dialog_logfile,
352943efbcgm		    "-----------------------------\n");
353943efbcgm		(dialog->sip_dlg_log[count]).sip_msgs = NULL;
354943efbcgm	}
355943efbcgm	(void) fprintf(sip_dialog_logfile, "************* End Dialog "
356943efbcgm	    "*************\n");
357943efbcgm	(void) fflush(sip_dialog_logfile);
358943efbcgm}
359943efbcgm
360943efbcgm/*
361943efbcgm * Calls the appropriate function to log transaction or dialog messages.
362943efbcgm * If this function is called because of assertion failure, then the file and
363943efbcgm * line where the assertion failed is logged to the log file.
364943efbcgm */
365943efbcgmvoid
366943efbcgmsip_write_to_log(void *obj, int type, char *file, int line)
367943efbcgm{
368943efbcgm	if (type & SIP_TRANSACTION_LOG) {
369943efbcgm		(void) pthread_mutex_lock(&trans_log.sip_logfile_mutex);
370943efbcgm		if (trans_log.sip_logging_enabled) {
371943efbcgm			if (type & SIP_ASSERT_ERROR) {
372943efbcgm				(void) fprintf(trans_log.sip_logfile,
373943efbcgm				    "Assertion Failure at %s:%d\n", file, line);
374943efbcgm			}
375943efbcgm			sip_write_xaction_to_log(obj);
376943efbcgm		}
377943efbcgm		(void) pthread_mutex_unlock(&trans_log.sip_logfile_mutex);
378943efbcgm	} else {
379943efbcgm		(void) pthread_mutex_lock(&dialog_log.sip_logfile_mutex);
380943efbcgm		if (dialog_log.sip_logging_enabled) {
381943efbcgm			if (type & SIP_ASSERT_ERROR) {
382943efbcgm				(void) fprintf(dialog_log.sip_logfile,
383943efbcgm				    "Assertion Failure at %s:%d\n", file, line);
384943efbcgm			}
385943efbcgm			sip_write_dlg_to_log(obj);
386943efbcgm		}
387943efbcgm		(void) pthread_mutex_unlock(&dialog_log.sip_logfile_mutex);
388943efbcgm	}
389943efbcgm}
390943efbcgm
391943efbcgm/*
392943efbcgm * This function records the messages that are exchanged within a dialog or
393943efbcgm * transaction. If logging is enabled the recorded messages are then dumped
394943efbcgm * to the log file just before deleting the transaction or dialog.
395943efbcgm */
396943efbcgmvoid
397943efbcgmsip_add_log(sip_log_t *sip_log, sip_msg_t sip_msg, int seq, int type)
398943efbcgm{
399943efbcgm	char			*msgstr;
400943efbcgm	sip_msg_chain_t		*new_msg;
401943efbcgm	sip_msg_chain_t		*msg_chain = sip_log->sip_msgs;
402943efbcgm
403943efbcgm	/*
404943efbcgm	 * No need to take any locks here. Caller of this function MUST
405943efbcgm	 * have already taken the transaction or dialog lock.
406943efbcgm	 */
407943efbcgm	if (((type == SIP_DIALOG_LOG) && !dialog_log.sip_logging_enabled) ||
408943efbcgm	    ((type == SIP_TRANSACTION_LOG) && !trans_log.sip_logging_enabled)) {
409943efbcgm		return;
410943efbcgm	}
411943efbcgm
412943efbcgm	new_msg = calloc(1, sizeof (sip_msg_chain_t));
413943efbcgm	if (new_msg == NULL)
414943efbcgm		return;
415943efbcgm
416943efbcgm	msgstr = sip_msg_to_str(sip_msg, NULL);
417943efbcgm	if (msgstr == NULL) {
418943efbcgm		free(new_msg);
419943efbcgm		return;
420943efbcgm	}
421943efbcgm
422943efbcgm	new_msg->sip_msg =  msgstr;
423943efbcgm	new_msg->msg_seq = seq;
424943efbcgm	new_msg->msg_timestamp = time(NULL);
425943efbcgm	new_msg->next = NULL;
426943efbcgm	if (sip_log->sip_msgcnt == 0) {
427943efbcgm		sip_log->sip_msgs = new_msg;
428943efbcgm	} else {
429943efbcgm		while (msg_chain->next != NULL)
430943efbcgm			msg_chain = msg_chain->next;
431943efbcgm		msg_chain->next = new_msg;
432943efbcgm	}
433943efbcgm	sip_log->sip_msgcnt++;
434943efbcgm}
435943efbcgm
436943efbcgm/*
437943efbcgm * Given a counter group and counter name within the group, returns the value
438943efbcgm * associated with the counter in 'cntval'.
439943efbcgm */
440943efbcgmint
441943efbcgmsip_get_counter_value(int group, int counter, void *cntval, size_t cntlen)
442943efbcgm{
443943efbcgm	if (group != SIP_TRAFFIC_COUNTERS || cntval == NULL)
444943efbcgm		return (EINVAL);
445943efbcgm	if ((counter == SIP_COUNTER_START_TIME || counter ==
446943efbcgm	    SIP_COUNTER_STOP_TIME) && (cntlen != sizeof (time_t))) {
447943efbcgm		return (EINVAL);
448943efbcgm	} else if (cntlen != sizeof (uint64_t)) {
449943efbcgm		return (EINVAL);
450943efbcgm	}
451943efbcgm
452943efbcgm	(void) pthread_mutex_lock(&sip_counters.sip_counter_mutex);
453943efbcgm	switch (counter) {
454943efbcgm		case SIP_TOTAL_BYTES_RCVD:
455943efbcgm			*(uint64_t *)cntval = sip_counters.sip_total_bytes_rcvd;
456943efbcgm			break;
457943efbcgm		case SIP_TOTAL_BYTES_SENT:
458943efbcgm			*(uint64_t *)cntval = sip_counters.sip_total_bytes_sent;
459943efbcgm			break;
460943efbcgm		case SIP_TOTAL_REQ_RCVD:
461943efbcgm			*(uint64_t *)cntval = sip_counters.sip_total_req_rcvd;
462943efbcgm			break;
463943efbcgm		case SIP_TOTAL_REQ_SENT:
464943efbcgm			*(uint64_t *)cntval = sip_counters.sip_total_req_sent;
465943efbcgm			break;
466943efbcgm		case SIP_TOTAL_RESP_RCVD:
467943efbcgm			*(uint64_t *)cntval = sip_counters.sip_total_resp_rcvd;
468943efbcgm			break;
469943efbcgm		case SIP_TOTAL_RESP_SENT:
470943efbcgm			*(uint64_t *)cntval = sip_counters.sip_total_resp_sent;
471943efbcgm			break;
472943efbcgm		case SIP_ACK_REQ_RCVD:
473943efbcgm			*(uint64_t *)cntval = sip_counters.sip_ack_req_rcvd;
474943efbcgm			break;
475943efbcgm		case SIP_ACK_REQ_SENT:
476943efbcgm			*(uint64_t *)cntval = sip_counters.sip_ack_req_sent;
477943efbcgm			break;
478943efbcgm		case SIP_BYE_REQ_RCVD:
479943efbcgm			*(uint64_t *)cntval = sip_counters.sip_bye_req_rcvd;
480943efbcgm			break;
481943efbcgm		case SIP_BYE_REQ_SENT:
482943efbcgm			*(uint64_t *)cntval = sip_counters.sip_bye_req_sent;
483943efbcgm			break;
484943efbcgm		case SIP_CANCEL_REQ_RCVD:
485943efbcgm			*(uint64_t *)cntval = sip_counters.sip_cancel_req_rcvd;
486943efbcgm			break;
487943efbcgm		case SIP_CANCEL_REQ_SENT:
488943efbcgm			*(uint64_t *)cntval = sip_counters.sip_cancel_req_sent;
489943efbcgm			break;
490943efbcgm		case SIP_INFO_REQ_RCVD:
491943efbcgm			*(uint64_t *)cntval = sip_counters.sip_info_req_rcvd;
492943efbcgm			break;
493943efbcgm		case SIP_INFO_REQ_SENT:
494943efbcgm			*(uint64_t *)cntval = sip_counters.sip_info_req_sent;
495943efbcgm			break;
496943efbcgm		case SIP_INVITE_REQ_RCVD:
497943efbcgm			*(uint64_t *)cntval = sip_counters.sip_invite_req_rcvd;
498943efbcgm			break;
499943efbcgm		case SIP_INVITE_REQ_SENT:
500943efbcgm			*(uint64_t *)cntval = sip_counters.sip_invite_req_sent;
501943efbcgm			break;
502943efbcgm		case SIP_NOTIFY_REQ_RCVD:
503943efbcgm			*(uint64_t *)cntval = sip_counters.sip_notify_req_rcvd;
504943efbcgm			break;
505943efbcgm		case SIP_NOTIFY_REQ_SENT:
506943efbcgm			*(uint64_t *)cntval = sip_counters.sip_notify_req_sent;
507943efbcgm			break;
508943efbcgm		case SIP_OPTIONS_REQ_RCVD:
509943efbcgm			*(uint64_t *)cntval = sip_counters.sip_options_req_rcvd;
510943efbcgm			break;
511943efbcgm		case SIP_OPTIONS_REQ_SENT:
512943efbcgm			*(uint64_t *)cntval = sip_counters.sip_options_req_sent;
513943efbcgm			break;
514943efbcgm		case SIP_PRACK_REQ_RCVD:
515943efbcgm			*(uint64_t *)cntval = sip_counters.sip_prack_req_rcvd;
516943efbcgm			break;
517943efbcgm		case SIP_PRACK_REQ_SENT:
518943efbcgm			*(uint64_t *)cntval = sip_counters.sip_prack_req_sent;
519943efbcgm			break;
520943efbcgm		case SIP_REFER_REQ_RCVD:
521943efbcgm			*(uint64_t *)cntval = sip_counters.sip_refer_req_rcvd;
522943efbcgm			break;
523943efbcgm		case SIP_REFER_REQ_SENT:
524943efbcgm			*(uint64_t *)cntval = sip_counters.sip_refer_req_sent;
525943efbcgm			break;
526943efbcgm		case SIP_REGISTER_REQ_RCVD:
527943efbcgm			*(uint64_t *)cntval = sip_counters.
528943efbcgm			    sip_register_req_rcvd;
529943efbcgm			break;
530943efbcgm		case SIP_REGISTER_REQ_SENT:
531943efbcgm			*(uint64_t *)cntval = sip_counters.
532943efbcgm			    sip_register_req_sent;
533943efbcgm			break;
534943efbcgm		case SIP_SUBSCRIBE_REQ_RCVD:
535943efbcgm			*(uint64_t *)cntval = sip_counters.
536943efbcgm			    sip_subscribe_req_rcvd;
537943efbcgm			break;
538943efbcgm		case SIP_SUBSCRIBE_REQ_SENT:
539943efbcgm			*(uint64_t *)cntval = sip_counters.
540943efbcgm			    sip_subscribe_req_sent;
541943efbcgm			break;
542943efbcgm		case SIP_UPDATE_REQ_RCVD:
543943efbcgm			*(uint64_t *)cntval = sip_counters.sip_update_req_rcvd;
544943efbcgm			break;
545943efbcgm		case SIP_UPDATE_REQ_SENT:
546943efbcgm			*(uint64_t *)cntval = sip_counters.sip_update_req_sent;
547943efbcgm			break;
548943efbcgm		case SIP_1XX_RESP_RCVD:
549943efbcgm			*(uint64_t *)cntval = sip_counters.sip_1xx_resp_rcvd;
550943efbcgm			break;
551943efbcgm		case SIP_1XX_RESP_SENT:
552943efbcgm			*(uint64_t *)cntval = sip_counters.sip_1xx_resp_sent;
553943efbcgm			break;
554943efbcgm		case SIP_2XX_RESP_RCVD:
555943efbcgm			*(uint64_t *)cntval = sip_counters.sip_2xx_resp_rcvd;
556943efbcgm			break;
557943efbcgm		case SIP_2XX_RESP_SENT:
558943efbcgm			*(uint64_t *)cntval = sip_counters.sip_2xx_resp_sent;
559943efbcgm			break;
560943efbcgm		case SIP_3XX_RESP_RCVD:
561943efbcgm			*(uint64_t *)cntval = sip_counters.sip_3xx_resp_rcvd;
562943efbcgm			break;
563943efbcgm		case SIP_3XX_RESP_SENT:
564943efbcgm			*(uint64_t *)cntval = sip_counters.sip_3xx_resp_sent;
565943efbcgm			break;
566943efbcgm		case SIP_4XX_RESP_RCVD:
567943efbcgm			*(uint64_t *)cntval = sip_counters.sip_4xx_resp_rcvd;
568943efbcgm			break;
569943efbcgm		case SIP_4XX_RESP_SENT:
570943efbcgm			*(uint64_t *)cntval = sip_counters.sip_4xx_resp_sent;
571943efbcgm			break;
572943efbcgm		case SIP_5XX_RESP_RCVD:
573943efbcgm			*(uint64_t *)cntval = sip_counters.sip_5xx_resp_rcvd;
574943efbcgm			break;
575943efbcgm		case SIP_5XX_RESP_SENT:
576943efbcgm			*(uint64_t *)cntval = sip_counters.sip_5xx_resp_sent;
577943efbcgm			break;
578943efbcgm		case SIP_6XX_RESP_RCVD:
579943efbcgm			*(uint64_t *)cntval = sip_counters.sip_6xx_resp_rcvd;
580943efbcgm			break;
581943efbcgm		case SIP_6xx_RESP_SENT:
582943efbcgm			*(uint64_t *)cntval = sip_counters.sip_6xx_resp_sent;
583943efbcgm			break;
584943efbcgm		case SIP_COUNTER_START_TIME:
585943efbcgm			*(time_t *)cntval = sip_counters.starttime;
586943efbcgm			break;
587943efbcgm		case SIP_COUNTER_STOP_TIME:
588943efbcgm			*(time_t *)cntval = sip_counters.stoptime;
589943efbcgm			break;
590943efbcgm		default:
591943efbcgm			(void) pthread_mutex_unlock(&sip_counters.
592943efbcgm			    sip_counter_mutex);
593943efbcgm			return (EINVAL);
594943efbcgm	}
595943efbcgm	(void) pthread_mutex_unlock(&sip_counters.sip_counter_mutex);
596943efbcgm	return (0);
597943efbcgm}
598943efbcgm
599943efbcgm/*
600943efbcgm * Enables the SIP performance/traffic counting. Also reset's the previous
601943efbcgm * counter values and starts counting afresh.
602943efbcgm */
603943efbcgmint
604943efbcgmsip_enable_counters(int group)
605943efbcgm{
606943efbcgm	if (group != SIP_TRAFFIC_COUNTERS)
607943efbcgm		return (EINVAL);
608943efbcgm	(void) pthread_mutex_lock(&sip_counters.sip_counter_mutex);
609943efbcgm	/* If it's not enabled, enable it and capture the start time */
610943efbcgm	if (!sip_counters.enabled) {
611943efbcgm		/* zero all the counters except for the mutex at the end */
612943efbcgm		(void) bzero(&sip_counters, sizeof (sip_traffic_counters_t) -
613943efbcgm		    sizeof (pthread_mutex_t));
614943efbcgm		sip_counters.enabled = B_TRUE;
615943efbcgm		sip_counters.starttime = time(NULL);
616943efbcgm		sip_counters.stoptime = 0;
617943efbcgm	}
618943efbcgm	(void) pthread_mutex_unlock(&sip_counters.sip_counter_mutex);
619943efbcgm	return (0);
620943efbcgm}
621943efbcgm
622943efbcgm/*
623943efbcgm * Disables the SIP performance/traffic counting. If already disabled it just
624943efbcgm * exits without doing anyting. It records the stop time.
625943efbcgm */
626943efbcgmint
627943efbcgmsip_disable_counters(int group)
628943efbcgm{
629943efbcgm	if (group != SIP_TRAFFIC_COUNTERS)
630943efbcgm		return (EINVAL);
631943efbcgm	(void) pthread_mutex_lock(&sip_counters.sip_counter_mutex);
632943efbcgm	if (sip_counters.enabled) {
633943efbcgm		sip_counters.enabled = B_FALSE;
634943efbcgm		sip_counters.stoptime = time(NULL);
635943efbcgm	}
636943efbcgm	(void) pthread_mutex_unlock(&sip_counters.sip_counter_mutex);
637943efbcgm	return (0);
638943efbcgm}
639