140cb5e5dSvi /* 240cb5e5dSvi * CDDL HEADER START 340cb5e5dSvi * 440cb5e5dSvi * The contents of this file are subject to the terms of the 540cb5e5dSvi * Common Development and Distribution License (the "License"). 640cb5e5dSvi * You may not use this file except in compliance with the License. 740cb5e5dSvi * 840cb5e5dSvi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 940cb5e5dSvi * or http://www.opensolaris.org/os/licensing. 1040cb5e5dSvi * See the License for the specific language governing permissions 1140cb5e5dSvi * and limitations under the License. 1240cb5e5dSvi * 1340cb5e5dSvi * When distributing Covered Code, include this CDDL HEADER in each 1440cb5e5dSvi * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1540cb5e5dSvi * If applicable, add the following below this CDDL HEADER, with the 1640cb5e5dSvi * fields enclosed by brackets "[]" replaced with your own identifying 1740cb5e5dSvi * information: Portions Copyright [yyyy] [name of copyright owner] 1840cb5e5dSvi * 1940cb5e5dSvi * CDDL HEADER END 2040cb5e5dSvi */ 2140cb5e5dSvi 2240cb5e5dSvi /* 23*943efbc3Sgm * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2440cb5e5dSvi * Use is subject to license terms. 2540cb5e5dSvi */ 2640cb5e5dSvi 2740cb5e5dSvi #pragma ident "%Z%%M% %I% %E% SMI" 2840cb5e5dSvi 292c2c4183Svi #include <stdio.h> 302c2c4183Svi #include <stdlib.h> 312c2c4183Svi #include <assert.h> 322c2c4183Svi #include <errno.h> 332c2c4183Svi #include <pthread.h> 342c2c4183Svi #include <strings.h> 352c2c4183Svi #include <sip.h> 362c2c4183Svi 3740cb5e5dSvi #include "sip_msg.h" 3840cb5e5dSvi #include "sip_miscdefs.h" 392c2c4183Svi #include "sip_hash.h" 4040cb5e5dSvi #include "sip_dialog.h" 4140cb5e5dSvi #include "sip_parse_generic.h" 4240cb5e5dSvi 4340cb5e5dSvi #define SIP_DLG_XCHG_FROM 0 4440cb5e5dSvi #define SIP_DLG_XCHG_TO 1 4540cb5e5dSvi 4640cb5e5dSvi /* 4740cb5e5dSvi * Dialog state change callback function 4840cb5e5dSvi */ 4940cb5e5dSvi void (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL; 5040cb5e5dSvi void (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL; 5140cb5e5dSvi 5240cb5e5dSvi boolean_t sip_incomplete_dialog(sip_dialog_t); 5340cb5e5dSvi 5440cb5e5dSvi /* 5540cb5e5dSvi * Exchange From/To header 5640cb5e5dSvi */ 5740cb5e5dSvi _sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int); 5840cb5e5dSvi 5940cb5e5dSvi /* 6040cb5e5dSvi * Complete dialog hash table 6140cb5e5dSvi */ 6240cb5e5dSvi sip_hash_t sip_dialog_hash[SIP_HASH_SZ]; 6340cb5e5dSvi 6440cb5e5dSvi /* 6540cb5e5dSvi * Partial dialog hash table 6640cb5e5dSvi */ 6740cb5e5dSvi sip_hash_t sip_dialog_phash[SIP_HASH_SZ]; 6840cb5e5dSvi 6940cb5e5dSvi /* 7040cb5e5dSvi * Route set structure 7140cb5e5dSvi */ 7240cb5e5dSvi typedef struct sip_dlg_route_set_s { 7340cb5e5dSvi char *sip_dlg_route; 7440cb5e5dSvi sip_str_t sip_dlg_ruri; 7540cb5e5dSvi boolean_t sip_dlg_route_lr; 7640cb5e5dSvi struct sip_dlg_route_set_s *sip_dlg_route_next; 7740cb5e5dSvi }sip_dlg_route_set_t; 7840cb5e5dSvi 7940cb5e5dSvi sip_dialog_t sip_seed_dialog(sip_conn_object_t, _sip_msg_t *, 8040cb5e5dSvi boolean_t, int); 8140cb5e5dSvi sip_dialog_t sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *); 8240cb5e5dSvi int sip_dialog_process(_sip_msg_t *, sip_dialog_t *); 8340cb5e5dSvi void sip_dialog_delete(_sip_dialog_t *); 8440cb5e5dSvi void sip_dialog_init(); 8540cb5e5dSvi sip_dialog_t sip_dialog_find(_sip_msg_t *); 8640cb5e5dSvi boolean_t sip_dialog_match(void *, void *); 8740cb5e5dSvi boolean_t sip_dialog_free(void *, void *, int *); 8840cb5e5dSvi sip_dialog_t sip_update_dialog(sip_dialog_t, _sip_msg_t *); 8940cb5e5dSvi char *sip_dialog_req_uri(sip_dialog_t); 9040cb5e5dSvi 9140cb5e5dSvi static void sip_release_dialog_res(_sip_dialog_t *); 9240cb5e5dSvi void sip_dlg_self_destruct(void *); 9340cb5e5dSvi static int sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *, 9440cb5e5dSvi int); 9540cb5e5dSvi static void sip_dialog_free_rset(sip_dlg_route_set_t *); 9640cb5e5dSvi 9740cb5e5dSvi /* 9840cb5e5dSvi * Timer object for partial dialogs 9940cb5e5dSvi */ 10040cb5e5dSvi typedef struct sip_dialog_timer_obj_s { 10140cb5e5dSvi _sip_dialog_t *dialog; 10240cb5e5dSvi void (*func)(sip_dialog_t, sip_msg_t, void *); 10340cb5e5dSvi } sip_dialog_timer_obj_t; 10440cb5e5dSvi 10540cb5e5dSvi /* 10640cb5e5dSvi * To avoid duplication all over the place 10740cb5e5dSvi */ 10840cb5e5dSvi static void 10940cb5e5dSvi sip_release_dialog_res(_sip_dialog_t *dialog) 11040cb5e5dSvi { 111*943efbc3Sgm int count = 0; 112*943efbc3Sgm sip_msg_chain_t *msg_chain; 113*943efbc3Sgm sip_msg_chain_t *nmsg_chain; 11440cb5e5dSvi 115*943efbc3Sgm if (dialog->sip_dlg_ref_cnt != 0) { 116*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 117*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 118*943efbc3Sgm } 11940cb5e5dSvi assert(dialog->sip_dlg_ref_cnt == 0); 12040cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 12140cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 12240cb5e5dSvi if (dialog->sip_dlg_call_id != NULL) 12340cb5e5dSvi sip_free_header(dialog->sip_dlg_call_id); 12440cb5e5dSvi if (dialog->sip_dlg_local_uri_tag != NULL) 12540cb5e5dSvi sip_free_header(dialog->sip_dlg_local_uri_tag); 12640cb5e5dSvi if (dialog->sip_dlg_remote_uri_tag != NULL) 12740cb5e5dSvi sip_free_header(dialog->sip_dlg_remote_uri_tag); 12840cb5e5dSvi if (dialog->sip_dlg_remote_target != NULL) 12940cb5e5dSvi sip_free_header(dialog->sip_dlg_remote_target); 130d8a40387Sgm if (dialog->sip_dlg_local_contact != NULL) 131d8a40387Sgm sip_free_header(dialog->sip_dlg_local_contact); 132d8a40387Sgm if (dialog->sip_dlg_new_local_contact != NULL) 133d8a40387Sgm sip_free_header(dialog->sip_dlg_new_local_contact); 13440cb5e5dSvi if (dialog->sip_dlg_route_set != NULL) 13540cb5e5dSvi sip_free_header(dialog->sip_dlg_route_set); 13640cb5e5dSvi if (dialog->sip_dlg_event != NULL) 13740cb5e5dSvi sip_free_header(dialog->sip_dlg_event); 13840cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 13940cb5e5dSvi free(dialog->sip_dlg_req_uri.sip_str_ptr); 14040cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 14140cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 0; 14240cb5e5dSvi } 14340cb5e5dSvi if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 14440cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 14540cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 14640cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 14740cb5e5dSvi } 148*943efbc3Sgm for (count = 0; count <= SIP_DLG_DESTROYED; count++) { 149*943efbc3Sgm msg_chain = dialog->sip_dlg_log[count].sip_msgs; 150*943efbc3Sgm while (msg_chain != NULL) { 151*943efbc3Sgm nmsg_chain = msg_chain->next; 152*943efbc3Sgm if (msg_chain->sip_msg != NULL) 153*943efbc3Sgm free(msg_chain->sip_msg); 154*943efbc3Sgm free(msg_chain); 155*943efbc3Sgm msg_chain = nmsg_chain; 156*943efbc3Sgm } 157*943efbc3Sgm } 15840cb5e5dSvi (void) pthread_mutex_destroy(&dialog->sip_dlg_mutex); 15940cb5e5dSvi free(dialog); 16040cb5e5dSvi } 16140cb5e5dSvi 16240cb5e5dSvi /* 16340cb5e5dSvi * Get the route information from the 'value' and add it to the route 16440cb5e5dSvi * set. 16540cb5e5dSvi */ 16640cb5e5dSvi static sip_dlg_route_set_t * 16740cb5e5dSvi sip_add_route_to_set(sip_hdr_value_t *value) 16840cb5e5dSvi { 16940cb5e5dSvi int vlen = 0; 17040cb5e5dSvi sip_dlg_route_set_t *rset; 17140cb5e5dSvi char *crlf; 17240cb5e5dSvi const sip_param_t *uri_param; 17340cb5e5dSvi int error; 17440cb5e5dSvi 17540cb5e5dSvi rset = calloc(1, sizeof (*rset)); 17640cb5e5dSvi if (rset == NULL) 17740cb5e5dSvi return (NULL); 17840cb5e5dSvi rset->sip_dlg_route_next = NULL; 17940cb5e5dSvi vlen = value->sip_value_end - value->sip_value_start; 18040cb5e5dSvi 18140cb5e5dSvi /* 18240cb5e5dSvi * check for CRLF 18340cb5e5dSvi */ 18440cb5e5dSvi crlf = value->sip_value_end - strlen(SIP_CRLF); 18540cb5e5dSvi while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 18640cb5e5dSvi vlen -= strlen(SIP_CRLF); 18740cb5e5dSvi crlf -= strlen(SIP_CRLF); 18840cb5e5dSvi } 18940cb5e5dSvi rset->sip_dlg_route = calloc(1, vlen + 1); 19040cb5e5dSvi if (rset->sip_dlg_route == NULL) { 19140cb5e5dSvi free(rset); 19240cb5e5dSvi return (NULL); 19340cb5e5dSvi } 19440cb5e5dSvi /* 19540cb5e5dSvi * loose routing 19640cb5e5dSvi */ 19740cb5e5dSvi rset->sip_dlg_route_lr = B_FALSE; 19840cb5e5dSvi (void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen); 19940cb5e5dSvi rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route + 20040cb5e5dSvi (value->cftr_uri.sip_str_ptr - value->sip_value_start); 20140cb5e5dSvi rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len; 20240cb5e5dSvi rset->sip_dlg_route[vlen] = '\0'; 20340cb5e5dSvi 20440cb5e5dSvi assert(value->sip_value_parsed_uri != NULL); 20540cb5e5dSvi /* 20640cb5e5dSvi * Check if the 'lr' param is present for this route. 20740cb5e5dSvi */ 20840cb5e5dSvi uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error); 20940cb5e5dSvi if (error != 0) { 21040cb5e5dSvi free(rset->sip_dlg_route); 21140cb5e5dSvi free(rset); 21240cb5e5dSvi return (NULL); 21340cb5e5dSvi } 21440cb5e5dSvi if (uri_param != NULL) { 21540cb5e5dSvi rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr", 21640cb5e5dSvi strlen("lr")); 21740cb5e5dSvi } 21840cb5e5dSvi return (rset); 21940cb5e5dSvi } 22040cb5e5dSvi 22140cb5e5dSvi /* 22240cb5e5dSvi * Depending on the route-set, determine the request URI. 22340cb5e5dSvi */ 22440cb5e5dSvi char * 22540cb5e5dSvi sip_dialog_req_uri(sip_dialog_t dialog) 22640cb5e5dSvi { 22740cb5e5dSvi const sip_str_t *req_uri; 22840cb5e5dSvi char *uri; 22940cb5e5dSvi _sip_dialog_t *_dialog; 23040cb5e5dSvi 23140cb5e5dSvi _dialog = (_sip_dialog_t *)dialog; 23240cb5e5dSvi if (_dialog->sip_dlg_route_set == NULL || 23340cb5e5dSvi _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 23440cb5e5dSvi const struct sip_value *val; 23540cb5e5dSvi 23640cb5e5dSvi val = sip_get_header_value(_dialog->sip_dlg_remote_target, 23740cb5e5dSvi NULL); 23840cb5e5dSvi if (val == NULL) 23940cb5e5dSvi return (NULL); 24040cb5e5dSvi req_uri = &((sip_hdr_value_t *)val)->cftr_uri; 24140cb5e5dSvi } else { 24240cb5e5dSvi req_uri = &_dialog->sip_dlg_req_uri; 24340cb5e5dSvi } 24440cb5e5dSvi uri = (char *)malloc(req_uri->sip_str_len + 1); 24540cb5e5dSvi if (uri == NULL) 24640cb5e5dSvi return (NULL); 24740cb5e5dSvi (void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len); 24840cb5e5dSvi uri[req_uri->sip_str_len] = '\0'; 24940cb5e5dSvi 25040cb5e5dSvi return (uri); 25140cb5e5dSvi } 25240cb5e5dSvi 25340cb5e5dSvi /* 25440cb5e5dSvi * Free the route set. 25540cb5e5dSvi */ 25640cb5e5dSvi void 25740cb5e5dSvi sip_dialog_free_rset(sip_dlg_route_set_t *rset) 25840cb5e5dSvi { 25940cb5e5dSvi sip_dlg_route_set_t *next; 26040cb5e5dSvi 26140cb5e5dSvi while (rset != NULL) { 26240cb5e5dSvi next = rset->sip_dlg_route_next; 26340cb5e5dSvi rset->sip_dlg_route_next = NULL; 26440cb5e5dSvi free(rset->sip_dlg_route); 26540cb5e5dSvi free(rset); 26640cb5e5dSvi rset = next; 26740cb5e5dSvi } 26840cb5e5dSvi } 26940cb5e5dSvi 27040cb5e5dSvi /* 27140cb5e5dSvi * Recompute route-set 27240cb5e5dSvi */ 27340cb5e5dSvi static int 27440cb5e5dSvi sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 27540cb5e5dSvi { 27640cb5e5dSvi int ret; 27740cb5e5dSvi 27840cb5e5dSvi if (dialog->sip_dlg_route_set != NULL) { 27940cb5e5dSvi sip_free_header(dialog->sip_dlg_route_set); 28040cb5e5dSvi dialog->sip_dlg_route_set = NULL; 28140cb5e5dSvi } 28240cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 28340cb5e5dSvi free(dialog->sip_dlg_req_uri.sip_str_ptr); 28440cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 28540cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 0; 28640cb5e5dSvi } 28740cb5e5dSvi if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 28840cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 28940cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 29040cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 29140cb5e5dSvi } 29240cb5e5dSvi ret = sip_dialog_get_route_set(dialog, sip_msg, what); 29340cb5e5dSvi return (ret); 29440cb5e5dSvi } 29540cb5e5dSvi 29640cb5e5dSvi /* 29740cb5e5dSvi * If the route set is empty, the UAC MUST place the remote target URI 29840cb5e5dSvi * into the Request-URI. The UAC MUST NOT add a Route header field to 29940cb5e5dSvi * the request. 30040cb5e5dSvi * 30140cb5e5dSvi * If the route set is not empty, and the first URI in the route set 30240cb5e5dSvi * contains the lr parameter (see Section 19.1.1), the UAC MUST place 30340cb5e5dSvi * the remote target URI into the Request-URI and MUST include a Route 30440cb5e5dSvi * header field containing the route set values in order, including all 30540cb5e5dSvi * parameters. 30640cb5e5dSvi * 30740cb5e5dSvi * If the route set is not empty, and its first URI does not contain the 30840cb5e5dSvi * lr parameter, the UAC MUST place the first URI from the route set 30940cb5e5dSvi * into the Request-URI, stripping any parameters that are not allowed 31040cb5e5dSvi * in a Request-URI. The UAC MUST add a Route header field containing 31140cb5e5dSvi * the remainder of the route set values in order, including all 31240cb5e5dSvi * parameters. The UAC MUST then place the remote target URI into the 31340cb5e5dSvi * Route header field as the last value. 31440cb5e5dSvi */ 31540cb5e5dSvi int 31640cb5e5dSvi sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head, 31740cb5e5dSvi int rcnt, int rlen) 31840cb5e5dSvi { 31940cb5e5dSvi size_t rset_len; 32040cb5e5dSvi _sip_header_t *rhdr; 32140cb5e5dSvi char *rset; 32240cb5e5dSvi char *rp; 32340cb5e5dSvi char *rsp; 32440cb5e5dSvi int count; 32540cb5e5dSvi sip_dlg_route_set_t *route; 32640cb5e5dSvi boolean_t first = B_TRUE; 32740cb5e5dSvi const sip_str_t *to_uri; 32840cb5e5dSvi char *uri = NULL; 32940cb5e5dSvi int rspl; 33040cb5e5dSvi int rpl; 33140cb5e5dSvi 332*943efbc3Sgm if (rcnt <= 0) { 333*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 334*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 335*943efbc3Sgm } 33640cb5e5dSvi assert(rcnt > 0); 33740cb5e5dSvi 33840cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1; 33940cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt); 34040cb5e5dSvi if (dialog->sip_dlg_rset.sip_str_ptr == NULL) 34140cb5e5dSvi return (ENOMEM); 34240cb5e5dSvi rsp = dialog->sip_dlg_rset.sip_str_ptr; 34340cb5e5dSvi rspl = rlen + rcnt; 34440cb5e5dSvi route = rset_head; 34540cb5e5dSvi rset_len = rlen; 34640cb5e5dSvi if (!route->sip_dlg_route_lr) { 34740cb5e5dSvi const struct sip_value *val; 34840cb5e5dSvi 34940cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL); 35040cb5e5dSvi to_uri = &((sip_hdr_value_t *)val)->cftr_uri; 35140cb5e5dSvi uri = (char *)malloc(to_uri->sip_str_len + 1); 35240cb5e5dSvi if (uri == NULL) { 35340cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 35440cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 35540cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 35640cb5e5dSvi return (ENOMEM); 35740cb5e5dSvi } 35840cb5e5dSvi (void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len); 35940cb5e5dSvi uri[to_uri->sip_str_len] = '\0'; 36040cb5e5dSvi rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) + 36140cb5e5dSvi SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN + 36240cb5e5dSvi sizeof (char); 36340cb5e5dSvi count = snprintf(rsp, rspl, "%s", route->sip_dlg_route); 36440cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = malloc( 36540cb5e5dSvi route->sip_dlg_ruri.sip_str_len + 1); 36640cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 36740cb5e5dSvi free(uri); 36840cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 36940cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 37040cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 37140cb5e5dSvi return (ENOMEM); 37240cb5e5dSvi } 37340cb5e5dSvi (void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp + 37440cb5e5dSvi (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route), 37540cb5e5dSvi route->sip_dlg_ruri.sip_str_len); 37640cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr[ 37740cb5e5dSvi route->sip_dlg_ruri.sip_str_len] = '\0'; 37840cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 37940cb5e5dSvi route->sip_dlg_ruri.sip_str_len; 38040cb5e5dSvi 38140cb5e5dSvi rsp += count; 38240cb5e5dSvi rspl -= count; 38340cb5e5dSvi route = route->sip_dlg_route_next; 38440cb5e5dSvi } 38540cb5e5dSvi 38640cb5e5dSvi /* 38740cb5e5dSvi * rcnt - 1 is for the number of COMMAs 38840cb5e5dSvi */ 38940cb5e5dSvi rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) + 39040cb5e5dSvi SIP_SPACE_LEN + rcnt - 1; 39140cb5e5dSvi rset = malloc(rset_len + 1); 39240cb5e5dSvi if (rset == NULL) { 39340cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 39440cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 39540cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 39640cb5e5dSvi return (ENOMEM); 39740cb5e5dSvi } 39840cb5e5dSvi rhdr = sip_new_header(rset_len + strlen(SIP_CRLF)); 39940cb5e5dSvi if (rhdr == NULL) { 40040cb5e5dSvi free(rset); 40140cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 40240cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 40340cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 40440cb5e5dSvi return (ENOMEM); 40540cb5e5dSvi } 40640cb5e5dSvi 40740cb5e5dSvi rp = rset; 40840cb5e5dSvi rpl = rset_len + 1; 40940cb5e5dSvi count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON); 41040cb5e5dSvi rp += count; 41140cb5e5dSvi rpl -= count; 41240cb5e5dSvi 41340cb5e5dSvi while (route != NULL) { 41440cb5e5dSvi if (first) { 41540cb5e5dSvi count = snprintf(rp, rpl, "%s", route->sip_dlg_route); 41640cb5e5dSvi rp += count; 41740cb5e5dSvi rpl -= count; 41840cb5e5dSvi first = B_FALSE; 41940cb5e5dSvi if (uri != NULL) { 42040cb5e5dSvi count = snprintf(rsp, rspl, "%c%s", 42140cb5e5dSvi SIP_COMMA, route->sip_dlg_route); 42240cb5e5dSvi } else { 42340cb5e5dSvi count = snprintf(rsp, rspl, "%s", 42440cb5e5dSvi route->sip_dlg_route); 42540cb5e5dSvi } 42640cb5e5dSvi rsp += count; 42740cb5e5dSvi rspl -= count; 42840cb5e5dSvi } else { 42940cb5e5dSvi count = snprintf(rp, rpl, "%c%s", SIP_COMMA, 43040cb5e5dSvi route->sip_dlg_route); 43140cb5e5dSvi rp += count; 43240cb5e5dSvi rpl -= count; 43340cb5e5dSvi count = snprintf(rsp, rspl, "%c%s", SIP_COMMA, 43440cb5e5dSvi route->sip_dlg_route); 43540cb5e5dSvi rsp += count; 43640cb5e5dSvi rspl -= count; 43740cb5e5dSvi } 43840cb5e5dSvi route = route->sip_dlg_route_next; 43940cb5e5dSvi } 440*943efbc3Sgm if (rsp > dialog->sip_dlg_rset.sip_str_ptr + 441*943efbc3Sgm dialog->sip_dlg_rset.sip_str_len) { 442*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 443*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 444*943efbc3Sgm } 44540cb5e5dSvi assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr + 44640cb5e5dSvi dialog->sip_dlg_rset.sip_str_len); 44740cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] = 44840cb5e5dSvi '\0'; 44940cb5e5dSvi if (uri != NULL) { 45040cb5e5dSvi if (first) { 45140cb5e5dSvi count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT, 45240cb5e5dSvi uri, SIP_RAQUOT); 45340cb5e5dSvi } else { 45440cb5e5dSvi count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA, 45540cb5e5dSvi SIP_LAQUOT, uri, SIP_RAQUOT); 45640cb5e5dSvi } 45740cb5e5dSvi rp += count; 45840cb5e5dSvi rpl -= count; 45940cb5e5dSvi free(uri); 46040cb5e5dSvi } 461*943efbc3Sgm if (rp > rset + rset_len) { 462*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 463*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 464*943efbc3Sgm } 46540cb5e5dSvi assert(rp <= rset + rset_len); 46640cb5e5dSvi (void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1, 46740cb5e5dSvi "%s%s", rset, SIP_CRLF); 46840cb5e5dSvi free(rset); 46940cb5e5dSvi dialog->sip_dlg_route_set = (sip_header_t)rhdr; 47040cb5e5dSvi sip_dialog_free_rset(rset_head); 47140cb5e5dSvi return (0); 47240cb5e5dSvi } 47340cb5e5dSvi 47440cb5e5dSvi /* 47540cb5e5dSvi * UAC Behavior 47640cb5e5dSvi * The route set MUST be set to the list of URIs in the Record-Route 47740cb5e5dSvi * header field from the response, taken in reverse order and preserving 47840cb5e5dSvi * all URI parameters. 47940cb5e5dSvi * 48040cb5e5dSvi * UAS behavior 48140cb5e5dSvi * The route set MUST be set to the list of URIs in the Record-Route 48240cb5e5dSvi * header field from the request, taken in order and preserving all URI 48340cb5e5dSvi * parameters. 48440cb5e5dSvi */ 48540cb5e5dSvi static int 48640cb5e5dSvi sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 48740cb5e5dSvi { 48840cb5e5dSvi sip_header_t rrhdr; 48940cb5e5dSvi sip_hdr_value_t *value; 49040cb5e5dSvi int error; 49140cb5e5dSvi sip_dlg_route_set_t *rset_head = NULL; 49240cb5e5dSvi sip_dlg_route_set_t *rset_tail = NULL; 49340cb5e5dSvi sip_dlg_route_set_t *rset; 49440cb5e5dSvi int rset_cnt = 0; 49540cb5e5dSvi int rset_len = 0; 49640cb5e5dSvi 49740cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 49840cb5e5dSvi rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL); 49940cb5e5dSvi while (rrhdr != NULL) { 50040cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 50140cb5e5dSvi value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error); 50240cb5e5dSvi while (value != NULL && error == 0) { 50340cb5e5dSvi char *crlf; 50440cb5e5dSvi 50540cb5e5dSvi if (value->sip_value_state == SIP_VALUE_BAD) { 50640cb5e5dSvi value = (sip_hdr_value_t *)sip_get_next_value( 50740cb5e5dSvi (sip_header_value_t)value, &error); 50840cb5e5dSvi continue; 50940cb5e5dSvi } 51040cb5e5dSvi rset = sip_add_route_to_set(value); 51140cb5e5dSvi if (rset == NULL) 51240cb5e5dSvi goto r_error; 51340cb5e5dSvi /* 51440cb5e5dSvi * Add one for COMMA 51540cb5e5dSvi */ 51640cb5e5dSvi rset_cnt++; 51740cb5e5dSvi rset_len += (value->sip_value_end - 51840cb5e5dSvi value->sip_value_start); 51940cb5e5dSvi /* 52040cb5e5dSvi * Check for CRLF 52140cb5e5dSvi */ 52240cb5e5dSvi crlf = value->sip_value_end - strlen(SIP_CRLF); 52340cb5e5dSvi while (crlf != NULL && 52440cb5e5dSvi strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 52540cb5e5dSvi rset_len -= strlen(SIP_CRLF); 52640cb5e5dSvi crlf -= strlen(SIP_CRLF); 52740cb5e5dSvi } 52840cb5e5dSvi if (rset_head == NULL) { 529*943efbc3Sgm if (rset_tail != NULL) { 530*943efbc3Sgm sip_write_to_log((void *)dialog, 531*943efbc3Sgm SIP_DIALOG_LOG | SIP_ASSERT_ERROR, 532*943efbc3Sgm __FILE__, __LINE__); 533*943efbc3Sgm } 53440cb5e5dSvi assert(rset_tail == NULL); 53540cb5e5dSvi rset_head = rset_tail = rset; 53640cb5e5dSvi } else if (what == SIP_UAS_DIALOG) { 53740cb5e5dSvi rset_tail->sip_dlg_route_next = rset; 53840cb5e5dSvi rset_tail = rset; 53940cb5e5dSvi } else if (what == SIP_UAC_DIALOG) { 54040cb5e5dSvi rset->sip_dlg_route_next = rset_head; 54140cb5e5dSvi rset_head = rset; 54240cb5e5dSvi } else { 543*943efbc3Sgm sip_write_to_log((void *)dialog, 544*943efbc3Sgm SIP_DIALOG_LOG | SIP_ASSERT_ERROR, 545*943efbc3Sgm __FILE__, __LINE__); 54640cb5e5dSvi assert(0); 54740cb5e5dSvi } 54840cb5e5dSvi value = (sip_hdr_value_t *)sip_get_next_value( 54940cb5e5dSvi (sip_header_value_t)value, &error); 55040cb5e5dSvi } 55140cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 55240cb5e5dSvi rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr); 55340cb5e5dSvi } 55440cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 55540cb5e5dSvi if (rset_cnt == 0) 55640cb5e5dSvi return (0); 55740cb5e5dSvi if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt, 55840cb5e5dSvi rset_len) != 0) { 55940cb5e5dSvi goto r_error; 56040cb5e5dSvi } 56140cb5e5dSvi return (0); 56240cb5e5dSvi r_error: 56340cb5e5dSvi sip_dialog_free_rset(rset_head); 56440cb5e5dSvi return (ENOMEM); 56540cb5e5dSvi } 56640cb5e5dSvi 56740cb5e5dSvi /* 56840cb5e5dSvi * UAS behavior: 56940cb5e5dSvi * The remote sequence number MUST be set to the value of the sequence 57040cb5e5dSvi * number in the CSeq header field of the request. The local sequence 57140cb5e5dSvi * number MUST be empty. The call identifier component of the dialog ID 57240cb5e5dSvi * MUST be set to the value of the Call-ID in the request. The local 57340cb5e5dSvi * tag component of the dialog ID MUST be set to the tag in the To field 57440cb5e5dSvi * in the response to the request (which always includes a tag), and the 57540cb5e5dSvi * remote tag component of the dialog ID MUST be set to the tag from the 57640cb5e5dSvi * From field in the request. A UAS MUST be prepared to receive a 57740cb5e5dSvi * request without a tag in the From field, in which case the tag is 57840cb5e5dSvi * considered to have a value of null. 57940cb5e5dSvi * The remote URI MUST be set to the URI in the From field, and the 58040cb5e5dSvi * local URI MUST be set to the URI in the To field. 58140cb5e5dSvi * The remote target MUST be set to the URI from the Contact header field 58240cb5e5dSvi * of the request. 58340cb5e5dSvi * 58440cb5e5dSvi * UAC behavior: 58540cb5e5dSvi * The local sequence number MUST be set to the value of the sequence 58640cb5e5dSvi * number in the CSeq header field of the request. The remote sequence 58740cb5e5dSvi * number MUST be empty (it is established when the remote UA sends a 58840cb5e5dSvi * request within the dialog). The call identifier component of the 58940cb5e5dSvi * dialog ID MUST be set to the value of the Call-ID in the request. 59040cb5e5dSvi * The local tag component of the dialog ID MUST be set to the tag in 59140cb5e5dSvi * the From field in the request, and the remote tag component of the 59240cb5e5dSvi * dialog ID MUST be set to the tag in the To field of the response. A 59340cb5e5dSvi * UAC MUST be prepared to receive a response without a tag in the To 59440cb5e5dSvi * field, in which case the tag is considered to have a value of null. 59540cb5e5dSvi * The remote URI MUST be set to the URI in the To field, and the local 59640cb5e5dSvi * URI MUST be set to the URI in the From field. 59740cb5e5dSvi * The remote target MUST be set to the URI from the Contact header field 59840cb5e5dSvi * of the response. 59940cb5e5dSvi */ 60040cb5e5dSvi 60140cb5e5dSvi 60240cb5e5dSvi /* 60340cb5e5dSvi * This is the routine that seeds a dialog. 60440cb5e5dSvi */ 60540cb5e5dSvi sip_dialog_t 60640cb5e5dSvi sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg, 60740cb5e5dSvi boolean_t dlg_on_fork, int dlg_type) 60840cb5e5dSvi { 60940cb5e5dSvi _sip_dialog_t *dialog; 61040cb5e5dSvi int cseq; 61140cb5e5dSvi sip_header_t fhdr = NULL; 61240cb5e5dSvi sip_header_t thdr = NULL; 61340cb5e5dSvi sip_header_t chdr; 61440cb5e5dSvi sip_header_t cihdr; 61540cb5e5dSvi sip_header_t evhdr = NULL; 61640cb5e5dSvi const struct sip_value *value; 61740cb5e5dSvi sip_dialog_timer_obj_t *tim_obj = NULL; 61840cb5e5dSvi const sip_str_t *callid; 61940cb5e5dSvi sip_method_t method; 62040cb5e5dSvi int timer1 = sip_timer_T1; 62140cb5e5dSvi int error; 62240cb5e5dSvi 62340cb5e5dSvi if (!sip_msg_is_request((sip_msg_t)sip_msg, &error)) 62440cb5e5dSvi return (NULL); 62540cb5e5dSvi 62640cb5e5dSvi method = sip_get_request_method((sip_msg_t)sip_msg, &error); 62740cb5e5dSvi /* 62840cb5e5dSvi * Only INVITE and SUBSCRIBE supported 62940cb5e5dSvi */ 63040cb5e5dSvi if (error != 0 || (method != INVITE && method != SUBSCRIBE)) 63140cb5e5dSvi return (NULL); 63240cb5e5dSvi 63340cb5e5dSvi /* 63440cb5e5dSvi * A request outside of a dialog MUST NOT contain a To tag 63540cb5e5dSvi */ 63640cb5e5dSvi if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL) 63740cb5e5dSvi return (NULL); 63840cb5e5dSvi 63940cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG) { 64040cb5e5dSvi thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 64140cb5e5dSvi SIP_DLG_XCHG_FROM); 64240cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 64340cb5e5dSvi } else { 64440cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 64540cb5e5dSvi fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL); 64640cb5e5dSvi } 64740cb5e5dSvi cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL); 64840cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 64940cb5e5dSvi if (method == SUBSCRIBE) 65040cb5e5dSvi evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 65140cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 65240cb5e5dSvi if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL || 65340cb5e5dSvi (method == SUBSCRIBE && evhdr == NULL)) { 65440cb5e5dSvi if (thdr != NULL) 65540cb5e5dSvi sip_free_header(thdr); 65640cb5e5dSvi return (NULL); 65740cb5e5dSvi } 65840cb5e5dSvi 65940cb5e5dSvi /* 66040cb5e5dSvi * Sanity check since we just store the headers in the dialog 66140cb5e5dSvi */ 66240cb5e5dSvi if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL || 66340cb5e5dSvi sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 66440cb5e5dSvi ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) || 66540cb5e5dSvi (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL || 66640cb5e5dSvi sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 66740cb5e5dSvi ((value = sip_get_header_value(chdr, NULL)) == NULL) || 66840cb5e5dSvi sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) { 66940cb5e5dSvi if (thdr != NULL) 67040cb5e5dSvi sip_free_header(thdr); 67140cb5e5dSvi return (NULL); 67240cb5e5dSvi } 67340cb5e5dSvi 67440cb5e5dSvi tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t)); 67540cb5e5dSvi if (tim_obj == NULL) { 67640cb5e5dSvi if (thdr != NULL) 67740cb5e5dSvi sip_free_header(thdr); 67840cb5e5dSvi return (NULL); 67940cb5e5dSvi } 68040cb5e5dSvi dialog = calloc(1, sizeof (_sip_dialog_t)); 68140cb5e5dSvi if (dialog == NULL) { 68240cb5e5dSvi if (thdr != NULL) 68340cb5e5dSvi sip_free_header(thdr); 68440cb5e5dSvi return (NULL); 68540cb5e5dSvi } 68640cb5e5dSvi /* 68740cb5e5dSvi * We will take the TO header with the tag when we complete this 68840cb5e5dSvi * dialog 68940cb5e5dSvi */ 69040cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG) { 69140cb5e5dSvi dialog->sip_dlg_remote_uri_tag = thdr; 69240cb5e5dSvi /* 69340cb5e5dSvi * We take the remote target from the incoming request on the 69440cb5e5dSvi * UAS. For the UAC, we will take it from the response. 69540cb5e5dSvi */ 69640cb5e5dSvi if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == 69740cb5e5dSvi NULL) { 69840cb5e5dSvi goto dia_err; 69940cb5e5dSvi } 70040cb5e5dSvi } else { 70140cb5e5dSvi if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) == 70240cb5e5dSvi NULL) { 70340cb5e5dSvi goto dia_err; 70440cb5e5dSvi } 705d8a40387Sgm /* 706d8a40387Sgm * We take the local contact from the originating request on 707d8a40387Sgm * UAC. For the UAS, we will take it from the response. 708d8a40387Sgm */ 709d8a40387Sgm if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) == 710d8a40387Sgm NULL) { 711d8a40387Sgm goto dia_err; 712d8a40387Sgm } else { 713d8a40387Sgm dialog->sip_dlg_new_local_contact = NULL; 714d8a40387Sgm } 71540cb5e5dSvi } 71640cb5e5dSvi if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL) 71740cb5e5dSvi goto dia_err; 71840cb5e5dSvi if (method == SUBSCRIBE) { 71940cb5e5dSvi dialog->sip_dlg_event = sip_dup_header(evhdr); 72040cb5e5dSvi if (dialog->sip_dlg_event == NULL) { 72140cb5e5dSvi goto dia_err; 72240cb5e5dSvi } 72340cb5e5dSvi } 72440cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 72540cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 72640cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 72740cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 0; 72840cb5e5dSvi /* 72940cb5e5dSvi * Get the route set from the request, if present 73040cb5e5dSvi */ 73140cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG && 73240cb5e5dSvi sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) { 73340cb5e5dSvi goto dia_err; 73440cb5e5dSvi } 73540cb5e5dSvi if (dlg_type == SIP_UAC_DIALOG) 73640cb5e5dSvi dialog->sip_dlg_local_cseq = cseq; 73740cb5e5dSvi else 73840cb5e5dSvi dialog->sip_dlg_remote_cseq = cseq; 73940cb5e5dSvi dialog->sip_dlg_type = dlg_type; 74040cb5e5dSvi dialog->sip_dlg_on_fork = dlg_on_fork; 74140cb5e5dSvi dialog->sip_dlg_method = method; 74240cb5e5dSvi /* 74340cb5e5dSvi * Set the partial dialog timer with the INVITE timeout val 74440cb5e5dSvi */ 74540cb5e5dSvi if (sip_conn_timer1 != NULL) 74640cb5e5dSvi timer1 = sip_conn_timer1(obj); 74740cb5e5dSvi SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1); 74840cb5e5dSvi tim_obj->dialog = dialog; 74940cb5e5dSvi /* 75040cb5e5dSvi * Since at the client we never pass the partial dialog, we need not 75140cb5e5dSvi * invoke the callback when the partial dialog self-destructs. 75240cb5e5dSvi */ 75340cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG) 75440cb5e5dSvi tim_obj->func = sip_ulp_dlg_del_cb; 75540cb5e5dSvi SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj, 75640cb5e5dSvi sip_dlg_self_destruct); 75740cb5e5dSvi if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 75840cb5e5dSvi goto dia_err; 75940cb5e5dSvi (void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL); 76040cb5e5dSvi 76140cb5e5dSvi if (dlg_type == SIP_UAC_DIALOG) { 76240cb5e5dSvi const sip_str_t *local_tag; 76340cb5e5dSvi 76440cb5e5dSvi local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 765*943efbc3Sgm if (local_tag == NULL) { 766*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 767*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 768*943efbc3Sgm } 76940cb5e5dSvi assert(local_tag != NULL); 77040cb5e5dSvi sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len, 77140cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 77240cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, NULL, 0, 77340cb5e5dSvi (uchar_t *)dialog->sip_dlg_id); 77440cb5e5dSvi 77540cb5e5dSvi 77640cb5e5dSvi /* 77740cb5e5dSvi * Add it to the partial hash table 77840cb5e5dSvi */ 77940cb5e5dSvi if (sip_hash_add(sip_dialog_phash, (void *)dialog, 78040cb5e5dSvi SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 78140cb5e5dSvi goto dia_err; 78240cb5e5dSvi } 78340cb5e5dSvi } 784*943efbc3Sgm 785*943efbc3Sgm dialog->sip_dlg_msgcnt = 1; 786*943efbc3Sgm sip_add_log(&dialog->sip_dlg_log[dialog->sip_dlg_state], 787*943efbc3Sgm (sip_msg_t)sip_msg, dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG); 788*943efbc3Sgm 78940cb5e5dSvi SIP_DLG_REFCNT_INCR(dialog); 79040cb5e5dSvi return ((sip_dialog_t)dialog); 79140cb5e5dSvi dia_err: 79240cb5e5dSvi sip_release_dialog_res(dialog); 79340cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 79440cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 79540cb5e5dSvi if (tim_obj != NULL) 79640cb5e5dSvi free(tim_obj); 79740cb5e5dSvi return (NULL); 79840cb5e5dSvi } 79940cb5e5dSvi 80040cb5e5dSvi /* 80140cb5e5dSvi * When creating a dialog from a NOTIFY request, we need to get the FROM 80240cb5e5dSvi * header for the dialog from the TO header of the NOTIFY. 80340cb5e5dSvi */ 80440cb5e5dSvi _sip_header_t * 80540cb5e5dSvi sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what) 80640cb5e5dSvi { 80740cb5e5dSvi int len; 80840cb5e5dSvi _sip_header_t *newhdr; 80940cb5e5dSvi int cnt; 81040cb5e5dSvi const struct sip_header *hdr; 81140cb5e5dSvi int hdrsize; 81240cb5e5dSvi int error; 81340cb5e5dSvi 81440cb5e5dSvi hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM : 81540cb5e5dSvi SIP_TO, NULL, &error); 81640cb5e5dSvi if (error != 0 || hdr == NULL) 81740cb5e5dSvi return (NULL); 81840cb5e5dSvi if (sip_parse_goto_values((_sip_header_t *)hdr) != 0) 81940cb5e5dSvi return (NULL); 82040cb5e5dSvi len = hdr->sip_hdr_end - hdr->sip_hdr_current; 82140cb5e5dSvi if (what == SIP_DLG_XCHG_FROM) { 82240cb5e5dSvi hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) + 82340cb5e5dSvi SIP_SPACE_LEN; 82440cb5e5dSvi } else { 82540cb5e5dSvi hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN + 82640cb5e5dSvi sizeof (char) + SIP_SPACE_LEN; 82740cb5e5dSvi } 82840cb5e5dSvi newhdr = sip_new_header(hdrsize); 82940cb5e5dSvi if (newhdr == NULL) 83040cb5e5dSvi return (NULL); 83140cb5e5dSvi if (what == SIP_DLG_XCHG_FROM) { 83240cb5e5dSvi cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 83340cb5e5dSvi "%s %c ", SIP_TO, SIP_HCOLON); 83440cb5e5dSvi } else { 83540cb5e5dSvi cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 83640cb5e5dSvi "%s %c ", SIP_FROM, SIP_HCOLON); 83740cb5e5dSvi } 83840cb5e5dSvi newhdr->sip_hdr_current += cnt; 83940cb5e5dSvi (void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len); 84040cb5e5dSvi newhdr->sip_hdr_current += len; 84140cb5e5dSvi assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end); 84240cb5e5dSvi assert(hdr->sip_header_functions != NULL); 84340cb5e5dSvi 84440cb5e5dSvi /* 84540cb5e5dSvi * FROM and TO have common parsing functions 84640cb5e5dSvi */ 84740cb5e5dSvi newhdr->sip_header_functions = hdr->sip_header_functions; 84840cb5e5dSvi newhdr->sip_hdr_current = newhdr->sip_hdr_start; 84940cb5e5dSvi 85040cb5e5dSvi return (newhdr); 85140cb5e5dSvi } 85240cb5e5dSvi 85340cb5e5dSvi /* 85440cb5e5dSvi * This is the response that completes the dialog that was created 85540cb5e5dSvi * in sip_seed_dialog(). 85640cb5e5dSvi */ 85740cb5e5dSvi sip_dialog_t 85840cb5e5dSvi sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog) 85940cb5e5dSvi { 86040cb5e5dSvi _sip_header_t *thdr; 86140cb5e5dSvi _sip_header_t *evhdr = NULL; 86240cb5e5dSvi _sip_header_t *substate = NULL; 86340cb5e5dSvi sip_header_t chdr = NULL; 86440cb5e5dSvi int resp_code; 86540cb5e5dSvi const sip_str_t *ttag; 86640cb5e5dSvi const sip_str_t *remtag; 86740cb5e5dSvi const sip_str_t *callid; 86840cb5e5dSvi const struct sip_value *val; 86940cb5e5dSvi sip_method_t method; 87040cb5e5dSvi int error = 0; 87140cb5e5dSvi int prev_state; 87240cb5e5dSvi boolean_t alloc_thdr = B_FALSE; 87340cb5e5dSvi 87440cb5e5dSvi if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0) 87540cb5e5dSvi method = sip_get_request_method((sip_msg_t)sip_msg, &error); 87640cb5e5dSvi else 87740cb5e5dSvi method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 87840cb5e5dSvi if (error != 0 || dialog == NULL || 87940cb5e5dSvi (sip_msg_is_request((sip_msg_t)sip_msg, &error) && 88040cb5e5dSvi (dialog->sip_dlg_method == INVITE || method != NOTIFY))) { 88140cb5e5dSvi return (NULL); 88240cb5e5dSvi } 88340cb5e5dSvi if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY && 88440cb5e5dSvi sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 88540cb5e5dSvi dialog->sip_dlg_local_cseq) || 88640cb5e5dSvi (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY && 88740cb5e5dSvi sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 88840cb5e5dSvi dialog->sip_dlg_remote_cseq)) { 88940cb5e5dSvi return (NULL); 89040cb5e5dSvi } 89140cb5e5dSvi if (method == NOTIFY) { 89240cb5e5dSvi const sip_str_t *sstate; 89340cb5e5dSvi 89440cb5e5dSvi thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 89540cb5e5dSvi SIP_DLG_XCHG_FROM); 89640cb5e5dSvi if (thdr == NULL) 89740cb5e5dSvi return (NULL); 89840cb5e5dSvi alloc_thdr = B_TRUE; 89940cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 90040cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 90140cb5e5dSvi if (chdr == NULL) { 90240cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 90340cb5e5dSvi sip_free_header(thdr); 90440cb5e5dSvi return (NULL); 90540cb5e5dSvi } 90640cb5e5dSvi evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 90740cb5e5dSvi if (evhdr == NULL) { 90840cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 90940cb5e5dSvi sip_free_header(thdr); 91040cb5e5dSvi return (NULL); 91140cb5e5dSvi } 91240cb5e5dSvi substate = sip_search_for_header(sip_msg, 91340cb5e5dSvi SIP_SUBSCRIPTION_STATE, NULL); 91440cb5e5dSvi if (substate == NULL) { 91540cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 91640cb5e5dSvi sip_free_header(thdr); 91740cb5e5dSvi return (NULL); 91840cb5e5dSvi } 91940cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 92040cb5e5dSvi sstate = sip_get_substate((sip_msg_t)sip_msg, &error); 92140cb5e5dSvi if (sstate == NULL || error != 0) { 92240cb5e5dSvi sip_free_header(thdr); 92340cb5e5dSvi return (NULL); 92440cb5e5dSvi } 92540cb5e5dSvi if ((sstate->sip_str_len != strlen("pending") && 92640cb5e5dSvi sstate->sip_str_len != strlen("active")) || 92740cb5e5dSvi ((sstate->sip_str_len == strlen("pending") && 92840cb5e5dSvi strncasecmp(sstate->sip_str_ptr, "pending", 92940cb5e5dSvi strlen("pending")) != 0) || 93040cb5e5dSvi (sstate->sip_str_len == strlen("active") && 93140cb5e5dSvi strncasecmp(sstate->sip_str_ptr, "active", 93240cb5e5dSvi strlen("active")) != 0))) { 93340cb5e5dSvi sip_free_header(thdr); 93440cb5e5dSvi return (NULL); 93540cb5e5dSvi } 93640cb5e5dSvi ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 93740cb5e5dSvi } else { 93840cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 93940cb5e5dSvi thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 94040cb5e5dSvi SIP_DLG_XCHG_TO); 94140cb5e5dSvi alloc_thdr = B_TRUE; 94240cb5e5dSvi } else { 94340cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 94440cb5e5dSvi thdr = sip_search_for_header(sip_msg, SIP_TO, NULL); 94540cb5e5dSvi if (dialog->sip_dlg_remote_target == NULL) { 94640cb5e5dSvi chdr = sip_search_for_header(sip_msg, 94740cb5e5dSvi SIP_CONTACT, NULL); 94840cb5e5dSvi } 94940cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 95040cb5e5dSvi } 95140cb5e5dSvi if (thdr == NULL) { 95240cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 95340cb5e5dSvi return (NULL); 95440cb5e5dSvi } 95540cb5e5dSvi ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL); 95640cb5e5dSvi } 95740cb5e5dSvi if (ttag == NULL) { 95840cb5e5dSvi if (alloc_thdr) 95940cb5e5dSvi sip_free_header(thdr); 96040cb5e5dSvi return (NULL); 96140cb5e5dSvi } 96240cb5e5dSvi prev_state = dialog->sip_dlg_state; 96340cb5e5dSvi 96440cb5e5dSvi if (method == NOTIFY) { 96540cb5e5dSvi int error; 96640cb5e5dSvi const sip_str_t *dlg_id_val = NULL; 96740cb5e5dSvi const sip_str_t *event; 96840cb5e5dSvi const sip_str_t *id_val = NULL; 96940cb5e5dSvi sip_header_value_t ev_val; 97040cb5e5dSvi sip_hdr_value_t *dlg_ev_val = NULL; 97140cb5e5dSvi 97240cb5e5dSvi event = sip_get_event((sip_msg_t)sip_msg, &error); 97340cb5e5dSvi if (event == NULL || error != 0) { 97440cb5e5dSvi sip_free_header(thdr); 97540cb5e5dSvi return (NULL); 97640cb5e5dSvi } 97740cb5e5dSvi ev_val = (sip_header_value_t)sip_get_header_value(evhdr, 97840cb5e5dSvi &error); 97940cb5e5dSvi if (ev_val != NULL) 98040cb5e5dSvi id_val = sip_get_param_value(ev_val, "id", &error); 98140cb5e5dSvi if (error == 0) { 98240cb5e5dSvi dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value( 98340cb5e5dSvi dialog->sip_dlg_event, &error); 98440cb5e5dSvi } 98540cb5e5dSvi if (dlg_ev_val == NULL || error != 0) { 98640cb5e5dSvi sip_free_header(thdr); 98740cb5e5dSvi return (NULL); 98840cb5e5dSvi } 98940cb5e5dSvi dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val, 99040cb5e5dSvi "id", &error); 99140cb5e5dSvi if (error != 0 || 99240cb5e5dSvi dlg_ev_val->str_val_len != event->sip_str_len || 99340cb5e5dSvi strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr, 99440cb5e5dSvi event->sip_str_len != 0)) { 99540cb5e5dSvi sip_free_header(thdr); 99640cb5e5dSvi return (NULL); 99740cb5e5dSvi } 99840cb5e5dSvi if ((dlg_id_val == NULL && id_val != NULL) || 99940cb5e5dSvi (dlg_id_val != NULL && id_val == NULL)) { 100040cb5e5dSvi sip_free_header(thdr); 100140cb5e5dSvi return (NULL); 100240cb5e5dSvi } else if (dlg_id_val != NULL && id_val != NULL) { 100340cb5e5dSvi if (dlg_id_val->sip_str_len != id_val->sip_str_len || 100440cb5e5dSvi strncasecmp(dlg_id_val->sip_str_ptr, 100540cb5e5dSvi id_val->sip_str_ptr, dlg_id_val->sip_str_len) != 100640cb5e5dSvi 0) { 100740cb5e5dSvi sip_free_header(thdr); 100840cb5e5dSvi return (NULL); 100940cb5e5dSvi } 101040cb5e5dSvi } 101140cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 101240cb5e5dSvi dialog->sip_dlg_remote_uri_tag = thdr; 101340cb5e5dSvi if ((dialog->sip_dlg_remote_target = 101440cb5e5dSvi sip_dup_header(chdr)) == NULL) { 101540cb5e5dSvi sip_free_header(thdr); 101640cb5e5dSvi return (NULL); 101740cb5e5dSvi } 101840cb5e5dSvi } else { 101940cb5e5dSvi dialog->sip_dlg_local_uri_tag = thdr; 102040cb5e5dSvi } 102140cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 102240cb5e5dSvi } else { 102340cb5e5dSvi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 102440cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 1025*943efbc3Sgm if (dialog->sip_dlg_state != SIP_DLG_NEW) { 1026*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1027*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 1028*943efbc3Sgm } 102940cb5e5dSvi assert(dialog->sip_dlg_state == SIP_DLG_NEW); 103040cb5e5dSvi if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) { 1031*943efbc3Sgm if (dialog->sip_dlg_type != SIP_UAC_DIALOG) { 1032*943efbc3Sgm sip_write_to_log((void *)dialog, 1033*943efbc3Sgm SIP_DIALOG_LOG | SIP_ASSERT_ERROR, 1034*943efbc3Sgm __FILE__, __LINE__); 1035*943efbc3Sgm } 103640cb5e5dSvi assert(dialog->sip_dlg_type == SIP_UAC_DIALOG); 103740cb5e5dSvi if ((dialog->sip_dlg_remote_target = 103840cb5e5dSvi sip_dup_header(chdr)) == NULL) { 103940cb5e5dSvi (void) pthread_mutex_unlock( 104040cb5e5dSvi &dialog->sip_dlg_mutex); 104140cb5e5dSvi if (alloc_thdr) 104240cb5e5dSvi sip_free_header(thdr); 10432c2c4183Svi goto terminate_new_dlg; 104440cb5e5dSvi } 104540cb5e5dSvi if (sip_dialog_get_route_set(dialog, sip_msg, 104640cb5e5dSvi dialog->sip_dlg_type) != 0) { 104740cb5e5dSvi (void) pthread_mutex_unlock( 104840cb5e5dSvi &dialog->sip_dlg_mutex); 104940cb5e5dSvi if (alloc_thdr) 105040cb5e5dSvi sip_free_header(thdr); 10512c2c4183Svi goto terminate_new_dlg; 105240cb5e5dSvi } 105340cb5e5dSvi } 105440cb5e5dSvi if (SIP_PROVISIONAL_RESP(resp_code)) { 105540cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_EARLY; 105640cb5e5dSvi } else if (SIP_OK_RESP(resp_code)) { 105740cb5e5dSvi /* 105840cb5e5dSvi * Per 12.1 the UAS must include the contact header 105940cb5e5dSvi * for a dialog establishing response, so if we 106040cb5e5dSvi * don't find one, we terminate it. 106140cb5e5dSvi */ 106240cb5e5dSvi if (dialog->sip_dlg_remote_target == NULL) { 106340cb5e5dSvi (void) pthread_mutex_unlock( 106440cb5e5dSvi &dialog->sip_dlg_mutex); 106540cb5e5dSvi if (sip_ulp_dlg_del_cb != NULL) { 106640cb5e5dSvi sip_ulp_dlg_del_cb(dialog, 106740cb5e5dSvi (sip_msg_t)sip_msg, NULL); 106840cb5e5dSvi } 106940cb5e5dSvi if (alloc_thdr) 107040cb5e5dSvi sip_free_header(thdr); 10712c2c4183Svi goto terminate_new_dlg; 107240cb5e5dSvi } 107340cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 107440cb5e5dSvi } else { 107540cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 107640cb5e5dSvi if (sip_ulp_dlg_del_cb != NULL) { 107740cb5e5dSvi sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg, 107840cb5e5dSvi NULL); 107940cb5e5dSvi } 108040cb5e5dSvi if (alloc_thdr) 108140cb5e5dSvi sip_free_header(thdr); 10822c2c4183Svi goto terminate_new_dlg; 108340cb5e5dSvi } 108440cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 108540cb5e5dSvi dialog->sip_dlg_local_uri_tag = thdr; 108640cb5e5dSvi } else { 108740cb5e5dSvi if ((dialog->sip_dlg_remote_uri_tag = 108840cb5e5dSvi sip_dup_header(thdr)) == NULL) { 108940cb5e5dSvi (void) pthread_mutex_unlock( 109040cb5e5dSvi &dialog->sip_dlg_mutex); 10912c2c4183Svi goto terminate_new_dlg; 109240cb5e5dSvi } 109340cb5e5dSvi } 109440cb5e5dSvi } 109540cb5e5dSvi 1096d8a40387Sgm /* 1097d8a40387Sgm * We take the local contact for UAS Dialog from the response (either 1098d8a40387Sgm * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE 1099d8a40387Sgm * request) 1100d8a40387Sgm */ 1101d8a40387Sgm if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state 1102d8a40387Sgm == SIP_DLG_CONFIRMED)) { 1103d8a40387Sgm if (chdr == NULL) { 1104d8a40387Sgm (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 1105d8a40387Sgm chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 1106d8a40387Sgm NULL); 1107d8a40387Sgm (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 1108d8a40387Sgm } 1109d8a40387Sgm if ((chdr == NULL) || ((dialog->sip_dlg_local_contact = 1110d8a40387Sgm sip_dup_header(chdr)) == NULL)) { 1111d8a40387Sgm (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1112d8a40387Sgm if (alloc_thdr) 1113d8a40387Sgm sip_free_header(thdr); 1114d8a40387Sgm goto terminate_new_dlg; 1115d8a40387Sgm } 1116d8a40387Sgm } 1117d8a40387Sgm 111840cb5e5dSvi /* 111940cb5e5dSvi * Cancel the partial dialog timer 112040cb5e5dSvi */ 112140cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 112240cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 112340cb5e5dSvi 112440cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 112540cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_local_uri_tag, 112640cb5e5dSvi &error); 112740cb5e5dSvi } else { 112840cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag, 112940cb5e5dSvi &error); 113040cb5e5dSvi } 1131*943efbc3Sgm if (val == NULL || error != 0) { 1132*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1133*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 1134*943efbc3Sgm } 113540cb5e5dSvi assert(val != NULL && error == 0); 113640cb5e5dSvi remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error); 113740cb5e5dSvi 113840cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_call_id, &error); 113940cb5e5dSvi callid = &((sip_hdr_value_t *)val)->str_val; 114040cb5e5dSvi 114140cb5e5dSvi /* 114240cb5e5dSvi * Get an ID for this dialog 114340cb5e5dSvi */ 114440cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 114540cb5e5dSvi sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len, 114640cb5e5dSvi ttag->sip_str_ptr, ttag->sip_str_len, 114740cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 114840cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 114940cb5e5dSvi } else { 115040cb5e5dSvi sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len, 115140cb5e5dSvi remtag->sip_str_ptr, remtag->sip_str_len, 115240cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 115340cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 115440cb5e5dSvi } 115540cb5e5dSvi 115640cb5e5dSvi SIP_DLG_REFCNT_INCR(dialog); 115740cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 115840cb5e5dSvi 115940cb5e5dSvi /* 116040cb5e5dSvi * Add it to the hash table 116140cb5e5dSvi */ 116240cb5e5dSvi if (sip_hash_add(sip_dialog_hash, (void *)dialog, 116340cb5e5dSvi SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 11642c2c4183Svi terminate_new_dlg: 116540cb5e5dSvi /* 116640cb5e5dSvi * So that sip_dialog_delete() does not try to remove 116740cb5e5dSvi * this from the hash table. 116840cb5e5dSvi */ 116940cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 117040cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 11712c2c4183Svi if (dialog->sip_dlg_local_uri_tag != NULL) { 11722c2c4183Svi sip_free_header(dialog->sip_dlg_local_uri_tag); 11732c2c4183Svi dialog->sip_dlg_local_uri_tag = NULL; 11742c2c4183Svi } 117540cb5e5dSvi } else { 11762c2c4183Svi if (dialog->sip_dlg_remote_uri_tag != NULL) { 11772c2c4183Svi sip_free_header(dialog->sip_dlg_remote_uri_tag); 11782c2c4183Svi dialog->sip_dlg_remote_uri_tag = NULL; 11792c2c4183Svi } 118040cb5e5dSvi } 118140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 118240cb5e5dSvi sip_dialog_terminate(dialog, (sip_msg_t)sip_msg); 118340cb5e5dSvi return (NULL); 118440cb5e5dSvi } 118540cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 118640cb5e5dSvi sip_dlg_ulp_state_cb((sip_dialog_t)dialog, 118740cb5e5dSvi (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state); 118840cb5e5dSvi } 118940cb5e5dSvi return ((sip_dialog_t)dialog); 119040cb5e5dSvi } 119140cb5e5dSvi 119240cb5e5dSvi /* 119340cb5e5dSvi * Check if this dialog is a match. 119440cb5e5dSvi */ 119540cb5e5dSvi boolean_t 119640cb5e5dSvi sip_dialog_match(void *obj, void *hindex) 119740cb5e5dSvi { 119840cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 119940cb5e5dSvi 120040cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 120140cb5e5dSvi if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 120240cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 120340cb5e5dSvi return (B_FALSE); 120440cb5e5dSvi } 120540cb5e5dSvi if (bcmp(dialog->sip_dlg_id, hindex, 120640cb5e5dSvi sizeof (dialog->sip_dlg_id)) == 0) { 120740cb5e5dSvi SIP_DLG_REFCNT_INCR(dialog); 120840cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 120940cb5e5dSvi return (B_TRUE); 121040cb5e5dSvi } 121140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 121240cb5e5dSvi return (B_FALSE); 121340cb5e5dSvi } 121440cb5e5dSvi 121540cb5e5dSvi /* 121640cb5e5dSvi * Don't delete, just take it out of the hash 121740cb5e5dSvi */ 121840cb5e5dSvi boolean_t 121940cb5e5dSvi sip_dialog_dontfree(void *obj, void *hindex, int *found) 122040cb5e5dSvi { 122140cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 122240cb5e5dSvi 122340cb5e5dSvi *found = 0; 122440cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 122540cb5e5dSvi if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 122640cb5e5dSvi == 0) { 122740cb5e5dSvi *found = 1; 122840cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 122940cb5e5dSvi return (B_TRUE); 123040cb5e5dSvi } 123140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 123240cb5e5dSvi return (B_FALSE); 123340cb5e5dSvi } 123440cb5e5dSvi 123540cb5e5dSvi /* 123640cb5e5dSvi * Free resources associated with the dialog, the object will be removed 123740cb5e5dSvi * from the hash list by sip_hash_delete. 123840cb5e5dSvi */ 123940cb5e5dSvi boolean_t 124040cb5e5dSvi sip_dialog_free(void *obj, void *hindex, int *found) 124140cb5e5dSvi { 124240cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 124340cb5e5dSvi 124440cb5e5dSvi *found = 0; 124540cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 124640cb5e5dSvi if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 124740cb5e5dSvi == 0) { 124840cb5e5dSvi *found = 1; 1249*943efbc3Sgm if (dialog->sip_dlg_state != SIP_DLG_DESTROYED) { 1250*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1251*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 1252*943efbc3Sgm } 125340cb5e5dSvi assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED); 125440cb5e5dSvi if (dialog->sip_dlg_ref_cnt != 0) { 125540cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 125640cb5e5dSvi return (B_FALSE); 125740cb5e5dSvi } 1258*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG, NULL, 0); 125940cb5e5dSvi sip_release_dialog_res(dialog); 126040cb5e5dSvi return (B_TRUE); 126140cb5e5dSvi } 126240cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 126340cb5e5dSvi return (B_FALSE); 126440cb5e5dSvi } 126540cb5e5dSvi 126640cb5e5dSvi /* 126740cb5e5dSvi * The UAS will receive the request from the transaction layer. If the 126840cb5e5dSvi * request has a tag in the To header field, the UAS core computes the 126940cb5e5dSvi * dialog identifier corresponding to the request and compares it with 127040cb5e5dSvi * existing dialogs. If there is a match, this is a mid-dialog request. 127140cb5e5dSvi */ 127240cb5e5dSvi sip_dialog_t 127340cb5e5dSvi sip_dialog_find(_sip_msg_t *sip_msg) 127440cb5e5dSvi { 127540cb5e5dSvi const sip_str_t *localtag; 127640cb5e5dSvi const sip_str_t *remtag; 127740cb5e5dSvi const sip_str_t *callid; 127840cb5e5dSvi uint16_t digest[8]; 127940cb5e5dSvi _sip_dialog_t *dialog; 128040cb5e5dSvi boolean_t is_request; 128140cb5e5dSvi int error; 128240cb5e5dSvi 128340cb5e5dSvi is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 128440cb5e5dSvi if (error != 0) 128540cb5e5dSvi return (NULL); 128640cb5e5dSvi if (is_request) { 128740cb5e5dSvi localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 128840cb5e5dSvi if (error == 0) 128940cb5e5dSvi remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 129040cb5e5dSvi } else { 129140cb5e5dSvi remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 129240cb5e5dSvi if (error == 0) 129340cb5e5dSvi localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 129440cb5e5dSvi } 129540cb5e5dSvi if (error != 0) 129640cb5e5dSvi return (NULL); 129740cb5e5dSvi callid = sip_get_callid((sip_msg_t)sip_msg, &error); 129840cb5e5dSvi if (error != 0 || remtag == NULL || localtag == NULL || 129940cb5e5dSvi callid == NULL) { 130040cb5e5dSvi return (NULL); 130140cb5e5dSvi } 130240cb5e5dSvi sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 130340cb5e5dSvi remtag->sip_str_ptr, remtag->sip_str_len, 130440cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 130540cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 130640cb5e5dSvi 130740cb5e5dSvi dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash, 130840cb5e5dSvi (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match); 130940cb5e5dSvi if (dialog == NULL) { 131040cb5e5dSvi sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 131140cb5e5dSvi NULL, 0, callid->sip_str_ptr, callid->sip_str_len, 131240cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 131340cb5e5dSvi dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash, 131440cb5e5dSvi (void *)digest, SIP_DIGEST_TO_HASH(digest), 131540cb5e5dSvi sip_dialog_match); 131640cb5e5dSvi } 131740cb5e5dSvi return ((sip_dialog_t)dialog); 131840cb5e5dSvi } 131940cb5e5dSvi 132040cb5e5dSvi /* 132140cb5e5dSvi * We keep this partial dialog for the duration of the INVITE 132240cb5e5dSvi * transaction timeout duration, i.e. Timer B. 132340cb5e5dSvi */ 132440cb5e5dSvi void 132540cb5e5dSvi sip_dlg_self_destruct(void *args) 132640cb5e5dSvi { 132740cb5e5dSvi sip_dialog_timer_obj_t *tim_obj = (sip_dialog_timer_obj_t *)args; 132840cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)tim_obj->dialog; 132940cb5e5dSvi int index; 133040cb5e5dSvi 133140cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 1332*943efbc3Sgm if (dialog->sip_dlg_state != SIP_DLG_NEW) { 1333*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1334*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 1335*943efbc3Sgm } 133640cb5e5dSvi assert(dialog->sip_dlg_state == SIP_DLG_NEW); 133740cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_DESTROYED; 133840cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 133940cb5e5dSvi index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 134040cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 134140cb5e5dSvi sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id, 134240cb5e5dSvi index, sip_dialog_dontfree); 134340cb5e5dSvi } else { 134440cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 134540cb5e5dSvi } 134640cb5e5dSvi if (tim_obj->func != NULL) 134740cb5e5dSvi tim_obj->func(dialog, NULL, NULL); 134840cb5e5dSvi free(tim_obj); 134940cb5e5dSvi SIP_DLG_REFCNT_DECR(dialog); 135040cb5e5dSvi } 135140cb5e5dSvi 135240cb5e5dSvi /* 135340cb5e5dSvi * Terminate a dialog 135440cb5e5dSvi */ 135540cb5e5dSvi void 135640cb5e5dSvi sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg) 135740cb5e5dSvi { 135840cb5e5dSvi int prev_state; 135940cb5e5dSvi 136040cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 136140cb5e5dSvi prev_state = dialog->sip_dlg_state; 136240cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_DESTROYED; 136340cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 136440cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 136540cb5e5dSvi sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state, 136640cb5e5dSvi dialog->sip_dlg_state); 136740cb5e5dSvi } 136840cb5e5dSvi SIP_DLG_REFCNT_DECR(dialog); 136940cb5e5dSvi } 137040cb5e5dSvi 137140cb5e5dSvi /* 137240cb5e5dSvi * Delete a dialog 137340cb5e5dSvi */ 137440cb5e5dSvi void 137540cb5e5dSvi sip_dialog_delete(_sip_dialog_t *dialog) 137640cb5e5dSvi { 137740cb5e5dSvi int index; 137840cb5e5dSvi 137940cb5e5dSvi /* 138040cb5e5dSvi * partial dialog, not in the hash table 138140cb5e5dSvi */ 138240cb5e5dSvi if (dialog->sip_dlg_local_uri_tag == NULL || 138340cb5e5dSvi dialog->sip_dlg_remote_uri_tag == NULL) { 138440cb5e5dSvi /* 138540cb5e5dSvi * Cancel the partial dialog timer 138640cb5e5dSvi */ 138740cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 138840cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 1389*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG, NULL, 0); 139040cb5e5dSvi sip_release_dialog_res(dialog); 139140cb5e5dSvi return; 139240cb5e5dSvi } 139340cb5e5dSvi index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 139440cb5e5dSvi sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index, 139540cb5e5dSvi sip_dialog_free); 139640cb5e5dSvi } 139740cb5e5dSvi 139840cb5e5dSvi /* 139940cb5e5dSvi * Get the remote target from the CONTACT header from the 200 OK response 140040cb5e5dSvi */ 140140cb5e5dSvi static boolean_t 140240cb5e5dSvi sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg) 140340cb5e5dSvi { 140440cb5e5dSvi sip_header_t chdr; 140540cb5e5dSvi 140640cb5e5dSvi if (dialog->sip_dlg_remote_target != NULL) 140740cb5e5dSvi return (B_TRUE); 140840cb5e5dSvi 140940cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 141040cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 141140cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 141240cb5e5dSvi if (chdr == NULL) 141340cb5e5dSvi return (B_FALSE); 141440cb5e5dSvi if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL) 141540cb5e5dSvi return (B_FALSE); 141640cb5e5dSvi 141740cb5e5dSvi return (B_TRUE); 141840cb5e5dSvi } 141940cb5e5dSvi 142040cb5e5dSvi /* 142140cb5e5dSvi * Process an incoming request/response 142240cb5e5dSvi */ 142340cb5e5dSvi /* ARGSUSED */ 142440cb5e5dSvi int 142540cb5e5dSvi sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog) 142640cb5e5dSvi { 142740cb5e5dSvi boolean_t request; 142840cb5e5dSvi _sip_dialog_t *_dialog; 142940cb5e5dSvi int error; 143040cb5e5dSvi 1431*943efbc3Sgm _dialog = (_sip_dialog_t *)*sip_dialog; 1432*943efbc3Sgm 1433*943efbc3Sgm (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 1434*943efbc3Sgm _dialog->sip_dlg_msgcnt++; 1435*943efbc3Sgm sip_add_log(&_dialog->sip_dlg_log[_dialog->sip_dlg_state], 1436*943efbc3Sgm (sip_msg_t)sip_msg, _dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG); 1437*943efbc3Sgm (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1438*943efbc3Sgm 143940cb5e5dSvi request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 144040cb5e5dSvi if (error != 0) 144140cb5e5dSvi return (EINVAL); 144240cb5e5dSvi if (request) { 144340cb5e5dSvi uint32_t cseq; 144440cb5e5dSvi sip_method_t method; 144540cb5e5dSvi 144640cb5e5dSvi cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error); 144740cb5e5dSvi if (error != 0) 144840cb5e5dSvi return (EINVAL); 144940cb5e5dSvi method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 145040cb5e5dSvi if (error != 0) 145140cb5e5dSvi return (EINVAL); 145240cb5e5dSvi if (sip_get_request_method((sip_msg_t)sip_msg, &error) != 145340cb5e5dSvi method) { 145440cb5e5dSvi return (EINVAL); 145540cb5e5dSvi } 145640cb5e5dSvi (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 145740cb5e5dSvi /* 145840cb5e5dSvi * Requests that do not change in any way the state 145940cb5e5dSvi * of a dialog may be received within a dialog. 146040cb5e5dSvi * They are processed as if they had been received 146140cb5e5dSvi * outside the dialog. 146240cb5e5dSvi * For dialogs that have been established with an 146340cb5e5dSvi * INVITE, the only target refresh request defined is 146440cb5e5dSvi * re-INVITE. 146540cb5e5dSvi */ 146640cb5e5dSvi if (_dialog->sip_dlg_method == INVITE && 146740cb5e5dSvi method == INVITE && _dialog->sip_dlg_remote_cseq != 0 && 146840cb5e5dSvi SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) { 146940cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 147040cb5e5dSvi return (EPROTO); 147140cb5e5dSvi } 147240cb5e5dSvi /* 147340cb5e5dSvi * Target-Refresh request 147440cb5e5dSvi */ 147540cb5e5dSvi if (_dialog->sip_dlg_method == INVITE && method == INVITE) { 147640cb5e5dSvi sip_header_t chdr; 147740cb5e5dSvi sip_header_t nchdr; 147840cb5e5dSvi 147940cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 148040cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 148140cb5e5dSvi NULL); 148240cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 148340cb5e5dSvi if (chdr != NULL && 148440cb5e5dSvi (nchdr = sip_dup_header(chdr)) != NULL) { 148540cb5e5dSvi if (_dialog->sip_dlg_remote_target != NULL) { 148640cb5e5dSvi sip_free_header( 148740cb5e5dSvi _dialog->sip_dlg_remote_target); 148840cb5e5dSvi } 148940cb5e5dSvi _dialog->sip_dlg_remote_target = nchdr; 149040cb5e5dSvi } 149140cb5e5dSvi } 149240cb5e5dSvi _dialog->sip_dlg_remote_cseq = cseq; 149340cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 149440cb5e5dSvi } else { 149540cb5e5dSvi int resp_code; 149640cb5e5dSvi sip_method_t method; 149740cb5e5dSvi int error; 149840cb5e5dSvi 149940cb5e5dSvi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 150040cb5e5dSvi if (error == 0) { 150140cb5e5dSvi method = sip_get_callseq_method((sip_msg_t)sip_msg, 150240cb5e5dSvi &error); 150340cb5e5dSvi } 150440cb5e5dSvi if (error != 0) 150540cb5e5dSvi return (error); 150640cb5e5dSvi 150740cb5e5dSvi (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 15085878c602Sgm if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 15095878c602Sgm (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15105878c602Sgm return (0); 15115878c602Sgm } 1512*943efbc3Sgm if (_dialog->sip_dlg_state != SIP_DLG_EARLY && 1513*943efbc3Sgm _dialog->sip_dlg_state != SIP_DLG_CONFIRMED) { 1514*943efbc3Sgm sip_write_to_log((void *)_dialog, SIP_DIALOG_LOG | 1515*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 1516*943efbc3Sgm } 151740cb5e5dSvi assert(_dialog->sip_dlg_state == SIP_DLG_EARLY || 151840cb5e5dSvi _dialog->sip_dlg_state == SIP_DLG_CONFIRMED); 151940cb5e5dSvi /* 152040cb5e5dSvi * Let the user delete the dialog if it is not a 1XX/2XX resp 152140cb5e5dSvi * for an early INVITE dialog. 152240cb5e5dSvi */ 152340cb5e5dSvi if (SIP_OK_RESP(resp_code)) { 152440cb5e5dSvi if (method == INVITE) { 152540cb5e5dSvi if (!sip_get_rtarg(_dialog, sip_msg)) { 152640cb5e5dSvi (void) pthread_mutex_unlock( 152740cb5e5dSvi &_dialog->sip_dlg_mutex); 152840cb5e5dSvi if (sip_ulp_dlg_del_cb != NULL) { 152940cb5e5dSvi sip_ulp_dlg_del_cb( 153040cb5e5dSvi (sip_dialog_t)_dialog, 153140cb5e5dSvi (sip_msg_t)sip_msg, NULL); 153240cb5e5dSvi } 153340cb5e5dSvi sip_dialog_terminate(_dialog, 153440cb5e5dSvi (sip_msg_t)sip_msg); 153540cb5e5dSvi return (0); 153640cb5e5dSvi } 153740cb5e5dSvi if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 153840cb5e5dSvi _dialog->sip_dlg_state = 153940cb5e5dSvi SIP_DLG_CONFIRMED; 154040cb5e5dSvi (void) sip_dlg_recompute_rset(_dialog, 154140cb5e5dSvi sip_msg, SIP_UAC_DIALOG); 1542*943efbc3Sgm (void) pthread_mutex_unlock( 1543*943efbc3Sgm &_dialog->sip_dlg_mutex); 154440cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 154540cb5e5dSvi sip_dlg_ulp_state_cb( 154640cb5e5dSvi (sip_dialog_t)_dialog, 154740cb5e5dSvi sip_msg, SIP_DLG_EARLY, 154840cb5e5dSvi _dialog->sip_dlg_state); 154940cb5e5dSvi } 155040cb5e5dSvi return (0); 1551d8a40387Sgm } else if (_dialog->sip_dlg_new_local_contact 1552d8a40387Sgm != NULL) { 1553*943efbc3Sgm if (_dialog->sip_dlg_local_contact == 1554*943efbc3Sgm NULL) { 1555*943efbc3Sgm (void) sip_write_to_log((void *) 1556*943efbc3Sgm _dialog, SIP_DIALOG_LOG | 1557*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, 1558*943efbc3Sgm __LINE__); 1559*943efbc3Sgm } 1560d8a40387Sgm assert(_dialog->sip_dlg_local_contact 1561d8a40387Sgm != NULL); 1562d8a40387Sgm sip_free_header(_dialog-> 1563111456ccSgm sip_dlg_local_contact); 1564d8a40387Sgm _dialog->sip_dlg_local_contact = 1565d8a40387Sgm _dialog->sip_dlg_new_local_contact; 1566d8a40387Sgm _dialog->sip_dlg_new_local_contact = 1567d8a40387Sgm NULL; 156840cb5e5dSvi } 156940cb5e5dSvi } 157040cb5e5dSvi } 157140cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 157240cb5e5dSvi } 157340cb5e5dSvi return (0); 157440cb5e5dSvi } 157540cb5e5dSvi 157640cb5e5dSvi /* 157740cb5e5dSvi * Copy partial dialog to create a complete dialog 157840cb5e5dSvi */ 157940cb5e5dSvi _sip_dialog_t * 158040cb5e5dSvi sip_copy_partial_dialog(_sip_dialog_t *dialog) 158140cb5e5dSvi { 158240cb5e5dSvi _sip_dialog_t *new_dlg; 158340cb5e5dSvi 158440cb5e5dSvi new_dlg = calloc(1, sizeof (_sip_dialog_t)); 158540cb5e5dSvi if (new_dlg == NULL) 158640cb5e5dSvi return (NULL); 158740cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 158840cb5e5dSvi new_dlg->sip_dlg_req_uri.sip_str_ptr = 158940cb5e5dSvi malloc(dialog->sip_dlg_req_uri.sip_str_len + 1); 159040cb5e5dSvi if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) { 159140cb5e5dSvi free(new_dlg); 159240cb5e5dSvi return (NULL); 159340cb5e5dSvi } 159440cb5e5dSvi (void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr, 159540cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr, 159640cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len); 159740cb5e5dSvi new_dlg->sip_dlg_req_uri.sip_str_ptr[ 159840cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len] = '\0'; 159940cb5e5dSvi new_dlg->sip_dlg_req_uri.sip_str_len = 160040cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len; 160140cb5e5dSvi } 160240cb5e5dSvi if (dialog->sip_dlg_route_set != NULL) { 1603*943efbc3Sgm if (dialog->sip_dlg_rset.sip_str_ptr == NULL) { 1604*943efbc3Sgm sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1605*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 1606*943efbc3Sgm } 160740cb5e5dSvi assert(dialog->sip_dlg_rset.sip_str_ptr != NULL); 160840cb5e5dSvi new_dlg->sip_dlg_rset.sip_str_ptr = 160940cb5e5dSvi malloc(dialog->sip_dlg_rset.sip_str_len + 1); 161040cb5e5dSvi if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) { 161140cb5e5dSvi if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 161240cb5e5dSvi free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 161340cb5e5dSvi free(new_dlg); 161440cb5e5dSvi return (NULL); 161540cb5e5dSvi } 161640cb5e5dSvi (void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr, 161740cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr, 161840cb5e5dSvi dialog->sip_dlg_rset.sip_str_len); 161940cb5e5dSvi new_dlg->sip_dlg_rset.sip_str_ptr[ 162040cb5e5dSvi dialog->sip_dlg_rset.sip_str_len] = '\0'; 162140cb5e5dSvi new_dlg->sip_dlg_rset.sip_str_len = 162240cb5e5dSvi dialog->sip_dlg_rset.sip_str_len; 162340cb5e5dSvi 162440cb5e5dSvi new_dlg->sip_dlg_route_set = 162540cb5e5dSvi sip_dup_header(dialog->sip_dlg_route_set); 162640cb5e5dSvi if (new_dlg->sip_dlg_route_set == NULL) { 162740cb5e5dSvi free(new_dlg->sip_dlg_rset.sip_str_ptr); 162840cb5e5dSvi if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 162940cb5e5dSvi free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 163040cb5e5dSvi free(new_dlg); 163140cb5e5dSvi return (NULL); 163240cb5e5dSvi } 163340cb5e5dSvi } 163440cb5e5dSvi if ((new_dlg->sip_dlg_local_uri_tag = 163540cb5e5dSvi sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL || 163640cb5e5dSvi (new_dlg->sip_dlg_remote_target = 163740cb5e5dSvi sip_dup_header(dialog->sip_dlg_remote_target)) == NULL || 1638d8a40387Sgm (new_dlg->sip_dlg_local_contact = 1639d8a40387Sgm sip_dup_header(dialog->sip_dlg_local_contact)) == NULL || 164040cb5e5dSvi (new_dlg->sip_dlg_call_id = 164140cb5e5dSvi sip_dup_header(dialog->sip_dlg_call_id)) == NULL) { 164240cb5e5dSvi sip_release_dialog_res(new_dlg); 164340cb5e5dSvi return (NULL); 164440cb5e5dSvi } 164540cb5e5dSvi if (dialog->sip_dlg_event != NULL) { 164640cb5e5dSvi new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event); 164740cb5e5dSvi if (new_dlg->sip_dlg_event == NULL) { 164840cb5e5dSvi sip_release_dialog_res(new_dlg); 164940cb5e5dSvi return (NULL); 165040cb5e5dSvi } 165140cb5e5dSvi } 165240cb5e5dSvi new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq; 165340cb5e5dSvi new_dlg->sip_dlg_type = dialog->sip_dlg_type; 165440cb5e5dSvi new_dlg->sip_dlg_on_fork = B_FALSE; 165540cb5e5dSvi (void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL); 165640cb5e5dSvi 165740cb5e5dSvi return (new_dlg); 165840cb5e5dSvi } 165940cb5e5dSvi 166040cb5e5dSvi /* 166140cb5e5dSvi * Update the dialog using the response 166240cb5e5dSvi */ 166340cb5e5dSvi sip_dialog_t 166440cb5e5dSvi sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg) 166540cb5e5dSvi { 166640cb5e5dSvi _sip_dialog_t *_dialog; 166740cb5e5dSvi boolean_t isreq; 166840cb5e5dSvi sip_method_t method; 166940cb5e5dSvi int resp_code = 0; 167040cb5e5dSvi int prev_state; 167140cb5e5dSvi boolean_t decr_ref = B_FALSE; 167240cb5e5dSvi int error; 167340cb5e5dSvi 1674*943efbc3Sgm _dialog = (_sip_dialog_t *)dialog; 1675*943efbc3Sgm (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 1676*943efbc3Sgm _dialog->sip_dlg_msgcnt++; 1677*943efbc3Sgm sip_add_log(&_dialog->sip_dlg_log[_dialog->sip_dlg_state], 1678*943efbc3Sgm (sip_msg_t)sip_msg, _dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG); 1679*943efbc3Sgm (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1680*943efbc3Sgm 168140cb5e5dSvi isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error); 168240cb5e5dSvi if (error != 0) 168340cb5e5dSvi return (dialog); 168440cb5e5dSvi (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 168540cb5e5dSvi if (isreq) { 168640cb5e5dSvi method = sip_get_request_method((sip_msg_t)sip_msg, &error); 168740cb5e5dSvi if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE || 168840cb5e5dSvi method != NOTIFY) { 168940cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 169040cb5e5dSvi return (dialog); 169140cb5e5dSvi } 169240cb5e5dSvi } else { 169340cb5e5dSvi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 169440cb5e5dSvi if (error != 0) { 169540cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 169640cb5e5dSvi return (dialog); 169740cb5e5dSvi } 1698d8a40387Sgm method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 1699d8a40387Sgm if (error != 0) { 1700d8a40387Sgm (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1701d8a40387Sgm return (dialog); 1702d8a40387Sgm } 170340cb5e5dSvi } 170440cb5e5dSvi prev_state = _dialog->sip_dlg_state; 170540cb5e5dSvi if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) { 170640cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 170740cb5e5dSvi } else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 170840cb5e5dSvi /* 170940cb5e5dSvi * Let the user delete the dialog if it is not a 1XX/2XX resp 171040cb5e5dSvi * for an early dialog. 171140cb5e5dSvi */ 1712*943efbc3Sgm if (isreq) { 1713*943efbc3Sgm sip_write_to_log((void *)_dialog, SIP_DIALOG_LOG | 1714*943efbc3Sgm SIP_ASSERT_ERROR, __FILE__, __LINE__); 1715*943efbc3Sgm } 171640cb5e5dSvi assert(!isreq); 171740cb5e5dSvi if (SIP_OK_RESP(resp_code)) { 171840cb5e5dSvi _dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 1719d8a40387Sgm /* 1720d8a40387Sgm * If we recieved provisional response before we would 1721d8a40387Sgm * not have captured local contact. So store it now. 1722d8a40387Sgm */ 1723d8a40387Sgm if (_dialog->sip_dlg_type == SIP_UAS_DIALOG && _dialog-> 1724d8a40387Sgm sip_dlg_method == INVITE && method == INVITE) { 1725d8a40387Sgm sip_header_t chdr; 1726d8a40387Sgm (void) pthread_mutex_lock(&sip_msg-> 1727d8a40387Sgm sip_msg_mutex); 1728d8a40387Sgm chdr = sip_search_for_header(sip_msg, 1729d8a40387Sgm SIP_CONTACT, NULL); 1730d8a40387Sgm (void) pthread_mutex_unlock(&sip_msg-> 1731d8a40387Sgm sip_msg_mutex); 1732d8a40387Sgm if (chdr != NULL) { 1733d8a40387Sgm _dialog->sip_dlg_local_contact 1734d8a40387Sgm = sip_dup_header(chdr); 1735d8a40387Sgm _dialog->sip_dlg_new_local_contact = 1736d8a40387Sgm NULL; 1737d8a40387Sgm } 1738d8a40387Sgm } 173940cb5e5dSvi (void) sip_dlg_recompute_rset(_dialog, sip_msg, 174040cb5e5dSvi SIP_UAS_DIALOG); 1741*943efbc3Sgm (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 174240cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 174340cb5e5dSvi sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg, 174440cb5e5dSvi prev_state, dialog->sip_dlg_state); 174540cb5e5dSvi } 174640cb5e5dSvi } else { 174740cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 174840cb5e5dSvi } 174940cb5e5dSvi } else if (_dialog->sip_dlg_state == SIP_DLG_NEW) { 175040cb5e5dSvi if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE && 175140cb5e5dSvi SIP_PROVISIONAL_RESP(resp_code)) { 175240cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 175340cb5e5dSvi return (dialog); 175440cb5e5dSvi } 175540cb5e5dSvi if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) { 175640cb5e5dSvi _sip_dialog_t *new_dlg; 175740cb5e5dSvi 175840cb5e5dSvi if (_dialog->sip_dlg_on_fork) { 175940cb5e5dSvi new_dlg = sip_copy_partial_dialog(_dialog); 176040cb5e5dSvi if (new_dlg == NULL) { 176140cb5e5dSvi (void) pthread_mutex_unlock( 176240cb5e5dSvi &_dialog->sip_dlg_mutex); 176340cb5e5dSvi return (dialog); 176440cb5e5dSvi } 176540cb5e5dSvi /* 176640cb5e5dSvi * This decr/incr dance is because the caller 176740cb5e5dSvi * has incremented the ref on the partial 176840cb5e5dSvi * dialog, we release it here and incr the 176940cb5e5dSvi * ref on the new dialog which will be 177040cb5e5dSvi * released by the caller. 177140cb5e5dSvi */ 177240cb5e5dSvi (void) pthread_mutex_unlock( 177340cb5e5dSvi &_dialog->sip_dlg_mutex); 177440cb5e5dSvi SIP_DLG_REFCNT_DECR(_dialog); 177540cb5e5dSvi _dialog = new_dlg; 177640cb5e5dSvi (void) pthread_mutex_lock( 177740cb5e5dSvi &_dialog->sip_dlg_mutex); 177840cb5e5dSvi SIP_DLG_REFCNT_INCR(_dialog); 177940cb5e5dSvi } else { 178040cb5e5dSvi int index; 178140cb5e5dSvi 178240cb5e5dSvi /* 178340cb5e5dSvi * take it out of the list so that further 178440cb5e5dSvi * responses will not result in a dialog. 178540cb5e5dSvi * We will have an extra refcount when we 178640cb5e5dSvi * come back from sip_complete_dialog(), i.e. 178740cb5e5dSvi * one when the partial dialog was created - 178840cb5e5dSvi * in sip_seed_dialog(), one held by the caller 178940cb5e5dSvi * and one that will be added by 179040cb5e5dSvi * sip_complete_dialog(). We need to release 179140cb5e5dSvi * the one added by the sip_seed_dialog(), 179240cb5e5dSvi * since the one in sip_complete_dialog() 179340cb5e5dSvi * is for the same purpose. 179440cb5e5dSvi */ 179540cb5e5dSvi if (SIP_IS_TIMER_RUNNING( 179640cb5e5dSvi _dialog->sip_dlg_timer)) { 179740cb5e5dSvi SIP_CANCEL_TIMER( 179840cb5e5dSvi _dialog->sip_dlg_timer); 179940cb5e5dSvi } 180040cb5e5dSvi index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 180140cb5e5dSvi (void) pthread_mutex_unlock( 180240cb5e5dSvi &_dialog->sip_dlg_mutex); 180340cb5e5dSvi sip_hash_delete(sip_dialog_phash, 180440cb5e5dSvi (void *)_dialog->sip_dlg_id, 180540cb5e5dSvi index, sip_dialog_dontfree); 180640cb5e5dSvi (void) pthread_mutex_lock( 180740cb5e5dSvi &_dialog->sip_dlg_mutex); 180840cb5e5dSvi decr_ref = B_TRUE; 180940cb5e5dSvi } 181040cb5e5dSvi } else { 181140cb5e5dSvi decr_ref = B_TRUE; 181240cb5e5dSvi } 181340cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 181440cb5e5dSvi if ((dialog = sip_complete_dialog(sip_msg, _dialog)) == 181540cb5e5dSvi NULL) { 18162c2c4183Svi if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref) 18172c2c4183Svi SIP_DLG_REFCNT_DECR(_dialog); 181840cb5e5dSvi return (NULL); 181940cb5e5dSvi } 182040cb5e5dSvi if (decr_ref) 182140cb5e5dSvi SIP_DLG_REFCNT_DECR(_dialog); 182240cb5e5dSvi } else { 182340cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 182440cb5e5dSvi } 182540cb5e5dSvi return (dialog); 182640cb5e5dSvi } 182740cb5e5dSvi 182840cb5e5dSvi /* 182940cb5e5dSvi * Initialize the hash table 183040cb5e5dSvi */ 183140cb5e5dSvi void 183240cb5e5dSvi sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *), 183340cb5e5dSvi void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int)) 183440cb5e5dSvi { 183540cb5e5dSvi int cnt; 183640cb5e5dSvi 183740cb5e5dSvi for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) { 183840cb5e5dSvi sip_dialog_hash[cnt].hash_count = 0; 183940cb5e5dSvi sip_dialog_hash[cnt].hash_head = NULL; 184040cb5e5dSvi sip_dialog_hash[cnt].hash_tail = NULL; 184140cb5e5dSvi (void) pthread_mutex_init( 184240cb5e5dSvi &sip_dialog_hash[cnt].sip_hash_mutex, NULL); 184340cb5e5dSvi sip_dialog_phash[cnt].hash_count = 0; 184440cb5e5dSvi sip_dialog_phash[cnt].hash_head = NULL; 184540cb5e5dSvi sip_dialog_phash[cnt].hash_tail = NULL; 184640cb5e5dSvi (void) pthread_mutex_init( 184740cb5e5dSvi &sip_dialog_phash[cnt].sip_hash_mutex, NULL); 184840cb5e5dSvi } 184940cb5e5dSvi if (ulp_dlg_del != NULL) 185040cb5e5dSvi sip_ulp_dlg_del_cb = ulp_dlg_del; 185140cb5e5dSvi 185240cb5e5dSvi if (ulp_state_cb != NULL) 185340cb5e5dSvi sip_dlg_ulp_state_cb = ulp_state_cb; 185440cb5e5dSvi } 1855d8a40387Sgm 1856d8a40387Sgm /* 1857d8a40387Sgm * Copy the new contact header of re-INVITE 1858d8a40387Sgm */ 1859d8a40387Sgm void 1860d8a40387Sgm sip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg) 1861d8a40387Sgm { 1862d8a40387Sgm sip_header_t chdr = NULL; 1863d8a40387Sgm sip_header_t nhdr = NULL; 1864d8a40387Sgm 1865d8a40387Sgm (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 1866d8a40387Sgm chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 1867d8a40387Sgm (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 1868d8a40387Sgm 1869d8a40387Sgm if (chdr == NULL) 1870d8a40387Sgm return; 1871d8a40387Sgm 1872d8a40387Sgm (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 1873d8a40387Sgm if (dialog->sip_dlg_method != INVITE || dialog->sip_dlg_state 1874d8a40387Sgm != SIP_DLG_CONFIRMED) { 1875d8a40387Sgm (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1876d8a40387Sgm return; 1877d8a40387Sgm } 1878d8a40387Sgm 1879d8a40387Sgm if (((nhdr = sip_dup_header(chdr)) != NULL)) { 1880d8a40387Sgm if (dialog->sip_dlg_new_local_contact != NULL) 1881d8a40387Sgm sip_free_header(dialog->sip_dlg_new_local_contact); 1882d8a40387Sgm dialog->sip_dlg_new_local_contact = nhdr; 1883d8a40387Sgm } 1884d8a40387Sgm (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1885d8a40387Sgm } 1886*943efbc3Sgm 1887*943efbc3Sgm /* 1888*943efbc3Sgm * Given a state, return the string - This is mostly for debug purposes 1889*943efbc3Sgm */ 1890*943efbc3Sgm char * 1891*943efbc3Sgm sip_get_dialog_state_str(int state) 1892*943efbc3Sgm { 1893*943efbc3Sgm switch (state) { 1894*943efbc3Sgm case SIP_DLG_NEW: 1895*943efbc3Sgm return ("SIP_DLG_NEW"); 1896*943efbc3Sgm case SIP_DLG_EARLY: 1897*943efbc3Sgm return ("SIP_DLG_EARLY"); 1898*943efbc3Sgm case SIP_DLG_CONFIRMED: 1899*943efbc3Sgm return ("SIP_DLG_CONFIRMED"); 1900*943efbc3Sgm case SIP_DLG_DESTROYED: 1901*943efbc3Sgm return ("SIP_DLG_DESTROYED"); 1902*943efbc3Sgm default: 1903*943efbc3Sgm return ("UNKNOWN"); 1904*943efbc3Sgm } 1905*943efbc3Sgm } 1906