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 /* 232c2c4183Svi * Copyright 2007 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 { 11140cb5e5dSvi 11240cb5e5dSvi assert(dialog->sip_dlg_ref_cnt == 0); 11340cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 11440cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 11540cb5e5dSvi if (dialog->sip_dlg_call_id != NULL) 11640cb5e5dSvi sip_free_header(dialog->sip_dlg_call_id); 11740cb5e5dSvi if (dialog->sip_dlg_local_uri_tag != NULL) 11840cb5e5dSvi sip_free_header(dialog->sip_dlg_local_uri_tag); 11940cb5e5dSvi if (dialog->sip_dlg_remote_uri_tag != NULL) 12040cb5e5dSvi sip_free_header(dialog->sip_dlg_remote_uri_tag); 12140cb5e5dSvi if (dialog->sip_dlg_remote_target != NULL) 12240cb5e5dSvi sip_free_header(dialog->sip_dlg_remote_target); 123*d8a40387Sgm if (dialog->sip_dlg_local_contact != NULL) 124*d8a40387Sgm sip_free_header(dialog->sip_dlg_local_contact); 125*d8a40387Sgm if (dialog->sip_dlg_new_local_contact != NULL) 126*d8a40387Sgm sip_free_header(dialog->sip_dlg_new_local_contact); 12740cb5e5dSvi if (dialog->sip_dlg_route_set != NULL) 12840cb5e5dSvi sip_free_header(dialog->sip_dlg_route_set); 12940cb5e5dSvi if (dialog->sip_dlg_event != NULL) 13040cb5e5dSvi sip_free_header(dialog->sip_dlg_event); 13140cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 13240cb5e5dSvi free(dialog->sip_dlg_req_uri.sip_str_ptr); 13340cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 13440cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 0; 13540cb5e5dSvi } 13640cb5e5dSvi if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 13740cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 13840cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 13940cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 14040cb5e5dSvi } 14140cb5e5dSvi (void) pthread_mutex_destroy(&dialog->sip_dlg_mutex); 14240cb5e5dSvi free(dialog); 14340cb5e5dSvi } 14440cb5e5dSvi 14540cb5e5dSvi /* 14640cb5e5dSvi * Get the route information from the 'value' and add it to the route 14740cb5e5dSvi * set. 14840cb5e5dSvi */ 14940cb5e5dSvi static sip_dlg_route_set_t * 15040cb5e5dSvi sip_add_route_to_set(sip_hdr_value_t *value) 15140cb5e5dSvi { 15240cb5e5dSvi int vlen = 0; 15340cb5e5dSvi sip_dlg_route_set_t *rset; 15440cb5e5dSvi char *crlf; 15540cb5e5dSvi const sip_param_t *uri_param; 15640cb5e5dSvi int error; 15740cb5e5dSvi 15840cb5e5dSvi rset = calloc(1, sizeof (*rset)); 15940cb5e5dSvi if (rset == NULL) 16040cb5e5dSvi return (NULL); 16140cb5e5dSvi rset->sip_dlg_route_next = NULL; 16240cb5e5dSvi vlen = value->sip_value_end - value->sip_value_start; 16340cb5e5dSvi 16440cb5e5dSvi /* 16540cb5e5dSvi * check for CRLF 16640cb5e5dSvi */ 16740cb5e5dSvi crlf = value->sip_value_end - strlen(SIP_CRLF); 16840cb5e5dSvi while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 16940cb5e5dSvi vlen -= strlen(SIP_CRLF); 17040cb5e5dSvi crlf -= strlen(SIP_CRLF); 17140cb5e5dSvi } 17240cb5e5dSvi rset->sip_dlg_route = calloc(1, vlen + 1); 17340cb5e5dSvi if (rset->sip_dlg_route == NULL) { 17440cb5e5dSvi free(rset); 17540cb5e5dSvi return (NULL); 17640cb5e5dSvi } 17740cb5e5dSvi /* 17840cb5e5dSvi * loose routing 17940cb5e5dSvi */ 18040cb5e5dSvi rset->sip_dlg_route_lr = B_FALSE; 18140cb5e5dSvi (void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen); 18240cb5e5dSvi rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route + 18340cb5e5dSvi (value->cftr_uri.sip_str_ptr - value->sip_value_start); 18440cb5e5dSvi rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len; 18540cb5e5dSvi rset->sip_dlg_route[vlen] = '\0'; 18640cb5e5dSvi 18740cb5e5dSvi assert(value->sip_value_parsed_uri != NULL); 18840cb5e5dSvi /* 18940cb5e5dSvi * Check if the 'lr' param is present for this route. 19040cb5e5dSvi */ 19140cb5e5dSvi uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error); 19240cb5e5dSvi if (error != 0) { 19340cb5e5dSvi free(rset->sip_dlg_route); 19440cb5e5dSvi free(rset); 19540cb5e5dSvi return (NULL); 19640cb5e5dSvi } 19740cb5e5dSvi if (uri_param != NULL) { 19840cb5e5dSvi rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr", 19940cb5e5dSvi strlen("lr")); 20040cb5e5dSvi } 20140cb5e5dSvi return (rset); 20240cb5e5dSvi } 20340cb5e5dSvi 20440cb5e5dSvi /* 20540cb5e5dSvi * Depending on the route-set, determine the request URI. 20640cb5e5dSvi */ 20740cb5e5dSvi char * 20840cb5e5dSvi sip_dialog_req_uri(sip_dialog_t dialog) 20940cb5e5dSvi { 21040cb5e5dSvi const sip_str_t *req_uri; 21140cb5e5dSvi char *uri; 21240cb5e5dSvi _sip_dialog_t *_dialog; 21340cb5e5dSvi 21440cb5e5dSvi _dialog = (_sip_dialog_t *)dialog; 21540cb5e5dSvi if (_dialog->sip_dlg_route_set == NULL || 21640cb5e5dSvi _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 21740cb5e5dSvi const struct sip_value *val; 21840cb5e5dSvi 21940cb5e5dSvi val = sip_get_header_value(_dialog->sip_dlg_remote_target, 22040cb5e5dSvi NULL); 22140cb5e5dSvi if (val == NULL) 22240cb5e5dSvi return (NULL); 22340cb5e5dSvi req_uri = &((sip_hdr_value_t *)val)->cftr_uri; 22440cb5e5dSvi } else { 22540cb5e5dSvi req_uri = &_dialog->sip_dlg_req_uri; 22640cb5e5dSvi } 22740cb5e5dSvi uri = (char *)malloc(req_uri->sip_str_len + 1); 22840cb5e5dSvi if (uri == NULL) 22940cb5e5dSvi return (NULL); 23040cb5e5dSvi (void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len); 23140cb5e5dSvi uri[req_uri->sip_str_len] = '\0'; 23240cb5e5dSvi 23340cb5e5dSvi return (uri); 23440cb5e5dSvi } 23540cb5e5dSvi 23640cb5e5dSvi /* 23740cb5e5dSvi * Free the route set. 23840cb5e5dSvi */ 23940cb5e5dSvi void 24040cb5e5dSvi sip_dialog_free_rset(sip_dlg_route_set_t *rset) 24140cb5e5dSvi { 24240cb5e5dSvi sip_dlg_route_set_t *next; 24340cb5e5dSvi 24440cb5e5dSvi while (rset != NULL) { 24540cb5e5dSvi next = rset->sip_dlg_route_next; 24640cb5e5dSvi rset->sip_dlg_route_next = NULL; 24740cb5e5dSvi free(rset->sip_dlg_route); 24840cb5e5dSvi free(rset); 24940cb5e5dSvi rset = next; 25040cb5e5dSvi } 25140cb5e5dSvi } 25240cb5e5dSvi 25340cb5e5dSvi /* 25440cb5e5dSvi * Recompute route-set 25540cb5e5dSvi */ 25640cb5e5dSvi static int 25740cb5e5dSvi sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 25840cb5e5dSvi { 25940cb5e5dSvi int ret; 26040cb5e5dSvi 26140cb5e5dSvi if (dialog->sip_dlg_route_set != NULL) { 26240cb5e5dSvi sip_free_header(dialog->sip_dlg_route_set); 26340cb5e5dSvi dialog->sip_dlg_route_set = NULL; 26440cb5e5dSvi } 26540cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 26640cb5e5dSvi free(dialog->sip_dlg_req_uri.sip_str_ptr); 26740cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 26840cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 0; 26940cb5e5dSvi } 27040cb5e5dSvi if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 27140cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 27240cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 27340cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 27440cb5e5dSvi } 27540cb5e5dSvi ret = sip_dialog_get_route_set(dialog, sip_msg, what); 27640cb5e5dSvi return (ret); 27740cb5e5dSvi } 27840cb5e5dSvi 27940cb5e5dSvi /* 28040cb5e5dSvi * If the route set is empty, the UAC MUST place the remote target URI 28140cb5e5dSvi * into the Request-URI. The UAC MUST NOT add a Route header field to 28240cb5e5dSvi * the request. 28340cb5e5dSvi * 28440cb5e5dSvi * If the route set is not empty, and the first URI in the route set 28540cb5e5dSvi * contains the lr parameter (see Section 19.1.1), the UAC MUST place 28640cb5e5dSvi * the remote target URI into the Request-URI and MUST include a Route 28740cb5e5dSvi * header field containing the route set values in order, including all 28840cb5e5dSvi * parameters. 28940cb5e5dSvi * 29040cb5e5dSvi * If the route set is not empty, and its first URI does not contain the 29140cb5e5dSvi * lr parameter, the UAC MUST place the first URI from the route set 29240cb5e5dSvi * into the Request-URI, stripping any parameters that are not allowed 29340cb5e5dSvi * in a Request-URI. The UAC MUST add a Route header field containing 29440cb5e5dSvi * the remainder of the route set values in order, including all 29540cb5e5dSvi * parameters. The UAC MUST then place the remote target URI into the 29640cb5e5dSvi * Route header field as the last value. 29740cb5e5dSvi */ 29840cb5e5dSvi int 29940cb5e5dSvi sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head, 30040cb5e5dSvi int rcnt, int rlen) 30140cb5e5dSvi { 30240cb5e5dSvi size_t rset_len; 30340cb5e5dSvi _sip_header_t *rhdr; 30440cb5e5dSvi char *rset; 30540cb5e5dSvi char *rp; 30640cb5e5dSvi char *rsp; 30740cb5e5dSvi int count; 30840cb5e5dSvi sip_dlg_route_set_t *route; 30940cb5e5dSvi boolean_t first = B_TRUE; 31040cb5e5dSvi const sip_str_t *to_uri; 31140cb5e5dSvi char *uri = NULL; 31240cb5e5dSvi int rspl; 31340cb5e5dSvi int rpl; 31440cb5e5dSvi 31540cb5e5dSvi assert(rcnt > 0); 31640cb5e5dSvi 31740cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1; 31840cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt); 31940cb5e5dSvi if (dialog->sip_dlg_rset.sip_str_ptr == NULL) 32040cb5e5dSvi return (ENOMEM); 32140cb5e5dSvi rsp = dialog->sip_dlg_rset.sip_str_ptr; 32240cb5e5dSvi rspl = rlen + rcnt; 32340cb5e5dSvi route = rset_head; 32440cb5e5dSvi rset_len = rlen; 32540cb5e5dSvi if (!route->sip_dlg_route_lr) { 32640cb5e5dSvi const struct sip_value *val; 32740cb5e5dSvi 32840cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL); 32940cb5e5dSvi to_uri = &((sip_hdr_value_t *)val)->cftr_uri; 33040cb5e5dSvi uri = (char *)malloc(to_uri->sip_str_len + 1); 33140cb5e5dSvi if (uri == NULL) { 33240cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 33340cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 33440cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 33540cb5e5dSvi return (ENOMEM); 33640cb5e5dSvi } 33740cb5e5dSvi (void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len); 33840cb5e5dSvi uri[to_uri->sip_str_len] = '\0'; 33940cb5e5dSvi rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) + 34040cb5e5dSvi SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN + 34140cb5e5dSvi sizeof (char); 34240cb5e5dSvi count = snprintf(rsp, rspl, "%s", route->sip_dlg_route); 34340cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = malloc( 34440cb5e5dSvi route->sip_dlg_ruri.sip_str_len + 1); 34540cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 34640cb5e5dSvi free(uri); 34740cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 34840cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 34940cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 35040cb5e5dSvi return (ENOMEM); 35140cb5e5dSvi } 35240cb5e5dSvi (void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp + 35340cb5e5dSvi (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route), 35440cb5e5dSvi route->sip_dlg_ruri.sip_str_len); 35540cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr[ 35640cb5e5dSvi route->sip_dlg_ruri.sip_str_len] = '\0'; 35740cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 35840cb5e5dSvi route->sip_dlg_ruri.sip_str_len; 35940cb5e5dSvi 36040cb5e5dSvi rsp += count; 36140cb5e5dSvi rspl -= count; 36240cb5e5dSvi route = route->sip_dlg_route_next; 36340cb5e5dSvi } 36440cb5e5dSvi 36540cb5e5dSvi /* 36640cb5e5dSvi * rcnt - 1 is for the number of COMMAs 36740cb5e5dSvi */ 36840cb5e5dSvi rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) + 36940cb5e5dSvi SIP_SPACE_LEN + rcnt - 1; 37040cb5e5dSvi rset = malloc(rset_len + 1); 37140cb5e5dSvi if (rset == NULL) { 37240cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 37340cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 37440cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 37540cb5e5dSvi return (ENOMEM); 37640cb5e5dSvi } 37740cb5e5dSvi rhdr = sip_new_header(rset_len + strlen(SIP_CRLF)); 37840cb5e5dSvi if (rhdr == NULL) { 37940cb5e5dSvi free(rset); 38040cb5e5dSvi free(dialog->sip_dlg_rset.sip_str_ptr); 38140cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 38240cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 38340cb5e5dSvi return (ENOMEM); 38440cb5e5dSvi } 38540cb5e5dSvi 38640cb5e5dSvi rp = rset; 38740cb5e5dSvi rpl = rset_len + 1; 38840cb5e5dSvi count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON); 38940cb5e5dSvi rp += count; 39040cb5e5dSvi rpl -= count; 39140cb5e5dSvi 39240cb5e5dSvi while (route != NULL) { 39340cb5e5dSvi if (first) { 39440cb5e5dSvi count = snprintf(rp, rpl, "%s", route->sip_dlg_route); 39540cb5e5dSvi rp += count; 39640cb5e5dSvi rpl -= count; 39740cb5e5dSvi first = B_FALSE; 39840cb5e5dSvi if (uri != NULL) { 39940cb5e5dSvi count = snprintf(rsp, rspl, "%c%s", 40040cb5e5dSvi SIP_COMMA, route->sip_dlg_route); 40140cb5e5dSvi } else { 40240cb5e5dSvi count = snprintf(rsp, rspl, "%s", 40340cb5e5dSvi route->sip_dlg_route); 40440cb5e5dSvi } 40540cb5e5dSvi rsp += count; 40640cb5e5dSvi rspl -= count; 40740cb5e5dSvi } else { 40840cb5e5dSvi count = snprintf(rp, rpl, "%c%s", SIP_COMMA, 40940cb5e5dSvi route->sip_dlg_route); 41040cb5e5dSvi rp += count; 41140cb5e5dSvi rpl -= count; 41240cb5e5dSvi count = snprintf(rsp, rspl, "%c%s", SIP_COMMA, 41340cb5e5dSvi route->sip_dlg_route); 41440cb5e5dSvi rsp += count; 41540cb5e5dSvi rspl -= count; 41640cb5e5dSvi } 41740cb5e5dSvi route = route->sip_dlg_route_next; 41840cb5e5dSvi } 41940cb5e5dSvi assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr + 42040cb5e5dSvi dialog->sip_dlg_rset.sip_str_len); 42140cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] = 42240cb5e5dSvi '\0'; 42340cb5e5dSvi if (uri != NULL) { 42440cb5e5dSvi if (first) { 42540cb5e5dSvi count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT, 42640cb5e5dSvi uri, SIP_RAQUOT); 42740cb5e5dSvi } else { 42840cb5e5dSvi count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA, 42940cb5e5dSvi SIP_LAQUOT, uri, SIP_RAQUOT); 43040cb5e5dSvi } 43140cb5e5dSvi rp += count; 43240cb5e5dSvi rpl -= count; 43340cb5e5dSvi free(uri); 43440cb5e5dSvi } 43540cb5e5dSvi assert(rp <= rset + rset_len); 43640cb5e5dSvi (void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1, 43740cb5e5dSvi "%s%s", rset, SIP_CRLF); 43840cb5e5dSvi free(rset); 43940cb5e5dSvi dialog->sip_dlg_route_set = (sip_header_t)rhdr; 44040cb5e5dSvi sip_dialog_free_rset(rset_head); 44140cb5e5dSvi return (0); 44240cb5e5dSvi } 44340cb5e5dSvi 44440cb5e5dSvi /* 44540cb5e5dSvi * UAC Behavior 44640cb5e5dSvi * The route set MUST be set to the list of URIs in the Record-Route 44740cb5e5dSvi * header field from the response, taken in reverse order and preserving 44840cb5e5dSvi * all URI parameters. 44940cb5e5dSvi * 45040cb5e5dSvi * UAS behavior 45140cb5e5dSvi * The route set MUST be set to the list of URIs in the Record-Route 45240cb5e5dSvi * header field from the request, taken in order and preserving all URI 45340cb5e5dSvi * parameters. 45440cb5e5dSvi */ 45540cb5e5dSvi static int 45640cb5e5dSvi sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 45740cb5e5dSvi { 45840cb5e5dSvi sip_header_t rrhdr; 45940cb5e5dSvi sip_hdr_value_t *value; 46040cb5e5dSvi int error; 46140cb5e5dSvi sip_dlg_route_set_t *rset_head = NULL; 46240cb5e5dSvi sip_dlg_route_set_t *rset_tail = NULL; 46340cb5e5dSvi sip_dlg_route_set_t *rset; 46440cb5e5dSvi int rset_cnt = 0; 46540cb5e5dSvi int rset_len = 0; 46640cb5e5dSvi 46740cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 46840cb5e5dSvi rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL); 46940cb5e5dSvi while (rrhdr != NULL) { 47040cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 47140cb5e5dSvi value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error); 47240cb5e5dSvi while (value != NULL && error == 0) { 47340cb5e5dSvi char *crlf; 47440cb5e5dSvi 47540cb5e5dSvi if (value->sip_value_state == SIP_VALUE_BAD) { 47640cb5e5dSvi value = (sip_hdr_value_t *)sip_get_next_value( 47740cb5e5dSvi (sip_header_value_t)value, &error); 47840cb5e5dSvi continue; 47940cb5e5dSvi } 48040cb5e5dSvi rset = sip_add_route_to_set(value); 48140cb5e5dSvi if (rset == NULL) 48240cb5e5dSvi goto r_error; 48340cb5e5dSvi /* 48440cb5e5dSvi * Add one for COMMA 48540cb5e5dSvi */ 48640cb5e5dSvi rset_cnt++; 48740cb5e5dSvi rset_len += (value->sip_value_end - 48840cb5e5dSvi value->sip_value_start); 48940cb5e5dSvi /* 49040cb5e5dSvi * Check for CRLF 49140cb5e5dSvi */ 49240cb5e5dSvi crlf = value->sip_value_end - strlen(SIP_CRLF); 49340cb5e5dSvi while (crlf != NULL && 49440cb5e5dSvi strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 49540cb5e5dSvi rset_len -= strlen(SIP_CRLF); 49640cb5e5dSvi crlf -= strlen(SIP_CRLF); 49740cb5e5dSvi } 49840cb5e5dSvi if (rset_head == NULL) { 49940cb5e5dSvi assert(rset_tail == NULL); 50040cb5e5dSvi rset_head = rset_tail = rset; 50140cb5e5dSvi } else if (what == SIP_UAS_DIALOG) { 50240cb5e5dSvi rset_tail->sip_dlg_route_next = rset; 50340cb5e5dSvi rset_tail = rset; 50440cb5e5dSvi } else if (what == SIP_UAC_DIALOG) { 50540cb5e5dSvi rset->sip_dlg_route_next = rset_head; 50640cb5e5dSvi rset_head = rset; 50740cb5e5dSvi } else { 50840cb5e5dSvi assert(0); 50940cb5e5dSvi } 51040cb5e5dSvi value = (sip_hdr_value_t *)sip_get_next_value( 51140cb5e5dSvi (sip_header_value_t)value, &error); 51240cb5e5dSvi } 51340cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 51440cb5e5dSvi rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr); 51540cb5e5dSvi } 51640cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 51740cb5e5dSvi if (rset_cnt == 0) 51840cb5e5dSvi return (0); 51940cb5e5dSvi if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt, 52040cb5e5dSvi rset_len) != 0) { 52140cb5e5dSvi goto r_error; 52240cb5e5dSvi } 52340cb5e5dSvi return (0); 52440cb5e5dSvi r_error: 52540cb5e5dSvi sip_dialog_free_rset(rset_head); 52640cb5e5dSvi return (ENOMEM); 52740cb5e5dSvi } 52840cb5e5dSvi 52940cb5e5dSvi /* 53040cb5e5dSvi * UAS behavior: 53140cb5e5dSvi * The remote sequence number MUST be set to the value of the sequence 53240cb5e5dSvi * number in the CSeq header field of the request. The local sequence 53340cb5e5dSvi * number MUST be empty. The call identifier component of the dialog ID 53440cb5e5dSvi * MUST be set to the value of the Call-ID in the request. The local 53540cb5e5dSvi * tag component of the dialog ID MUST be set to the tag in the To field 53640cb5e5dSvi * in the response to the request (which always includes a tag), and the 53740cb5e5dSvi * remote tag component of the dialog ID MUST be set to the tag from the 53840cb5e5dSvi * From field in the request. A UAS MUST be prepared to receive a 53940cb5e5dSvi * request without a tag in the From field, in which case the tag is 54040cb5e5dSvi * considered to have a value of null. 54140cb5e5dSvi * The remote URI MUST be set to the URI in the From field, and the 54240cb5e5dSvi * local URI MUST be set to the URI in the To field. 54340cb5e5dSvi * The remote target MUST be set to the URI from the Contact header field 54440cb5e5dSvi * of the request. 54540cb5e5dSvi * 54640cb5e5dSvi * UAC behavior: 54740cb5e5dSvi * The local sequence number MUST be set to the value of the sequence 54840cb5e5dSvi * number in the CSeq header field of the request. The remote sequence 54940cb5e5dSvi * number MUST be empty (it is established when the remote UA sends a 55040cb5e5dSvi * request within the dialog). The call identifier component of the 55140cb5e5dSvi * dialog ID MUST be set to the value of the Call-ID in the request. 55240cb5e5dSvi * The local tag component of the dialog ID MUST be set to the tag in 55340cb5e5dSvi * the From field in the request, and the remote tag component of the 55440cb5e5dSvi * dialog ID MUST be set to the tag in the To field of the response. A 55540cb5e5dSvi * UAC MUST be prepared to receive a response without a tag in the To 55640cb5e5dSvi * field, in which case the tag is considered to have a value of null. 55740cb5e5dSvi * The remote URI MUST be set to the URI in the To field, and the local 55840cb5e5dSvi * URI MUST be set to the URI in the From field. 55940cb5e5dSvi * The remote target MUST be set to the URI from the Contact header field 56040cb5e5dSvi * of the response. 56140cb5e5dSvi */ 56240cb5e5dSvi 56340cb5e5dSvi 56440cb5e5dSvi /* 56540cb5e5dSvi * This is the routine that seeds a dialog. 56640cb5e5dSvi */ 56740cb5e5dSvi sip_dialog_t 56840cb5e5dSvi sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg, 56940cb5e5dSvi boolean_t dlg_on_fork, int dlg_type) 57040cb5e5dSvi { 57140cb5e5dSvi _sip_dialog_t *dialog; 57240cb5e5dSvi int cseq; 57340cb5e5dSvi sip_header_t fhdr = NULL; 57440cb5e5dSvi sip_header_t thdr = NULL; 57540cb5e5dSvi sip_header_t chdr; 57640cb5e5dSvi sip_header_t cihdr; 57740cb5e5dSvi sip_header_t evhdr = NULL; 57840cb5e5dSvi const struct sip_value *value; 57940cb5e5dSvi sip_dialog_timer_obj_t *tim_obj = NULL; 58040cb5e5dSvi const sip_str_t *callid; 58140cb5e5dSvi sip_method_t method; 58240cb5e5dSvi int timer1 = sip_timer_T1; 58340cb5e5dSvi int error; 58440cb5e5dSvi 58540cb5e5dSvi if (!sip_msg_is_request((sip_msg_t)sip_msg, &error)) 58640cb5e5dSvi return (NULL); 58740cb5e5dSvi 58840cb5e5dSvi method = sip_get_request_method((sip_msg_t)sip_msg, &error); 58940cb5e5dSvi /* 59040cb5e5dSvi * Only INVITE and SUBSCRIBE supported 59140cb5e5dSvi */ 59240cb5e5dSvi if (error != 0 || (method != INVITE && method != SUBSCRIBE)) 59340cb5e5dSvi return (NULL); 59440cb5e5dSvi 59540cb5e5dSvi /* 59640cb5e5dSvi * A request outside of a dialog MUST NOT contain a To tag 59740cb5e5dSvi */ 59840cb5e5dSvi if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL) 59940cb5e5dSvi return (NULL); 60040cb5e5dSvi 60140cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG) { 60240cb5e5dSvi thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 60340cb5e5dSvi SIP_DLG_XCHG_FROM); 60440cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 60540cb5e5dSvi } else { 60640cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 60740cb5e5dSvi fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL); 60840cb5e5dSvi } 60940cb5e5dSvi cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL); 61040cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 61140cb5e5dSvi if (method == SUBSCRIBE) 61240cb5e5dSvi evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 61340cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 61440cb5e5dSvi if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL || 61540cb5e5dSvi (method == SUBSCRIBE && evhdr == NULL)) { 61640cb5e5dSvi if (thdr != NULL) 61740cb5e5dSvi sip_free_header(thdr); 61840cb5e5dSvi return (NULL); 61940cb5e5dSvi } 62040cb5e5dSvi 62140cb5e5dSvi /* 62240cb5e5dSvi * Sanity check since we just store the headers in the dialog 62340cb5e5dSvi */ 62440cb5e5dSvi if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL || 62540cb5e5dSvi sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 62640cb5e5dSvi ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) || 62740cb5e5dSvi (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL || 62840cb5e5dSvi sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 62940cb5e5dSvi ((value = sip_get_header_value(chdr, NULL)) == NULL) || 63040cb5e5dSvi sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) { 63140cb5e5dSvi if (thdr != NULL) 63240cb5e5dSvi sip_free_header(thdr); 63340cb5e5dSvi return (NULL); 63440cb5e5dSvi } 63540cb5e5dSvi 63640cb5e5dSvi tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t)); 63740cb5e5dSvi if (tim_obj == NULL) { 63840cb5e5dSvi if (thdr != NULL) 63940cb5e5dSvi sip_free_header(thdr); 64040cb5e5dSvi return (NULL); 64140cb5e5dSvi } 64240cb5e5dSvi dialog = calloc(1, sizeof (_sip_dialog_t)); 64340cb5e5dSvi if (dialog == NULL) { 64440cb5e5dSvi if (thdr != NULL) 64540cb5e5dSvi sip_free_header(thdr); 64640cb5e5dSvi return (NULL); 64740cb5e5dSvi } 64840cb5e5dSvi /* 64940cb5e5dSvi * We will take the TO header with the tag when we complete this 65040cb5e5dSvi * dialog 65140cb5e5dSvi */ 65240cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG) { 65340cb5e5dSvi dialog->sip_dlg_remote_uri_tag = thdr; 65440cb5e5dSvi /* 65540cb5e5dSvi * We take the remote target from the incoming request on the 65640cb5e5dSvi * UAS. For the UAC, we will take it from the response. 65740cb5e5dSvi */ 65840cb5e5dSvi if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == 65940cb5e5dSvi NULL) { 66040cb5e5dSvi goto dia_err; 66140cb5e5dSvi } 66240cb5e5dSvi } else { 66340cb5e5dSvi if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) == 66440cb5e5dSvi NULL) { 66540cb5e5dSvi goto dia_err; 66640cb5e5dSvi } 667*d8a40387Sgm /* 668*d8a40387Sgm * We take the local contact from the originating request on 669*d8a40387Sgm * UAC. For the UAS, we will take it from the response. 670*d8a40387Sgm */ 671*d8a40387Sgm if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) == 672*d8a40387Sgm NULL) { 673*d8a40387Sgm goto dia_err; 674*d8a40387Sgm } else { 675*d8a40387Sgm dialog->sip_dlg_new_local_contact = NULL; 676*d8a40387Sgm } 67740cb5e5dSvi } 67840cb5e5dSvi if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL) 67940cb5e5dSvi goto dia_err; 68040cb5e5dSvi if (method == SUBSCRIBE) { 68140cb5e5dSvi dialog->sip_dlg_event = sip_dup_header(evhdr); 68240cb5e5dSvi if (dialog->sip_dlg_event == NULL) { 68340cb5e5dSvi goto dia_err; 68440cb5e5dSvi } 68540cb5e5dSvi } 68640cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr = NULL; 68740cb5e5dSvi dialog->sip_dlg_rset.sip_str_len = 0; 68840cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 68940cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len = 0; 69040cb5e5dSvi /* 69140cb5e5dSvi * Get the route set from the request, if present 69240cb5e5dSvi */ 69340cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG && 69440cb5e5dSvi sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) { 69540cb5e5dSvi goto dia_err; 69640cb5e5dSvi } 69740cb5e5dSvi if (dlg_type == SIP_UAC_DIALOG) 69840cb5e5dSvi dialog->sip_dlg_local_cseq = cseq; 69940cb5e5dSvi else 70040cb5e5dSvi dialog->sip_dlg_remote_cseq = cseq; 70140cb5e5dSvi dialog->sip_dlg_type = dlg_type; 70240cb5e5dSvi dialog->sip_dlg_on_fork = dlg_on_fork; 70340cb5e5dSvi dialog->sip_dlg_method = method; 70440cb5e5dSvi /* 70540cb5e5dSvi * Set the partial dialog timer with the INVITE timeout val 70640cb5e5dSvi */ 70740cb5e5dSvi if (sip_conn_timer1 != NULL) 70840cb5e5dSvi timer1 = sip_conn_timer1(obj); 70940cb5e5dSvi SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1); 71040cb5e5dSvi tim_obj->dialog = dialog; 71140cb5e5dSvi /* 71240cb5e5dSvi * Since at the client we never pass the partial dialog, we need not 71340cb5e5dSvi * invoke the callback when the partial dialog self-destructs. 71440cb5e5dSvi */ 71540cb5e5dSvi if (dlg_type == SIP_UAS_DIALOG) 71640cb5e5dSvi tim_obj->func = sip_ulp_dlg_del_cb; 71740cb5e5dSvi SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj, 71840cb5e5dSvi sip_dlg_self_destruct); 71940cb5e5dSvi if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 72040cb5e5dSvi goto dia_err; 72140cb5e5dSvi (void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL); 72240cb5e5dSvi 72340cb5e5dSvi if (dlg_type == SIP_UAC_DIALOG) { 72440cb5e5dSvi const sip_str_t *local_tag; 72540cb5e5dSvi 72640cb5e5dSvi local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 72740cb5e5dSvi assert(local_tag != NULL); 72840cb5e5dSvi sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len, 72940cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 73040cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, NULL, 0, 73140cb5e5dSvi (uchar_t *)dialog->sip_dlg_id); 73240cb5e5dSvi 73340cb5e5dSvi 73440cb5e5dSvi /* 73540cb5e5dSvi * Add it to the partial hash table 73640cb5e5dSvi */ 73740cb5e5dSvi if (sip_hash_add(sip_dialog_phash, (void *)dialog, 73840cb5e5dSvi SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 73940cb5e5dSvi goto dia_err; 74040cb5e5dSvi } 74140cb5e5dSvi } 74240cb5e5dSvi SIP_DLG_REFCNT_INCR(dialog); 74340cb5e5dSvi return ((sip_dialog_t)dialog); 74440cb5e5dSvi dia_err: 74540cb5e5dSvi sip_release_dialog_res(dialog); 74640cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 74740cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 74840cb5e5dSvi if (tim_obj != NULL) 74940cb5e5dSvi free(tim_obj); 75040cb5e5dSvi return (NULL); 75140cb5e5dSvi } 75240cb5e5dSvi 75340cb5e5dSvi /* 75440cb5e5dSvi * When creating a dialog from a NOTIFY request, we need to get the FROM 75540cb5e5dSvi * header for the dialog from the TO header of the NOTIFY. 75640cb5e5dSvi */ 75740cb5e5dSvi _sip_header_t * 75840cb5e5dSvi sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what) 75940cb5e5dSvi { 76040cb5e5dSvi int len; 76140cb5e5dSvi _sip_header_t *newhdr; 76240cb5e5dSvi int cnt; 76340cb5e5dSvi const struct sip_header *hdr; 76440cb5e5dSvi int hdrsize; 76540cb5e5dSvi int error; 76640cb5e5dSvi 76740cb5e5dSvi hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM : 76840cb5e5dSvi SIP_TO, NULL, &error); 76940cb5e5dSvi if (error != 0 || hdr == NULL) 77040cb5e5dSvi return (NULL); 77140cb5e5dSvi if (sip_parse_goto_values((_sip_header_t *)hdr) != 0) 77240cb5e5dSvi return (NULL); 77340cb5e5dSvi len = hdr->sip_hdr_end - hdr->sip_hdr_current; 77440cb5e5dSvi if (what == SIP_DLG_XCHG_FROM) { 77540cb5e5dSvi hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) + 77640cb5e5dSvi SIP_SPACE_LEN; 77740cb5e5dSvi } else { 77840cb5e5dSvi hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN + 77940cb5e5dSvi sizeof (char) + SIP_SPACE_LEN; 78040cb5e5dSvi } 78140cb5e5dSvi newhdr = sip_new_header(hdrsize); 78240cb5e5dSvi if (newhdr == NULL) 78340cb5e5dSvi return (NULL); 78440cb5e5dSvi if (what == SIP_DLG_XCHG_FROM) { 78540cb5e5dSvi cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 78640cb5e5dSvi "%s %c ", SIP_TO, SIP_HCOLON); 78740cb5e5dSvi } else { 78840cb5e5dSvi cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 78940cb5e5dSvi "%s %c ", SIP_FROM, SIP_HCOLON); 79040cb5e5dSvi } 79140cb5e5dSvi newhdr->sip_hdr_current += cnt; 79240cb5e5dSvi (void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len); 79340cb5e5dSvi newhdr->sip_hdr_current += len; 79440cb5e5dSvi assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end); 79540cb5e5dSvi assert(hdr->sip_header_functions != NULL); 79640cb5e5dSvi 79740cb5e5dSvi /* 79840cb5e5dSvi * FROM and TO have common parsing functions 79940cb5e5dSvi */ 80040cb5e5dSvi newhdr->sip_header_functions = hdr->sip_header_functions; 80140cb5e5dSvi newhdr->sip_hdr_current = newhdr->sip_hdr_start; 80240cb5e5dSvi 80340cb5e5dSvi return (newhdr); 80440cb5e5dSvi } 80540cb5e5dSvi 80640cb5e5dSvi /* 80740cb5e5dSvi * This is the response that completes the dialog that was created 80840cb5e5dSvi * in sip_seed_dialog(). 80940cb5e5dSvi */ 81040cb5e5dSvi sip_dialog_t 81140cb5e5dSvi sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog) 81240cb5e5dSvi { 81340cb5e5dSvi _sip_header_t *thdr; 81440cb5e5dSvi _sip_header_t *evhdr = NULL; 81540cb5e5dSvi _sip_header_t *substate = NULL; 81640cb5e5dSvi sip_header_t chdr = NULL; 81740cb5e5dSvi int resp_code; 81840cb5e5dSvi const sip_str_t *ttag; 81940cb5e5dSvi const sip_str_t *remtag; 82040cb5e5dSvi const sip_str_t *callid; 82140cb5e5dSvi const struct sip_value *val; 82240cb5e5dSvi sip_method_t method; 82340cb5e5dSvi int error = 0; 82440cb5e5dSvi int prev_state; 82540cb5e5dSvi boolean_t alloc_thdr = B_FALSE; 82640cb5e5dSvi 82740cb5e5dSvi if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0) 82840cb5e5dSvi method = sip_get_request_method((sip_msg_t)sip_msg, &error); 82940cb5e5dSvi else 83040cb5e5dSvi method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 83140cb5e5dSvi if (error != 0 || dialog == NULL || 83240cb5e5dSvi (sip_msg_is_request((sip_msg_t)sip_msg, &error) && 83340cb5e5dSvi (dialog->sip_dlg_method == INVITE || method != NOTIFY))) { 83440cb5e5dSvi return (NULL); 83540cb5e5dSvi } 83640cb5e5dSvi if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY && 83740cb5e5dSvi sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 83840cb5e5dSvi dialog->sip_dlg_local_cseq) || 83940cb5e5dSvi (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY && 84040cb5e5dSvi sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 84140cb5e5dSvi dialog->sip_dlg_remote_cseq)) { 84240cb5e5dSvi return (NULL); 84340cb5e5dSvi } 84440cb5e5dSvi if (method == NOTIFY) { 84540cb5e5dSvi const sip_str_t *sstate; 84640cb5e5dSvi 84740cb5e5dSvi thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 84840cb5e5dSvi SIP_DLG_XCHG_FROM); 84940cb5e5dSvi if (thdr == NULL) 85040cb5e5dSvi return (NULL); 85140cb5e5dSvi alloc_thdr = B_TRUE; 85240cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 85340cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 85440cb5e5dSvi if (chdr == NULL) { 85540cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 85640cb5e5dSvi sip_free_header(thdr); 85740cb5e5dSvi return (NULL); 85840cb5e5dSvi } 85940cb5e5dSvi evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 86040cb5e5dSvi if (evhdr == NULL) { 86140cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 86240cb5e5dSvi sip_free_header(thdr); 86340cb5e5dSvi return (NULL); 86440cb5e5dSvi } 86540cb5e5dSvi substate = sip_search_for_header(sip_msg, 86640cb5e5dSvi SIP_SUBSCRIPTION_STATE, NULL); 86740cb5e5dSvi if (substate == NULL) { 86840cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 86940cb5e5dSvi sip_free_header(thdr); 87040cb5e5dSvi return (NULL); 87140cb5e5dSvi } 87240cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 87340cb5e5dSvi sstate = sip_get_substate((sip_msg_t)sip_msg, &error); 87440cb5e5dSvi if (sstate == NULL || error != 0) { 87540cb5e5dSvi sip_free_header(thdr); 87640cb5e5dSvi return (NULL); 87740cb5e5dSvi } 87840cb5e5dSvi if ((sstate->sip_str_len != strlen("pending") && 87940cb5e5dSvi sstate->sip_str_len != strlen("active")) || 88040cb5e5dSvi ((sstate->sip_str_len == strlen("pending") && 88140cb5e5dSvi strncasecmp(sstate->sip_str_ptr, "pending", 88240cb5e5dSvi strlen("pending")) != 0) || 88340cb5e5dSvi (sstate->sip_str_len == strlen("active") && 88440cb5e5dSvi strncasecmp(sstate->sip_str_ptr, "active", 88540cb5e5dSvi strlen("active")) != 0))) { 88640cb5e5dSvi sip_free_header(thdr); 88740cb5e5dSvi return (NULL); 88840cb5e5dSvi } 88940cb5e5dSvi ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 89040cb5e5dSvi } else { 89140cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 89240cb5e5dSvi thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 89340cb5e5dSvi SIP_DLG_XCHG_TO); 89440cb5e5dSvi alloc_thdr = B_TRUE; 89540cb5e5dSvi } else { 89640cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 89740cb5e5dSvi thdr = sip_search_for_header(sip_msg, SIP_TO, NULL); 89840cb5e5dSvi if (dialog->sip_dlg_remote_target == NULL) { 89940cb5e5dSvi chdr = sip_search_for_header(sip_msg, 90040cb5e5dSvi SIP_CONTACT, NULL); 90140cb5e5dSvi } 90240cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 90340cb5e5dSvi } 90440cb5e5dSvi if (thdr == NULL) { 90540cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 90640cb5e5dSvi return (NULL); 90740cb5e5dSvi } 90840cb5e5dSvi ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL); 90940cb5e5dSvi } 91040cb5e5dSvi if (ttag == NULL) { 91140cb5e5dSvi if (alloc_thdr) 91240cb5e5dSvi sip_free_header(thdr); 91340cb5e5dSvi return (NULL); 91440cb5e5dSvi } 91540cb5e5dSvi prev_state = dialog->sip_dlg_state; 91640cb5e5dSvi 91740cb5e5dSvi if (method == NOTIFY) { 91840cb5e5dSvi int error; 91940cb5e5dSvi const sip_str_t *dlg_id_val = NULL; 92040cb5e5dSvi const sip_str_t *event; 92140cb5e5dSvi const sip_str_t *id_val = NULL; 92240cb5e5dSvi sip_header_value_t ev_val; 92340cb5e5dSvi sip_hdr_value_t *dlg_ev_val = NULL; 92440cb5e5dSvi 92540cb5e5dSvi event = sip_get_event((sip_msg_t)sip_msg, &error); 92640cb5e5dSvi if (event == NULL || error != 0) { 92740cb5e5dSvi sip_free_header(thdr); 92840cb5e5dSvi return (NULL); 92940cb5e5dSvi } 93040cb5e5dSvi ev_val = (sip_header_value_t)sip_get_header_value(evhdr, 93140cb5e5dSvi &error); 93240cb5e5dSvi if (ev_val != NULL) 93340cb5e5dSvi id_val = sip_get_param_value(ev_val, "id", &error); 93440cb5e5dSvi if (error == 0) { 93540cb5e5dSvi dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value( 93640cb5e5dSvi dialog->sip_dlg_event, &error); 93740cb5e5dSvi } 93840cb5e5dSvi if (dlg_ev_val == NULL || error != 0) { 93940cb5e5dSvi sip_free_header(thdr); 94040cb5e5dSvi return (NULL); 94140cb5e5dSvi } 94240cb5e5dSvi dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val, 94340cb5e5dSvi "id", &error); 94440cb5e5dSvi if (error != 0 || 94540cb5e5dSvi dlg_ev_val->str_val_len != event->sip_str_len || 94640cb5e5dSvi strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr, 94740cb5e5dSvi event->sip_str_len != 0)) { 94840cb5e5dSvi sip_free_header(thdr); 94940cb5e5dSvi return (NULL); 95040cb5e5dSvi } 95140cb5e5dSvi if ((dlg_id_val == NULL && id_val != NULL) || 95240cb5e5dSvi (dlg_id_val != NULL && id_val == NULL)) { 95340cb5e5dSvi sip_free_header(thdr); 95440cb5e5dSvi return (NULL); 95540cb5e5dSvi } else if (dlg_id_val != NULL && id_val != NULL) { 95640cb5e5dSvi if (dlg_id_val->sip_str_len != id_val->sip_str_len || 95740cb5e5dSvi strncasecmp(dlg_id_val->sip_str_ptr, 95840cb5e5dSvi id_val->sip_str_ptr, dlg_id_val->sip_str_len) != 95940cb5e5dSvi 0) { 96040cb5e5dSvi sip_free_header(thdr); 96140cb5e5dSvi return (NULL); 96240cb5e5dSvi } 96340cb5e5dSvi } 96440cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 96540cb5e5dSvi dialog->sip_dlg_remote_uri_tag = thdr; 96640cb5e5dSvi if ((dialog->sip_dlg_remote_target = 96740cb5e5dSvi sip_dup_header(chdr)) == NULL) { 96840cb5e5dSvi sip_free_header(thdr); 96940cb5e5dSvi return (NULL); 97040cb5e5dSvi } 97140cb5e5dSvi } else { 97240cb5e5dSvi dialog->sip_dlg_local_uri_tag = thdr; 97340cb5e5dSvi } 97440cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 97540cb5e5dSvi } else { 97640cb5e5dSvi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 97740cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 97840cb5e5dSvi assert(dialog->sip_dlg_state == SIP_DLG_NEW); 97940cb5e5dSvi if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) { 98040cb5e5dSvi assert(dialog->sip_dlg_type == SIP_UAC_DIALOG); 98140cb5e5dSvi if ((dialog->sip_dlg_remote_target = 98240cb5e5dSvi sip_dup_header(chdr)) == NULL) { 98340cb5e5dSvi (void) pthread_mutex_unlock( 98440cb5e5dSvi &dialog->sip_dlg_mutex); 98540cb5e5dSvi if (alloc_thdr) 98640cb5e5dSvi sip_free_header(thdr); 9872c2c4183Svi goto terminate_new_dlg; 98840cb5e5dSvi } 98940cb5e5dSvi if (sip_dialog_get_route_set(dialog, sip_msg, 99040cb5e5dSvi dialog->sip_dlg_type) != 0) { 99140cb5e5dSvi (void) pthread_mutex_unlock( 99240cb5e5dSvi &dialog->sip_dlg_mutex); 99340cb5e5dSvi if (alloc_thdr) 99440cb5e5dSvi sip_free_header(thdr); 9952c2c4183Svi goto terminate_new_dlg; 99640cb5e5dSvi } 99740cb5e5dSvi } 99840cb5e5dSvi if (SIP_PROVISIONAL_RESP(resp_code)) { 99940cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_EARLY; 100040cb5e5dSvi } else if (SIP_OK_RESP(resp_code)) { 100140cb5e5dSvi /* 100240cb5e5dSvi * Per 12.1 the UAS must include the contact header 100340cb5e5dSvi * for a dialog establishing response, so if we 100440cb5e5dSvi * don't find one, we terminate it. 100540cb5e5dSvi */ 100640cb5e5dSvi if (dialog->sip_dlg_remote_target == NULL) { 100740cb5e5dSvi (void) pthread_mutex_unlock( 100840cb5e5dSvi &dialog->sip_dlg_mutex); 100940cb5e5dSvi if (sip_ulp_dlg_del_cb != NULL) { 101040cb5e5dSvi sip_ulp_dlg_del_cb(dialog, 101140cb5e5dSvi (sip_msg_t)sip_msg, NULL); 101240cb5e5dSvi } 101340cb5e5dSvi if (alloc_thdr) 101440cb5e5dSvi sip_free_header(thdr); 10152c2c4183Svi goto terminate_new_dlg; 101640cb5e5dSvi } 101740cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 101840cb5e5dSvi } else { 101940cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 102040cb5e5dSvi if (sip_ulp_dlg_del_cb != NULL) { 102140cb5e5dSvi sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg, 102240cb5e5dSvi NULL); 102340cb5e5dSvi } 102440cb5e5dSvi if (alloc_thdr) 102540cb5e5dSvi sip_free_header(thdr); 10262c2c4183Svi goto terminate_new_dlg; 102740cb5e5dSvi } 102840cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 102940cb5e5dSvi dialog->sip_dlg_local_uri_tag = thdr; 103040cb5e5dSvi } else { 103140cb5e5dSvi if ((dialog->sip_dlg_remote_uri_tag = 103240cb5e5dSvi sip_dup_header(thdr)) == NULL) { 103340cb5e5dSvi (void) pthread_mutex_unlock( 103440cb5e5dSvi &dialog->sip_dlg_mutex); 10352c2c4183Svi goto terminate_new_dlg; 103640cb5e5dSvi } 103740cb5e5dSvi } 103840cb5e5dSvi } 103940cb5e5dSvi 1040*d8a40387Sgm /* 1041*d8a40387Sgm * We take the local contact for UAS Dialog from the response (either 1042*d8a40387Sgm * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE 1043*d8a40387Sgm * request) 1044*d8a40387Sgm */ 1045*d8a40387Sgm if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state 1046*d8a40387Sgm == SIP_DLG_CONFIRMED)) { 1047*d8a40387Sgm if (chdr == NULL) { 1048*d8a40387Sgm (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 1049*d8a40387Sgm chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 1050*d8a40387Sgm NULL); 1051*d8a40387Sgm (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 1052*d8a40387Sgm } 1053*d8a40387Sgm if ((chdr == NULL) || ((dialog->sip_dlg_local_contact = 1054*d8a40387Sgm sip_dup_header(chdr)) == NULL)) { 1055*d8a40387Sgm (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1056*d8a40387Sgm if (alloc_thdr) 1057*d8a40387Sgm sip_free_header(thdr); 1058*d8a40387Sgm goto terminate_new_dlg; 1059*d8a40387Sgm } 1060*d8a40387Sgm } 1061*d8a40387Sgm 106240cb5e5dSvi /* 106340cb5e5dSvi * Cancel the partial dialog timer 106440cb5e5dSvi */ 106540cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 106640cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 106740cb5e5dSvi 106840cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 106940cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_local_uri_tag, 107040cb5e5dSvi &error); 107140cb5e5dSvi } else { 107240cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag, 107340cb5e5dSvi &error); 107440cb5e5dSvi } 107540cb5e5dSvi assert(val != NULL && error == 0); 107640cb5e5dSvi remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error); 107740cb5e5dSvi 107840cb5e5dSvi val = sip_get_header_value(dialog->sip_dlg_call_id, &error); 107940cb5e5dSvi callid = &((sip_hdr_value_t *)val)->str_val; 108040cb5e5dSvi 108140cb5e5dSvi /* 108240cb5e5dSvi * Get an ID for this dialog 108340cb5e5dSvi */ 108440cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 108540cb5e5dSvi sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len, 108640cb5e5dSvi ttag->sip_str_ptr, ttag->sip_str_len, 108740cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 108840cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 108940cb5e5dSvi } else { 109040cb5e5dSvi sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len, 109140cb5e5dSvi remtag->sip_str_ptr, remtag->sip_str_len, 109240cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 109340cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 109440cb5e5dSvi } 109540cb5e5dSvi 109640cb5e5dSvi SIP_DLG_REFCNT_INCR(dialog); 109740cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 109840cb5e5dSvi 109940cb5e5dSvi /* 110040cb5e5dSvi * Add it to the hash table 110140cb5e5dSvi */ 110240cb5e5dSvi if (sip_hash_add(sip_dialog_hash, (void *)dialog, 110340cb5e5dSvi SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 11042c2c4183Svi terminate_new_dlg: 110540cb5e5dSvi /* 110640cb5e5dSvi * So that sip_dialog_delete() does not try to remove 110740cb5e5dSvi * this from the hash table. 110840cb5e5dSvi */ 110940cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 111040cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 11112c2c4183Svi if (dialog->sip_dlg_local_uri_tag != NULL) { 11122c2c4183Svi sip_free_header(dialog->sip_dlg_local_uri_tag); 11132c2c4183Svi dialog->sip_dlg_local_uri_tag = NULL; 11142c2c4183Svi } 111540cb5e5dSvi } else { 11162c2c4183Svi if (dialog->sip_dlg_remote_uri_tag != NULL) { 11172c2c4183Svi sip_free_header(dialog->sip_dlg_remote_uri_tag); 11182c2c4183Svi dialog->sip_dlg_remote_uri_tag = NULL; 11192c2c4183Svi } 112040cb5e5dSvi } 112140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 112240cb5e5dSvi sip_dialog_terminate(dialog, (sip_msg_t)sip_msg); 112340cb5e5dSvi return (NULL); 112440cb5e5dSvi } 112540cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 112640cb5e5dSvi sip_dlg_ulp_state_cb((sip_dialog_t)dialog, 112740cb5e5dSvi (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state); 112840cb5e5dSvi } 112940cb5e5dSvi return ((sip_dialog_t)dialog); 113040cb5e5dSvi } 113140cb5e5dSvi 113240cb5e5dSvi /* 113340cb5e5dSvi * Check if this dialog is a match. 113440cb5e5dSvi */ 113540cb5e5dSvi boolean_t 113640cb5e5dSvi sip_dialog_match(void *obj, void *hindex) 113740cb5e5dSvi { 113840cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 113940cb5e5dSvi 114040cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 114140cb5e5dSvi if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 114240cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 114340cb5e5dSvi return (B_FALSE); 114440cb5e5dSvi } 114540cb5e5dSvi if (bcmp(dialog->sip_dlg_id, hindex, 114640cb5e5dSvi sizeof (dialog->sip_dlg_id)) == 0) { 114740cb5e5dSvi SIP_DLG_REFCNT_INCR(dialog); 114840cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 114940cb5e5dSvi return (B_TRUE); 115040cb5e5dSvi } 115140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 115240cb5e5dSvi return (B_FALSE); 115340cb5e5dSvi } 115440cb5e5dSvi 115540cb5e5dSvi /* 115640cb5e5dSvi * Don't delete, just take it out of the hash 115740cb5e5dSvi */ 115840cb5e5dSvi boolean_t 115940cb5e5dSvi sip_dialog_dontfree(void *obj, void *hindex, int *found) 116040cb5e5dSvi { 116140cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 116240cb5e5dSvi 116340cb5e5dSvi *found = 0; 116440cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 116540cb5e5dSvi if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 116640cb5e5dSvi == 0) { 116740cb5e5dSvi *found = 1; 116840cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 116940cb5e5dSvi return (B_TRUE); 117040cb5e5dSvi } 117140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 117240cb5e5dSvi return (B_FALSE); 117340cb5e5dSvi } 117440cb5e5dSvi 117540cb5e5dSvi /* 117640cb5e5dSvi * Free resources associated with the dialog, the object will be removed 117740cb5e5dSvi * from the hash list by sip_hash_delete. 117840cb5e5dSvi */ 117940cb5e5dSvi boolean_t 118040cb5e5dSvi sip_dialog_free(void *obj, void *hindex, int *found) 118140cb5e5dSvi { 118240cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 118340cb5e5dSvi 118440cb5e5dSvi *found = 0; 118540cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 118640cb5e5dSvi if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 118740cb5e5dSvi == 0) { 118840cb5e5dSvi *found = 1; 118940cb5e5dSvi assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED); 119040cb5e5dSvi if (dialog->sip_dlg_ref_cnt != 0) { 119140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 119240cb5e5dSvi return (B_FALSE); 119340cb5e5dSvi } 119440cb5e5dSvi sip_release_dialog_res(dialog); 119540cb5e5dSvi return (B_TRUE); 119640cb5e5dSvi } 119740cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 119840cb5e5dSvi return (B_FALSE); 119940cb5e5dSvi } 120040cb5e5dSvi 120140cb5e5dSvi /* 120240cb5e5dSvi * The UAS will receive the request from the transaction layer. If the 120340cb5e5dSvi * request has a tag in the To header field, the UAS core computes the 120440cb5e5dSvi * dialog identifier corresponding to the request and compares it with 120540cb5e5dSvi * existing dialogs. If there is a match, this is a mid-dialog request. 120640cb5e5dSvi */ 120740cb5e5dSvi sip_dialog_t 120840cb5e5dSvi sip_dialog_find(_sip_msg_t *sip_msg) 120940cb5e5dSvi { 121040cb5e5dSvi const sip_str_t *localtag; 121140cb5e5dSvi const sip_str_t *remtag; 121240cb5e5dSvi const sip_str_t *callid; 121340cb5e5dSvi uint16_t digest[8]; 121440cb5e5dSvi _sip_dialog_t *dialog; 121540cb5e5dSvi boolean_t is_request; 121640cb5e5dSvi int error; 121740cb5e5dSvi 121840cb5e5dSvi is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 121940cb5e5dSvi if (error != 0) 122040cb5e5dSvi return (NULL); 122140cb5e5dSvi if (is_request) { 122240cb5e5dSvi localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 122340cb5e5dSvi if (error == 0) 122440cb5e5dSvi remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 122540cb5e5dSvi } else { 122640cb5e5dSvi remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 122740cb5e5dSvi if (error == 0) 122840cb5e5dSvi localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 122940cb5e5dSvi } 123040cb5e5dSvi if (error != 0) 123140cb5e5dSvi return (NULL); 123240cb5e5dSvi callid = sip_get_callid((sip_msg_t)sip_msg, &error); 123340cb5e5dSvi if (error != 0 || remtag == NULL || localtag == NULL || 123440cb5e5dSvi callid == NULL) { 123540cb5e5dSvi return (NULL); 123640cb5e5dSvi } 123740cb5e5dSvi sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 123840cb5e5dSvi remtag->sip_str_ptr, remtag->sip_str_len, 123940cb5e5dSvi callid->sip_str_ptr, callid->sip_str_len, 124040cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 124140cb5e5dSvi 124240cb5e5dSvi dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash, 124340cb5e5dSvi (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match); 124440cb5e5dSvi if (dialog == NULL) { 124540cb5e5dSvi sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 124640cb5e5dSvi NULL, 0, callid->sip_str_ptr, callid->sip_str_len, 124740cb5e5dSvi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 124840cb5e5dSvi dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash, 124940cb5e5dSvi (void *)digest, SIP_DIGEST_TO_HASH(digest), 125040cb5e5dSvi sip_dialog_match); 125140cb5e5dSvi } 125240cb5e5dSvi return ((sip_dialog_t)dialog); 125340cb5e5dSvi } 125440cb5e5dSvi 125540cb5e5dSvi /* 125640cb5e5dSvi * We keep this partial dialog for the duration of the INVITE 125740cb5e5dSvi * transaction timeout duration, i.e. Timer B. 125840cb5e5dSvi */ 125940cb5e5dSvi void 126040cb5e5dSvi sip_dlg_self_destruct(void *args) 126140cb5e5dSvi { 126240cb5e5dSvi sip_dialog_timer_obj_t *tim_obj = (sip_dialog_timer_obj_t *)args; 126340cb5e5dSvi _sip_dialog_t *dialog = (_sip_dialog_t *)tim_obj->dialog; 126440cb5e5dSvi int index; 126540cb5e5dSvi 126640cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 126740cb5e5dSvi assert(dialog->sip_dlg_state == SIP_DLG_NEW); 126840cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_DESTROYED; 126940cb5e5dSvi if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 127040cb5e5dSvi index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 127140cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 127240cb5e5dSvi sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id, 127340cb5e5dSvi index, sip_dialog_dontfree); 127440cb5e5dSvi } else { 127540cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 127640cb5e5dSvi } 127740cb5e5dSvi if (tim_obj->func != NULL) 127840cb5e5dSvi tim_obj->func(dialog, NULL, NULL); 127940cb5e5dSvi free(tim_obj); 128040cb5e5dSvi SIP_DLG_REFCNT_DECR(dialog); 128140cb5e5dSvi } 128240cb5e5dSvi 128340cb5e5dSvi /* 128440cb5e5dSvi * Terminate a dialog 128540cb5e5dSvi */ 128640cb5e5dSvi void 128740cb5e5dSvi sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg) 128840cb5e5dSvi { 128940cb5e5dSvi int prev_state; 129040cb5e5dSvi 129140cb5e5dSvi (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 129240cb5e5dSvi prev_state = dialog->sip_dlg_state; 129340cb5e5dSvi dialog->sip_dlg_state = SIP_DLG_DESTROYED; 129440cb5e5dSvi (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 129540cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 129640cb5e5dSvi sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state, 129740cb5e5dSvi dialog->sip_dlg_state); 129840cb5e5dSvi } 129940cb5e5dSvi SIP_DLG_REFCNT_DECR(dialog); 130040cb5e5dSvi } 130140cb5e5dSvi 130240cb5e5dSvi /* 130340cb5e5dSvi * Delete a dialog 130440cb5e5dSvi */ 130540cb5e5dSvi void 130640cb5e5dSvi sip_dialog_delete(_sip_dialog_t *dialog) 130740cb5e5dSvi { 130840cb5e5dSvi int index; 130940cb5e5dSvi 131040cb5e5dSvi /* 131140cb5e5dSvi * partial dialog, not in the hash table 131240cb5e5dSvi */ 131340cb5e5dSvi if (dialog->sip_dlg_local_uri_tag == NULL || 131440cb5e5dSvi dialog->sip_dlg_remote_uri_tag == NULL) { 131540cb5e5dSvi /* 131640cb5e5dSvi * Cancel the partial dialog timer 131740cb5e5dSvi */ 131840cb5e5dSvi if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 131940cb5e5dSvi SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 132040cb5e5dSvi sip_release_dialog_res(dialog); 132140cb5e5dSvi return; 132240cb5e5dSvi } 132340cb5e5dSvi index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 132440cb5e5dSvi sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index, 132540cb5e5dSvi sip_dialog_free); 132640cb5e5dSvi } 132740cb5e5dSvi 132840cb5e5dSvi /* 132940cb5e5dSvi * Get the remote target from the CONTACT header from the 200 OK response 133040cb5e5dSvi */ 133140cb5e5dSvi static boolean_t 133240cb5e5dSvi sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg) 133340cb5e5dSvi { 133440cb5e5dSvi sip_header_t chdr; 133540cb5e5dSvi 133640cb5e5dSvi if (dialog->sip_dlg_remote_target != NULL) 133740cb5e5dSvi return (B_TRUE); 133840cb5e5dSvi 133940cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 134040cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 134140cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 134240cb5e5dSvi if (chdr == NULL) 134340cb5e5dSvi return (B_FALSE); 134440cb5e5dSvi if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL) 134540cb5e5dSvi return (B_FALSE); 134640cb5e5dSvi 134740cb5e5dSvi return (B_TRUE); 134840cb5e5dSvi } 134940cb5e5dSvi 135040cb5e5dSvi /* 135140cb5e5dSvi * Process an incoming request/response 135240cb5e5dSvi */ 135340cb5e5dSvi /* ARGSUSED */ 135440cb5e5dSvi int 135540cb5e5dSvi sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog) 135640cb5e5dSvi { 135740cb5e5dSvi boolean_t request; 135840cb5e5dSvi _sip_dialog_t *_dialog; 135940cb5e5dSvi int error; 136040cb5e5dSvi 136140cb5e5dSvi request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 136240cb5e5dSvi if (error != 0) 136340cb5e5dSvi return (EINVAL); 136440cb5e5dSvi _dialog = (_sip_dialog_t *)*sip_dialog; 136540cb5e5dSvi if (request) { 136640cb5e5dSvi uint32_t cseq; 136740cb5e5dSvi sip_method_t method; 136840cb5e5dSvi 136940cb5e5dSvi cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error); 137040cb5e5dSvi if (error != 0) 137140cb5e5dSvi return (EINVAL); 137240cb5e5dSvi method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 137340cb5e5dSvi if (error != 0) 137440cb5e5dSvi return (EINVAL); 137540cb5e5dSvi if (sip_get_request_method((sip_msg_t)sip_msg, &error) != 137640cb5e5dSvi method) { 137740cb5e5dSvi return (EINVAL); 137840cb5e5dSvi } 137940cb5e5dSvi (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 138040cb5e5dSvi /* 138140cb5e5dSvi * Requests that do not change in any way the state 138240cb5e5dSvi * of a dialog may be received within a dialog. 138340cb5e5dSvi * They are processed as if they had been received 138440cb5e5dSvi * outside the dialog. 138540cb5e5dSvi * For dialogs that have been established with an 138640cb5e5dSvi * INVITE, the only target refresh request defined is 138740cb5e5dSvi * re-INVITE. 138840cb5e5dSvi */ 138940cb5e5dSvi if (_dialog->sip_dlg_method == INVITE && 139040cb5e5dSvi method == INVITE && _dialog->sip_dlg_remote_cseq != 0 && 139140cb5e5dSvi SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) { 139240cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 139340cb5e5dSvi return (EPROTO); 139440cb5e5dSvi } 139540cb5e5dSvi /* 139640cb5e5dSvi * Target-Refresh request 139740cb5e5dSvi */ 139840cb5e5dSvi if (_dialog->sip_dlg_method == INVITE && method == INVITE) { 139940cb5e5dSvi sip_header_t chdr; 140040cb5e5dSvi sip_header_t nchdr; 140140cb5e5dSvi 140240cb5e5dSvi (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 140340cb5e5dSvi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 140440cb5e5dSvi NULL); 140540cb5e5dSvi (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 140640cb5e5dSvi if (chdr != NULL && 140740cb5e5dSvi (nchdr = sip_dup_header(chdr)) != NULL) { 140840cb5e5dSvi if (_dialog->sip_dlg_remote_target != NULL) { 140940cb5e5dSvi sip_free_header( 141040cb5e5dSvi _dialog->sip_dlg_remote_target); 141140cb5e5dSvi } 141240cb5e5dSvi _dialog->sip_dlg_remote_target = nchdr; 141340cb5e5dSvi } 141440cb5e5dSvi } 141540cb5e5dSvi _dialog->sip_dlg_remote_cseq = cseq; 141640cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 141740cb5e5dSvi } else { 141840cb5e5dSvi int resp_code; 141940cb5e5dSvi sip_method_t method; 142040cb5e5dSvi int error; 142140cb5e5dSvi 142240cb5e5dSvi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 142340cb5e5dSvi if (error == 0) { 142440cb5e5dSvi method = sip_get_callseq_method((sip_msg_t)sip_msg, 142540cb5e5dSvi &error); 142640cb5e5dSvi } 142740cb5e5dSvi if (error != 0) 142840cb5e5dSvi return (error); 142940cb5e5dSvi 143040cb5e5dSvi (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 14315878c602Sgm if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 14325878c602Sgm (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 14335878c602Sgm return (0); 14345878c602Sgm } 143540cb5e5dSvi assert(_dialog->sip_dlg_state == SIP_DLG_EARLY || 143640cb5e5dSvi _dialog->sip_dlg_state == SIP_DLG_CONFIRMED); 143740cb5e5dSvi /* 143840cb5e5dSvi * Let the user delete the dialog if it is not a 1XX/2XX resp 143940cb5e5dSvi * for an early INVITE dialog. 144040cb5e5dSvi */ 144140cb5e5dSvi if (SIP_OK_RESP(resp_code)) { 144240cb5e5dSvi if (method == INVITE) { 144340cb5e5dSvi if (!sip_get_rtarg(_dialog, sip_msg)) { 144440cb5e5dSvi (void) pthread_mutex_unlock( 144540cb5e5dSvi &_dialog->sip_dlg_mutex); 144640cb5e5dSvi if (sip_ulp_dlg_del_cb != NULL) { 144740cb5e5dSvi sip_ulp_dlg_del_cb( 144840cb5e5dSvi (sip_dialog_t)_dialog, 144940cb5e5dSvi (sip_msg_t)sip_msg, NULL); 145040cb5e5dSvi } 145140cb5e5dSvi sip_dialog_terminate(_dialog, 145240cb5e5dSvi (sip_msg_t)sip_msg); 145340cb5e5dSvi return (0); 145440cb5e5dSvi } 145540cb5e5dSvi if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 145640cb5e5dSvi _dialog->sip_dlg_state = 145740cb5e5dSvi SIP_DLG_CONFIRMED; 145840cb5e5dSvi (void) pthread_mutex_unlock( 145940cb5e5dSvi &_dialog->sip_dlg_mutex); 146040cb5e5dSvi (void) sip_dlg_recompute_rset(_dialog, 146140cb5e5dSvi sip_msg, SIP_UAC_DIALOG); 146240cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 146340cb5e5dSvi sip_dlg_ulp_state_cb( 146440cb5e5dSvi (sip_dialog_t)_dialog, 146540cb5e5dSvi sip_msg, SIP_DLG_EARLY, 146640cb5e5dSvi _dialog->sip_dlg_state); 146740cb5e5dSvi } 146840cb5e5dSvi return (0); 1469*d8a40387Sgm } else if (_dialog->sip_dlg_new_local_contact 1470*d8a40387Sgm != NULL) { 1471*d8a40387Sgm assert(_dialog->sip_dlg_local_contact 1472*d8a40387Sgm != NULL); 1473*d8a40387Sgm sip_free_header(_dialog-> 1474*d8a40387Sgm sip_dlg_local_contact); 1475*d8a40387Sgm _dialog->sip_dlg_local_contact = 1476*d8a40387Sgm _dialog->sip_dlg_new_local_contact; 1477*d8a40387Sgm _dialog->sip_dlg_new_local_contact = 1478*d8a40387Sgm NULL; 147940cb5e5dSvi } 148040cb5e5dSvi } 148140cb5e5dSvi } 148240cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 148340cb5e5dSvi } 148440cb5e5dSvi return (0); 148540cb5e5dSvi } 148640cb5e5dSvi 148740cb5e5dSvi /* 148840cb5e5dSvi * Copy partial dialog to create a complete dialog 148940cb5e5dSvi */ 149040cb5e5dSvi _sip_dialog_t * 149140cb5e5dSvi sip_copy_partial_dialog(_sip_dialog_t *dialog) 149240cb5e5dSvi { 149340cb5e5dSvi _sip_dialog_t *new_dlg; 149440cb5e5dSvi 149540cb5e5dSvi new_dlg = calloc(1, sizeof (_sip_dialog_t)); 149640cb5e5dSvi if (new_dlg == NULL) 149740cb5e5dSvi return (NULL); 149840cb5e5dSvi if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 149940cb5e5dSvi new_dlg->sip_dlg_req_uri.sip_str_ptr = 150040cb5e5dSvi malloc(dialog->sip_dlg_req_uri.sip_str_len + 1); 150140cb5e5dSvi if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) { 150240cb5e5dSvi free(new_dlg); 150340cb5e5dSvi return (NULL); 150440cb5e5dSvi } 150540cb5e5dSvi (void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr, 150640cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_ptr, 150740cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len); 150840cb5e5dSvi new_dlg->sip_dlg_req_uri.sip_str_ptr[ 150940cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len] = '\0'; 151040cb5e5dSvi new_dlg->sip_dlg_req_uri.sip_str_len = 151140cb5e5dSvi dialog->sip_dlg_req_uri.sip_str_len; 151240cb5e5dSvi } 151340cb5e5dSvi if (dialog->sip_dlg_route_set != NULL) { 151440cb5e5dSvi assert(dialog->sip_dlg_rset.sip_str_ptr != NULL); 151540cb5e5dSvi new_dlg->sip_dlg_rset.sip_str_ptr = 151640cb5e5dSvi malloc(dialog->sip_dlg_rset.sip_str_len + 1); 151740cb5e5dSvi if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) { 151840cb5e5dSvi if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 151940cb5e5dSvi free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 152040cb5e5dSvi free(new_dlg); 152140cb5e5dSvi return (NULL); 152240cb5e5dSvi } 152340cb5e5dSvi (void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr, 152440cb5e5dSvi dialog->sip_dlg_rset.sip_str_ptr, 152540cb5e5dSvi dialog->sip_dlg_rset.sip_str_len); 152640cb5e5dSvi new_dlg->sip_dlg_rset.sip_str_ptr[ 152740cb5e5dSvi dialog->sip_dlg_rset.sip_str_len] = '\0'; 152840cb5e5dSvi new_dlg->sip_dlg_rset.sip_str_len = 152940cb5e5dSvi dialog->sip_dlg_rset.sip_str_len; 153040cb5e5dSvi 153140cb5e5dSvi new_dlg->sip_dlg_route_set = 153240cb5e5dSvi sip_dup_header(dialog->sip_dlg_route_set); 153340cb5e5dSvi if (new_dlg->sip_dlg_route_set == NULL) { 153440cb5e5dSvi free(new_dlg->sip_dlg_rset.sip_str_ptr); 153540cb5e5dSvi if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 153640cb5e5dSvi free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 153740cb5e5dSvi free(new_dlg); 153840cb5e5dSvi return (NULL); 153940cb5e5dSvi } 154040cb5e5dSvi } 154140cb5e5dSvi if ((new_dlg->sip_dlg_local_uri_tag = 154240cb5e5dSvi sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL || 154340cb5e5dSvi (new_dlg->sip_dlg_remote_target = 154440cb5e5dSvi sip_dup_header(dialog->sip_dlg_remote_target)) == NULL || 1545*d8a40387Sgm (new_dlg->sip_dlg_local_contact = 1546*d8a40387Sgm sip_dup_header(dialog->sip_dlg_local_contact)) == NULL || 154740cb5e5dSvi (new_dlg->sip_dlg_call_id = 154840cb5e5dSvi sip_dup_header(dialog->sip_dlg_call_id)) == NULL) { 154940cb5e5dSvi sip_release_dialog_res(new_dlg); 155040cb5e5dSvi return (NULL); 155140cb5e5dSvi } 155240cb5e5dSvi if (dialog->sip_dlg_event != NULL) { 155340cb5e5dSvi new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event); 155440cb5e5dSvi if (new_dlg->sip_dlg_event == NULL) { 155540cb5e5dSvi sip_release_dialog_res(new_dlg); 155640cb5e5dSvi return (NULL); 155740cb5e5dSvi } 155840cb5e5dSvi } 155940cb5e5dSvi new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq; 156040cb5e5dSvi new_dlg->sip_dlg_type = dialog->sip_dlg_type; 156140cb5e5dSvi new_dlg->sip_dlg_on_fork = B_FALSE; 156240cb5e5dSvi (void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL); 156340cb5e5dSvi 156440cb5e5dSvi return (new_dlg); 156540cb5e5dSvi } 156640cb5e5dSvi 156740cb5e5dSvi /* 156840cb5e5dSvi * Update the dialog using the response 156940cb5e5dSvi */ 157040cb5e5dSvi sip_dialog_t 157140cb5e5dSvi sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg) 157240cb5e5dSvi { 157340cb5e5dSvi _sip_dialog_t *_dialog; 157440cb5e5dSvi boolean_t isreq; 157540cb5e5dSvi sip_method_t method; 157640cb5e5dSvi int resp_code = 0; 157740cb5e5dSvi int prev_state; 157840cb5e5dSvi boolean_t decr_ref = B_FALSE; 157940cb5e5dSvi int error; 158040cb5e5dSvi 158140cb5e5dSvi isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error); 158240cb5e5dSvi if (error != 0) 158340cb5e5dSvi return (dialog); 158440cb5e5dSvi _dialog = (_sip_dialog_t *)dialog; 158540cb5e5dSvi (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 158640cb5e5dSvi if (isreq) { 158740cb5e5dSvi method = sip_get_request_method((sip_msg_t)sip_msg, &error); 158840cb5e5dSvi if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE || 158940cb5e5dSvi method != NOTIFY) { 159040cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 159140cb5e5dSvi return (dialog); 159240cb5e5dSvi } 159340cb5e5dSvi } else { 159440cb5e5dSvi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 159540cb5e5dSvi if (error != 0) { 159640cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 159740cb5e5dSvi return (dialog); 159840cb5e5dSvi } 1599*d8a40387Sgm method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 1600*d8a40387Sgm if (error != 0) { 1601*d8a40387Sgm (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1602*d8a40387Sgm return (dialog); 1603*d8a40387Sgm } 160440cb5e5dSvi } 160540cb5e5dSvi prev_state = _dialog->sip_dlg_state; 160640cb5e5dSvi if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) { 160740cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 160840cb5e5dSvi } else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 160940cb5e5dSvi /* 161040cb5e5dSvi * Let the user delete the dialog if it is not a 1XX/2XX resp 161140cb5e5dSvi * for an early dialog. 161240cb5e5dSvi */ 161340cb5e5dSvi assert(!isreq); 161440cb5e5dSvi if (SIP_OK_RESP(resp_code)) { 161540cb5e5dSvi _dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 1616*d8a40387Sgm /* 1617*d8a40387Sgm * If we recieved provisional response before we would 1618*d8a40387Sgm * not have captured local contact. So store it now. 1619*d8a40387Sgm */ 1620*d8a40387Sgm if (_dialog->sip_dlg_type == SIP_UAS_DIALOG && _dialog-> 1621*d8a40387Sgm sip_dlg_method == INVITE && method == INVITE) { 1622*d8a40387Sgm sip_header_t chdr; 1623*d8a40387Sgm (void) pthread_mutex_lock(&sip_msg-> 1624*d8a40387Sgm sip_msg_mutex); 1625*d8a40387Sgm chdr = sip_search_for_header(sip_msg, 1626*d8a40387Sgm SIP_CONTACT, NULL); 1627*d8a40387Sgm (void) pthread_mutex_unlock(&sip_msg-> 1628*d8a40387Sgm sip_msg_mutex); 1629*d8a40387Sgm if (chdr != NULL) { 1630*d8a40387Sgm _dialog->sip_dlg_local_contact 1631*d8a40387Sgm = sip_dup_header(chdr); 1632*d8a40387Sgm _dialog->sip_dlg_new_local_contact = 1633*d8a40387Sgm NULL; 1634*d8a40387Sgm } 1635*d8a40387Sgm } 163640cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 163740cb5e5dSvi (void) sip_dlg_recompute_rset(_dialog, sip_msg, 163840cb5e5dSvi SIP_UAS_DIALOG); 163940cb5e5dSvi if (sip_dlg_ulp_state_cb != NULL) { 164040cb5e5dSvi sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg, 164140cb5e5dSvi prev_state, dialog->sip_dlg_state); 164240cb5e5dSvi } 164340cb5e5dSvi } else { 164440cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 164540cb5e5dSvi } 164640cb5e5dSvi } else if (_dialog->sip_dlg_state == SIP_DLG_NEW) { 164740cb5e5dSvi if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE && 164840cb5e5dSvi SIP_PROVISIONAL_RESP(resp_code)) { 164940cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 165040cb5e5dSvi return (dialog); 165140cb5e5dSvi } 165240cb5e5dSvi if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) { 165340cb5e5dSvi _sip_dialog_t *new_dlg; 165440cb5e5dSvi 165540cb5e5dSvi if (_dialog->sip_dlg_on_fork) { 165640cb5e5dSvi new_dlg = sip_copy_partial_dialog(_dialog); 165740cb5e5dSvi if (new_dlg == NULL) { 165840cb5e5dSvi (void) pthread_mutex_unlock( 165940cb5e5dSvi &_dialog->sip_dlg_mutex); 166040cb5e5dSvi return (dialog); 166140cb5e5dSvi } 166240cb5e5dSvi /* 166340cb5e5dSvi * This decr/incr dance is because the caller 166440cb5e5dSvi * has incremented the ref on the partial 166540cb5e5dSvi * dialog, we release it here and incr the 166640cb5e5dSvi * ref on the new dialog which will be 166740cb5e5dSvi * released by the caller. 166840cb5e5dSvi */ 166940cb5e5dSvi (void) pthread_mutex_unlock( 167040cb5e5dSvi &_dialog->sip_dlg_mutex); 167140cb5e5dSvi SIP_DLG_REFCNT_DECR(_dialog); 167240cb5e5dSvi _dialog = new_dlg; 167340cb5e5dSvi (void) pthread_mutex_lock( 167440cb5e5dSvi &_dialog->sip_dlg_mutex); 167540cb5e5dSvi SIP_DLG_REFCNT_INCR(_dialog); 167640cb5e5dSvi } else { 167740cb5e5dSvi int index; 167840cb5e5dSvi 167940cb5e5dSvi /* 168040cb5e5dSvi * take it out of the list so that further 168140cb5e5dSvi * responses will not result in a dialog. 168240cb5e5dSvi * We will have an extra refcount when we 168340cb5e5dSvi * come back from sip_complete_dialog(), i.e. 168440cb5e5dSvi * one when the partial dialog was created - 168540cb5e5dSvi * in sip_seed_dialog(), one held by the caller 168640cb5e5dSvi * and one that will be added by 168740cb5e5dSvi * sip_complete_dialog(). We need to release 168840cb5e5dSvi * the one added by the sip_seed_dialog(), 168940cb5e5dSvi * since the one in sip_complete_dialog() 169040cb5e5dSvi * is for the same purpose. 169140cb5e5dSvi */ 169240cb5e5dSvi if (SIP_IS_TIMER_RUNNING( 169340cb5e5dSvi _dialog->sip_dlg_timer)) { 169440cb5e5dSvi SIP_CANCEL_TIMER( 169540cb5e5dSvi _dialog->sip_dlg_timer); 169640cb5e5dSvi } 169740cb5e5dSvi index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 169840cb5e5dSvi (void) pthread_mutex_unlock( 169940cb5e5dSvi &_dialog->sip_dlg_mutex); 170040cb5e5dSvi sip_hash_delete(sip_dialog_phash, 170140cb5e5dSvi (void *)_dialog->sip_dlg_id, 170240cb5e5dSvi index, sip_dialog_dontfree); 170340cb5e5dSvi (void) pthread_mutex_lock( 170440cb5e5dSvi &_dialog->sip_dlg_mutex); 170540cb5e5dSvi decr_ref = B_TRUE; 170640cb5e5dSvi } 170740cb5e5dSvi } else { 170840cb5e5dSvi decr_ref = B_TRUE; 170940cb5e5dSvi } 171040cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 171140cb5e5dSvi if ((dialog = sip_complete_dialog(sip_msg, _dialog)) == 171240cb5e5dSvi NULL) { 17132c2c4183Svi if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref) 17142c2c4183Svi SIP_DLG_REFCNT_DECR(_dialog); 171540cb5e5dSvi return (NULL); 171640cb5e5dSvi } 171740cb5e5dSvi if (decr_ref) 171840cb5e5dSvi SIP_DLG_REFCNT_DECR(_dialog); 171940cb5e5dSvi } else { 172040cb5e5dSvi (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 172140cb5e5dSvi } 172240cb5e5dSvi return (dialog); 172340cb5e5dSvi } 172440cb5e5dSvi 172540cb5e5dSvi /* 172640cb5e5dSvi * Initialize the hash table 172740cb5e5dSvi */ 172840cb5e5dSvi void 172940cb5e5dSvi sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *), 173040cb5e5dSvi void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int)) 173140cb5e5dSvi { 173240cb5e5dSvi int cnt; 173340cb5e5dSvi 173440cb5e5dSvi for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) { 173540cb5e5dSvi sip_dialog_hash[cnt].hash_count = 0; 173640cb5e5dSvi sip_dialog_hash[cnt].hash_head = NULL; 173740cb5e5dSvi sip_dialog_hash[cnt].hash_tail = NULL; 173840cb5e5dSvi (void) pthread_mutex_init( 173940cb5e5dSvi &sip_dialog_hash[cnt].sip_hash_mutex, NULL); 174040cb5e5dSvi sip_dialog_phash[cnt].hash_count = 0; 174140cb5e5dSvi sip_dialog_phash[cnt].hash_head = NULL; 174240cb5e5dSvi sip_dialog_phash[cnt].hash_tail = NULL; 174340cb5e5dSvi (void) pthread_mutex_init( 174440cb5e5dSvi &sip_dialog_phash[cnt].sip_hash_mutex, NULL); 174540cb5e5dSvi } 174640cb5e5dSvi if (ulp_dlg_del != NULL) 174740cb5e5dSvi sip_ulp_dlg_del_cb = ulp_dlg_del; 174840cb5e5dSvi 174940cb5e5dSvi if (ulp_state_cb != NULL) 175040cb5e5dSvi sip_dlg_ulp_state_cb = ulp_state_cb; 175140cb5e5dSvi } 1752*d8a40387Sgm 1753*d8a40387Sgm /* 1754*d8a40387Sgm * Copy the new contact header of re-INVITE 1755*d8a40387Sgm */ 1756*d8a40387Sgm void 1757*d8a40387Sgm sip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg) 1758*d8a40387Sgm { 1759*d8a40387Sgm sip_header_t chdr = NULL; 1760*d8a40387Sgm sip_header_t nhdr = NULL; 1761*d8a40387Sgm 1762*d8a40387Sgm (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 1763*d8a40387Sgm chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 1764*d8a40387Sgm (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 1765*d8a40387Sgm 1766*d8a40387Sgm if (chdr == NULL) 1767*d8a40387Sgm return; 1768*d8a40387Sgm 1769*d8a40387Sgm (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 1770*d8a40387Sgm if (dialog->sip_dlg_method != INVITE || dialog->sip_dlg_state 1771*d8a40387Sgm != SIP_DLG_CONFIRMED) { 1772*d8a40387Sgm (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1773*d8a40387Sgm return; 1774*d8a40387Sgm } 1775*d8a40387Sgm 1776*d8a40387Sgm if (((nhdr = sip_dup_header(chdr)) != NULL)) { 1777*d8a40387Sgm if (dialog->sip_dlg_new_local_contact != NULL) 1778*d8a40387Sgm sip_free_header(dialog->sip_dlg_new_local_contact); 1779*d8a40387Sgm dialog->sip_dlg_new_local_contact = nhdr; 1780*d8a40387Sgm } 1781*d8a40387Sgm (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1782*d8a40387Sgm } 1783