12882Svi117747 /* 22882Svi117747 * CDDL HEADER START 32882Svi117747 * 42882Svi117747 * The contents of this file are subject to the terms of the 52882Svi117747 * Common Development and Distribution License (the "License"). 62882Svi117747 * You may not use this file except in compliance with the License. 72882Svi117747 * 82882Svi117747 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92882Svi117747 * or http://www.opensolaris.org/os/licensing. 102882Svi117747 * See the License for the specific language governing permissions 112882Svi117747 * and limitations under the License. 122882Svi117747 * 132882Svi117747 * When distributing Covered Code, include this CDDL HEADER in each 142882Svi117747 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152882Svi117747 * If applicable, add the following below this CDDL HEADER, with the 162882Svi117747 * fields enclosed by brackets "[]" replaced with your own identifying 172882Svi117747 * information: Portions Copyright [yyyy] [name of copyright owner] 182882Svi117747 * 192882Svi117747 * CDDL HEADER END 202882Svi117747 */ 212882Svi117747 222882Svi117747 /* 233439Svi117747 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 242882Svi117747 * Use is subject to license terms. 252882Svi117747 */ 262882Svi117747 272882Svi117747 #pragma ident "%Z%%M% %I% %E% SMI" 282882Svi117747 293439Svi117747 #include <stdio.h> 303439Svi117747 #include <stdlib.h> 313439Svi117747 #include <assert.h> 323439Svi117747 #include <errno.h> 333439Svi117747 #include <pthread.h> 343439Svi117747 #include <strings.h> 353439Svi117747 #include <sip.h> 363439Svi117747 372882Svi117747 #include "sip_msg.h" 383439Svi117747 #include "sip_miscdefs.h" 392882Svi117747 #include "sip_hash.h" 402882Svi117747 #include "sip_dialog.h" 412882Svi117747 #include "sip_parse_generic.h" 422882Svi117747 432882Svi117747 #define SIP_DLG_XCHG_FROM 0 442882Svi117747 #define SIP_DLG_XCHG_TO 1 452882Svi117747 462882Svi117747 /* 472882Svi117747 * Dialog state change callback function 482882Svi117747 */ 492882Svi117747 void (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL; 502882Svi117747 void (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL; 512882Svi117747 522882Svi117747 boolean_t sip_incomplete_dialog(sip_dialog_t); 532882Svi117747 542882Svi117747 /* 552882Svi117747 * Exchange From/To header 562882Svi117747 */ 572882Svi117747 _sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int); 582882Svi117747 592882Svi117747 /* 602882Svi117747 * Complete dialog hash table 612882Svi117747 */ 622882Svi117747 sip_hash_t sip_dialog_hash[SIP_HASH_SZ]; 632882Svi117747 642882Svi117747 /* 652882Svi117747 * Partial dialog hash table 662882Svi117747 */ 672882Svi117747 sip_hash_t sip_dialog_phash[SIP_HASH_SZ]; 682882Svi117747 692882Svi117747 /* 702882Svi117747 * Route set structure 712882Svi117747 */ 722882Svi117747 typedef struct sip_dlg_route_set_s { 732882Svi117747 char *sip_dlg_route; 742882Svi117747 sip_str_t sip_dlg_ruri; 752882Svi117747 boolean_t sip_dlg_route_lr; 762882Svi117747 struct sip_dlg_route_set_s *sip_dlg_route_next; 772882Svi117747 }sip_dlg_route_set_t; 782882Svi117747 792882Svi117747 sip_dialog_t sip_seed_dialog(sip_conn_object_t, _sip_msg_t *, 802882Svi117747 boolean_t, int); 812882Svi117747 sip_dialog_t sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *); 822882Svi117747 int sip_dialog_process(_sip_msg_t *, sip_dialog_t *); 832882Svi117747 void sip_dialog_delete(_sip_dialog_t *); 842882Svi117747 void sip_dialog_init(); 852882Svi117747 sip_dialog_t sip_dialog_find(_sip_msg_t *); 862882Svi117747 boolean_t sip_dialog_match(void *, void *); 872882Svi117747 boolean_t sip_dialog_free(void *, void *, int *); 882882Svi117747 sip_dialog_t sip_update_dialog(sip_dialog_t, _sip_msg_t *); 892882Svi117747 char *sip_dialog_req_uri(sip_dialog_t); 902882Svi117747 912882Svi117747 static void sip_release_dialog_res(_sip_dialog_t *); 922882Svi117747 void sip_dlg_self_destruct(void *); 932882Svi117747 static int sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *, 942882Svi117747 int); 952882Svi117747 static void sip_dialog_free_rset(sip_dlg_route_set_t *); 962882Svi117747 972882Svi117747 /* 982882Svi117747 * Timer object for partial dialogs 992882Svi117747 */ 1002882Svi117747 typedef struct sip_dialog_timer_obj_s { 1012882Svi117747 _sip_dialog_t *dialog; 1022882Svi117747 void (*func)(sip_dialog_t, sip_msg_t, void *); 1032882Svi117747 } sip_dialog_timer_obj_t; 1042882Svi117747 1052882Svi117747 /* 1062882Svi117747 * To avoid duplication all over the place 1072882Svi117747 */ 1082882Svi117747 static void 1092882Svi117747 sip_release_dialog_res(_sip_dialog_t *dialog) 1102882Svi117747 { 1112882Svi117747 1122882Svi117747 assert(dialog->sip_dlg_ref_cnt == 0); 1132882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 1142882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 1152882Svi117747 if (dialog->sip_dlg_call_id != NULL) 1162882Svi117747 sip_free_header(dialog->sip_dlg_call_id); 1172882Svi117747 if (dialog->sip_dlg_local_uri_tag != NULL) 1182882Svi117747 sip_free_header(dialog->sip_dlg_local_uri_tag); 1192882Svi117747 if (dialog->sip_dlg_remote_uri_tag != NULL) 1202882Svi117747 sip_free_header(dialog->sip_dlg_remote_uri_tag); 1212882Svi117747 if (dialog->sip_dlg_remote_target != NULL) 1222882Svi117747 sip_free_header(dialog->sip_dlg_remote_target); 1232882Svi117747 if (dialog->sip_dlg_route_set != NULL) 1242882Svi117747 sip_free_header(dialog->sip_dlg_route_set); 1252882Svi117747 if (dialog->sip_dlg_event != NULL) 1262882Svi117747 sip_free_header(dialog->sip_dlg_event); 1272882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 1282882Svi117747 free(dialog->sip_dlg_req_uri.sip_str_ptr); 1292882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 1302882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 1312882Svi117747 } 1322882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 1332882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 1342882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 1352882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 1362882Svi117747 } 1372882Svi117747 (void) pthread_mutex_destroy(&dialog->sip_dlg_mutex); 1382882Svi117747 free(dialog); 1392882Svi117747 } 1402882Svi117747 1412882Svi117747 /* 1422882Svi117747 * Get the route information from the 'value' and add it to the route 1432882Svi117747 * set. 1442882Svi117747 */ 1452882Svi117747 static sip_dlg_route_set_t * 1462882Svi117747 sip_add_route_to_set(sip_hdr_value_t *value) 1472882Svi117747 { 1482882Svi117747 int vlen = 0; 1492882Svi117747 sip_dlg_route_set_t *rset; 1502882Svi117747 char *crlf; 1512882Svi117747 const sip_param_t *uri_param; 1522882Svi117747 int error; 1532882Svi117747 1542882Svi117747 rset = calloc(1, sizeof (*rset)); 1552882Svi117747 if (rset == NULL) 1562882Svi117747 return (NULL); 1572882Svi117747 rset->sip_dlg_route_next = NULL; 1582882Svi117747 vlen = value->sip_value_end - value->sip_value_start; 1592882Svi117747 1602882Svi117747 /* 1612882Svi117747 * check for CRLF 1622882Svi117747 */ 1632882Svi117747 crlf = value->sip_value_end - strlen(SIP_CRLF); 1642882Svi117747 while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 1652882Svi117747 vlen -= strlen(SIP_CRLF); 1662882Svi117747 crlf -= strlen(SIP_CRLF); 1672882Svi117747 } 1682882Svi117747 rset->sip_dlg_route = calloc(1, vlen + 1); 1692882Svi117747 if (rset->sip_dlg_route == NULL) { 1702882Svi117747 free(rset); 1712882Svi117747 return (NULL); 1722882Svi117747 } 1732882Svi117747 /* 1742882Svi117747 * loose routing 1752882Svi117747 */ 1762882Svi117747 rset->sip_dlg_route_lr = B_FALSE; 1772882Svi117747 (void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen); 1782882Svi117747 rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route + 1792882Svi117747 (value->cftr_uri.sip_str_ptr - value->sip_value_start); 1802882Svi117747 rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len; 1812882Svi117747 rset->sip_dlg_route[vlen] = '\0'; 1822882Svi117747 1832882Svi117747 assert(value->sip_value_parsed_uri != NULL); 1842882Svi117747 /* 1852882Svi117747 * Check if the 'lr' param is present for this route. 1862882Svi117747 */ 1872882Svi117747 uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error); 1882882Svi117747 if (error != 0) { 1892882Svi117747 free(rset->sip_dlg_route); 1902882Svi117747 free(rset); 1912882Svi117747 return (NULL); 1922882Svi117747 } 1932882Svi117747 if (uri_param != NULL) { 1942882Svi117747 rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr", 1952882Svi117747 strlen("lr")); 1962882Svi117747 } 1972882Svi117747 return (rset); 1982882Svi117747 } 1992882Svi117747 2002882Svi117747 /* 2012882Svi117747 * Depending on the route-set, determine the request URI. 2022882Svi117747 */ 2032882Svi117747 char * 2042882Svi117747 sip_dialog_req_uri(sip_dialog_t dialog) 2052882Svi117747 { 2062882Svi117747 const sip_str_t *req_uri; 2072882Svi117747 char *uri; 2082882Svi117747 _sip_dialog_t *_dialog; 2092882Svi117747 2102882Svi117747 _dialog = (_sip_dialog_t *)dialog; 2112882Svi117747 if (_dialog->sip_dlg_route_set == NULL || 2122882Svi117747 _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 2132882Svi117747 const struct sip_value *val; 2142882Svi117747 2152882Svi117747 val = sip_get_header_value(_dialog->sip_dlg_remote_target, 2162882Svi117747 NULL); 2172882Svi117747 if (val == NULL) 2182882Svi117747 return (NULL); 2192882Svi117747 req_uri = &((sip_hdr_value_t *)val)->cftr_uri; 2202882Svi117747 } else { 2212882Svi117747 req_uri = &_dialog->sip_dlg_req_uri; 2222882Svi117747 } 2232882Svi117747 uri = (char *)malloc(req_uri->sip_str_len + 1); 2242882Svi117747 if (uri == NULL) 2252882Svi117747 return (NULL); 2262882Svi117747 (void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len); 2272882Svi117747 uri[req_uri->sip_str_len] = '\0'; 2282882Svi117747 2292882Svi117747 return (uri); 2302882Svi117747 } 2312882Svi117747 2322882Svi117747 /* 2332882Svi117747 * Free the route set. 2342882Svi117747 */ 2352882Svi117747 void 2362882Svi117747 sip_dialog_free_rset(sip_dlg_route_set_t *rset) 2372882Svi117747 { 2382882Svi117747 sip_dlg_route_set_t *next; 2392882Svi117747 2402882Svi117747 while (rset != NULL) { 2412882Svi117747 next = rset->sip_dlg_route_next; 2422882Svi117747 rset->sip_dlg_route_next = NULL; 2432882Svi117747 free(rset->sip_dlg_route); 2442882Svi117747 free(rset); 2452882Svi117747 rset = next; 2462882Svi117747 } 2472882Svi117747 } 2482882Svi117747 2492882Svi117747 /* 2502882Svi117747 * Recompute route-set 2512882Svi117747 */ 2522882Svi117747 static int 2532882Svi117747 sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 2542882Svi117747 { 2552882Svi117747 int ret; 2562882Svi117747 2572882Svi117747 if (dialog->sip_dlg_route_set != NULL) { 2582882Svi117747 sip_free_header(dialog->sip_dlg_route_set); 2592882Svi117747 dialog->sip_dlg_route_set = NULL; 2602882Svi117747 } 2612882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 2622882Svi117747 free(dialog->sip_dlg_req_uri.sip_str_ptr); 2632882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 2642882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 2652882Svi117747 } 2662882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 2672882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 2682882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 2692882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 2702882Svi117747 } 2712882Svi117747 ret = sip_dialog_get_route_set(dialog, sip_msg, what); 2722882Svi117747 return (ret); 2732882Svi117747 } 2742882Svi117747 2752882Svi117747 /* 2762882Svi117747 * If the route set is empty, the UAC MUST place the remote target URI 2772882Svi117747 * into the Request-URI. The UAC MUST NOT add a Route header field to 2782882Svi117747 * the request. 2792882Svi117747 * 2802882Svi117747 * If the route set is not empty, and the first URI in the route set 2812882Svi117747 * contains the lr parameter (see Section 19.1.1), the UAC MUST place 2822882Svi117747 * the remote target URI into the Request-URI and MUST include a Route 2832882Svi117747 * header field containing the route set values in order, including all 2842882Svi117747 * parameters. 2852882Svi117747 * 2862882Svi117747 * If the route set is not empty, and its first URI does not contain the 2872882Svi117747 * lr parameter, the UAC MUST place the first URI from the route set 2882882Svi117747 * into the Request-URI, stripping any parameters that are not allowed 2892882Svi117747 * in a Request-URI. The UAC MUST add a Route header field containing 2902882Svi117747 * the remainder of the route set values in order, including all 2912882Svi117747 * parameters. The UAC MUST then place the remote target URI into the 2922882Svi117747 * Route header field as the last value. 2932882Svi117747 */ 2942882Svi117747 int 2952882Svi117747 sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head, 2962882Svi117747 int rcnt, int rlen) 2972882Svi117747 { 2982882Svi117747 size_t rset_len; 2992882Svi117747 _sip_header_t *rhdr; 3002882Svi117747 char *rset; 3012882Svi117747 char *rp; 3022882Svi117747 char *rsp; 3032882Svi117747 int count; 3042882Svi117747 sip_dlg_route_set_t *route; 3052882Svi117747 boolean_t first = B_TRUE; 3062882Svi117747 const sip_str_t *to_uri; 3072882Svi117747 char *uri = NULL; 3082882Svi117747 int rspl; 3092882Svi117747 int rpl; 3102882Svi117747 3112882Svi117747 assert(rcnt > 0); 3122882Svi117747 3132882Svi117747 dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1; 3142882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt); 3152882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr == NULL) 3162882Svi117747 return (ENOMEM); 3172882Svi117747 rsp = dialog->sip_dlg_rset.sip_str_ptr; 3182882Svi117747 rspl = rlen + rcnt; 3192882Svi117747 route = rset_head; 3202882Svi117747 rset_len = rlen; 3212882Svi117747 if (!route->sip_dlg_route_lr) { 3222882Svi117747 const struct sip_value *val; 3232882Svi117747 3242882Svi117747 val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL); 3252882Svi117747 to_uri = &((sip_hdr_value_t *)val)->cftr_uri; 3262882Svi117747 uri = (char *)malloc(to_uri->sip_str_len + 1); 3272882Svi117747 if (uri == NULL) { 3282882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3292882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3302882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3312882Svi117747 return (ENOMEM); 3322882Svi117747 } 3332882Svi117747 (void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len); 3342882Svi117747 uri[to_uri->sip_str_len] = '\0'; 3352882Svi117747 rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) + 3362882Svi117747 SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN + 3372882Svi117747 sizeof (char); 3382882Svi117747 count = snprintf(rsp, rspl, "%s", route->sip_dlg_route); 3392882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = malloc( 3402882Svi117747 route->sip_dlg_ruri.sip_str_len + 1); 3412882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 3422882Svi117747 free(uri); 3432882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3442882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3452882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3462882Svi117747 return (ENOMEM); 3472882Svi117747 } 3482882Svi117747 (void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp + 3492882Svi117747 (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route), 3502882Svi117747 route->sip_dlg_ruri.sip_str_len); 3512882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr[ 3522882Svi117747 route->sip_dlg_ruri.sip_str_len] = '\0'; 3532882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 3542882Svi117747 route->sip_dlg_ruri.sip_str_len; 3552882Svi117747 3562882Svi117747 rsp += count; 3572882Svi117747 rspl -= count; 3582882Svi117747 route = route->sip_dlg_route_next; 3592882Svi117747 } 3602882Svi117747 3612882Svi117747 /* 3622882Svi117747 * rcnt - 1 is for the number of COMMAs 3632882Svi117747 */ 3642882Svi117747 rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) + 3652882Svi117747 SIP_SPACE_LEN + rcnt - 1; 3662882Svi117747 rset = malloc(rset_len + 1); 3672882Svi117747 if (rset == NULL) { 3682882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3692882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3702882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3712882Svi117747 return (ENOMEM); 3722882Svi117747 } 3732882Svi117747 rhdr = sip_new_header(rset_len + strlen(SIP_CRLF)); 3742882Svi117747 if (rhdr == NULL) { 3752882Svi117747 free(rset); 3762882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3772882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3782882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3792882Svi117747 return (ENOMEM); 3802882Svi117747 } 3812882Svi117747 3822882Svi117747 rp = rset; 3832882Svi117747 rpl = rset_len + 1; 3842882Svi117747 count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON); 3852882Svi117747 rp += count; 3862882Svi117747 rpl -= count; 3872882Svi117747 3882882Svi117747 while (route != NULL) { 3892882Svi117747 if (first) { 3902882Svi117747 count = snprintf(rp, rpl, "%s", route->sip_dlg_route); 3912882Svi117747 rp += count; 3922882Svi117747 rpl -= count; 3932882Svi117747 first = B_FALSE; 3942882Svi117747 if (uri != NULL) { 3952882Svi117747 count = snprintf(rsp, rspl, "%c%s", 3962882Svi117747 SIP_COMMA, route->sip_dlg_route); 3972882Svi117747 } else { 3982882Svi117747 count = snprintf(rsp, rspl, "%s", 3992882Svi117747 route->sip_dlg_route); 4002882Svi117747 } 4012882Svi117747 rsp += count; 4022882Svi117747 rspl -= count; 4032882Svi117747 } else { 4042882Svi117747 count = snprintf(rp, rpl, "%c%s", SIP_COMMA, 4052882Svi117747 route->sip_dlg_route); 4062882Svi117747 rp += count; 4072882Svi117747 rpl -= count; 4082882Svi117747 count = snprintf(rsp, rspl, "%c%s", SIP_COMMA, 4092882Svi117747 route->sip_dlg_route); 4102882Svi117747 rsp += count; 4112882Svi117747 rspl -= count; 4122882Svi117747 } 4132882Svi117747 route = route->sip_dlg_route_next; 4142882Svi117747 } 4152882Svi117747 assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr + 4162882Svi117747 dialog->sip_dlg_rset.sip_str_len); 4172882Svi117747 dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] = 4182882Svi117747 '\0'; 4192882Svi117747 if (uri != NULL) { 4202882Svi117747 if (first) { 4212882Svi117747 count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT, 4222882Svi117747 uri, SIP_RAQUOT); 4232882Svi117747 } else { 4242882Svi117747 count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA, 4252882Svi117747 SIP_LAQUOT, uri, SIP_RAQUOT); 4262882Svi117747 } 4272882Svi117747 rp += count; 4282882Svi117747 rpl -= count; 4292882Svi117747 free(uri); 4302882Svi117747 } 4312882Svi117747 assert(rp <= rset + rset_len); 4322882Svi117747 (void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1, 4332882Svi117747 "%s%s", rset, SIP_CRLF); 4342882Svi117747 free(rset); 4352882Svi117747 dialog->sip_dlg_route_set = (sip_header_t)rhdr; 4362882Svi117747 sip_dialog_free_rset(rset_head); 4372882Svi117747 return (0); 4382882Svi117747 } 4392882Svi117747 4402882Svi117747 /* 4412882Svi117747 * UAC Behavior 4422882Svi117747 * The route set MUST be set to the list of URIs in the Record-Route 4432882Svi117747 * header field from the response, taken in reverse order and preserving 4442882Svi117747 * all URI parameters. 4452882Svi117747 * 4462882Svi117747 * UAS behavior 4472882Svi117747 * The route set MUST be set to the list of URIs in the Record-Route 4482882Svi117747 * header field from the request, taken in order and preserving all URI 4492882Svi117747 * parameters. 4502882Svi117747 */ 4512882Svi117747 static int 4522882Svi117747 sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 4532882Svi117747 { 4542882Svi117747 sip_header_t rrhdr; 4552882Svi117747 sip_hdr_value_t *value; 4562882Svi117747 int error; 4572882Svi117747 sip_dlg_route_set_t *rset_head = NULL; 4582882Svi117747 sip_dlg_route_set_t *rset_tail = NULL; 4592882Svi117747 sip_dlg_route_set_t *rset; 4602882Svi117747 int rset_cnt = 0; 4612882Svi117747 int rset_len = 0; 4622882Svi117747 4632882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 4642882Svi117747 rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL); 4652882Svi117747 while (rrhdr != NULL) { 4662882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 4672882Svi117747 value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error); 4682882Svi117747 while (value != NULL && error == 0) { 4692882Svi117747 char *crlf; 4702882Svi117747 4712882Svi117747 if (value->sip_value_state == SIP_VALUE_BAD) { 4722882Svi117747 value = (sip_hdr_value_t *)sip_get_next_value( 4732882Svi117747 (sip_header_value_t)value, &error); 4742882Svi117747 continue; 4752882Svi117747 } 4762882Svi117747 rset = sip_add_route_to_set(value); 4772882Svi117747 if (rset == NULL) 4782882Svi117747 goto r_error; 4792882Svi117747 /* 4802882Svi117747 * Add one for COMMA 4812882Svi117747 */ 4822882Svi117747 rset_cnt++; 4832882Svi117747 rset_len += (value->sip_value_end - 4842882Svi117747 value->sip_value_start); 4852882Svi117747 /* 4862882Svi117747 * Check for CRLF 4872882Svi117747 */ 4882882Svi117747 crlf = value->sip_value_end - strlen(SIP_CRLF); 4892882Svi117747 while (crlf != NULL && 4902882Svi117747 strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 4912882Svi117747 rset_len -= strlen(SIP_CRLF); 4922882Svi117747 crlf -= strlen(SIP_CRLF); 4932882Svi117747 } 4942882Svi117747 if (rset_head == NULL) { 4952882Svi117747 assert(rset_tail == NULL); 4962882Svi117747 rset_head = rset_tail = rset; 4972882Svi117747 } else if (what == SIP_UAS_DIALOG) { 4982882Svi117747 rset_tail->sip_dlg_route_next = rset; 4992882Svi117747 rset_tail = rset; 5002882Svi117747 } else if (what == SIP_UAC_DIALOG) { 5012882Svi117747 rset->sip_dlg_route_next = rset_head; 5022882Svi117747 rset_head = rset; 5032882Svi117747 } else { 5042882Svi117747 assert(0); 5052882Svi117747 } 5062882Svi117747 value = (sip_hdr_value_t *)sip_get_next_value( 5072882Svi117747 (sip_header_value_t)value, &error); 5082882Svi117747 } 5092882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 5102882Svi117747 rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr); 5112882Svi117747 } 5122882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 5132882Svi117747 if (rset_cnt == 0) 5142882Svi117747 return (0); 5152882Svi117747 if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt, 5162882Svi117747 rset_len) != 0) { 5172882Svi117747 goto r_error; 5182882Svi117747 } 5192882Svi117747 return (0); 5202882Svi117747 r_error: 5212882Svi117747 sip_dialog_free_rset(rset_head); 5222882Svi117747 return (ENOMEM); 5232882Svi117747 } 5242882Svi117747 5252882Svi117747 /* 5262882Svi117747 * UAS behavior: 5272882Svi117747 * The remote sequence number MUST be set to the value of the sequence 5282882Svi117747 * number in the CSeq header field of the request. The local sequence 5292882Svi117747 * number MUST be empty. The call identifier component of the dialog ID 5302882Svi117747 * MUST be set to the value of the Call-ID in the request. The local 5312882Svi117747 * tag component of the dialog ID MUST be set to the tag in the To field 5322882Svi117747 * in the response to the request (which always includes a tag), and the 5332882Svi117747 * remote tag component of the dialog ID MUST be set to the tag from the 5342882Svi117747 * From field in the request. A UAS MUST be prepared to receive a 5352882Svi117747 * request without a tag in the From field, in which case the tag is 5362882Svi117747 * considered to have a value of null. 5372882Svi117747 * The remote URI MUST be set to the URI in the From field, and the 5382882Svi117747 * local URI MUST be set to the URI in the To field. 5392882Svi117747 * The remote target MUST be set to the URI from the Contact header field 5402882Svi117747 * of the request. 5412882Svi117747 * 5422882Svi117747 * UAC behavior: 5432882Svi117747 * The local sequence number MUST be set to the value of the sequence 5442882Svi117747 * number in the CSeq header field of the request. The remote sequence 5452882Svi117747 * number MUST be empty (it is established when the remote UA sends a 5462882Svi117747 * request within the dialog). The call identifier component of the 5472882Svi117747 * dialog ID MUST be set to the value of the Call-ID in the request. 5482882Svi117747 * The local tag component of the dialog ID MUST be set to the tag in 5492882Svi117747 * the From field in the request, and the remote tag component of the 5502882Svi117747 * dialog ID MUST be set to the tag in the To field of the response. A 5512882Svi117747 * UAC MUST be prepared to receive a response without a tag in the To 5522882Svi117747 * field, in which case the tag is considered to have a value of null. 5532882Svi117747 * The remote URI MUST be set to the URI in the To field, and the local 5542882Svi117747 * URI MUST be set to the URI in the From field. 5552882Svi117747 * The remote target MUST be set to the URI from the Contact header field 5562882Svi117747 * of the response. 5572882Svi117747 */ 5582882Svi117747 5592882Svi117747 5602882Svi117747 /* 5612882Svi117747 * This is the routine that seeds a dialog. 5622882Svi117747 */ 5632882Svi117747 sip_dialog_t 5642882Svi117747 sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg, 5652882Svi117747 boolean_t dlg_on_fork, int dlg_type) 5662882Svi117747 { 5672882Svi117747 _sip_dialog_t *dialog; 5682882Svi117747 int cseq; 5692882Svi117747 sip_header_t fhdr = NULL; 5702882Svi117747 sip_header_t thdr = NULL; 5712882Svi117747 sip_header_t chdr; 5722882Svi117747 sip_header_t cihdr; 5732882Svi117747 sip_header_t evhdr = NULL; 5742882Svi117747 const struct sip_value *value; 5752882Svi117747 sip_dialog_timer_obj_t *tim_obj = NULL; 5762882Svi117747 const sip_str_t *callid; 5772882Svi117747 sip_method_t method; 5782882Svi117747 int timer1 = sip_timer_T1; 5792882Svi117747 int error; 5802882Svi117747 5812882Svi117747 if (!sip_msg_is_request((sip_msg_t)sip_msg, &error)) 5822882Svi117747 return (NULL); 5832882Svi117747 5842882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 5852882Svi117747 /* 5862882Svi117747 * Only INVITE and SUBSCRIBE supported 5872882Svi117747 */ 5882882Svi117747 if (error != 0 || (method != INVITE && method != SUBSCRIBE)) 5892882Svi117747 return (NULL); 5902882Svi117747 5912882Svi117747 /* 5922882Svi117747 * A request outside of a dialog MUST NOT contain a To tag 5932882Svi117747 */ 5942882Svi117747 if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL) 5952882Svi117747 return (NULL); 5962882Svi117747 5972882Svi117747 if (dlg_type == SIP_UAS_DIALOG) { 5982882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 5992882Svi117747 SIP_DLG_XCHG_FROM); 6002882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 6012882Svi117747 } else { 6022882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 6032882Svi117747 fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL); 6042882Svi117747 } 6052882Svi117747 cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL); 6062882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 6072882Svi117747 if (method == SUBSCRIBE) 6082882Svi117747 evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 6092882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 6102882Svi117747 if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL || 6112882Svi117747 (method == SUBSCRIBE && evhdr == NULL)) { 6122882Svi117747 if (thdr != NULL) 6132882Svi117747 sip_free_header(thdr); 6142882Svi117747 return (NULL); 6152882Svi117747 } 6162882Svi117747 6172882Svi117747 /* 6182882Svi117747 * Sanity check since we just store the headers in the dialog 6192882Svi117747 */ 6202882Svi117747 if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL || 6212882Svi117747 sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 6222882Svi117747 ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) || 6232882Svi117747 (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL || 6242882Svi117747 sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 6252882Svi117747 ((value = sip_get_header_value(chdr, NULL)) == NULL) || 6262882Svi117747 sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) { 6272882Svi117747 if (thdr != NULL) 6282882Svi117747 sip_free_header(thdr); 6292882Svi117747 return (NULL); 6302882Svi117747 } 6312882Svi117747 6322882Svi117747 tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t)); 6332882Svi117747 if (tim_obj == NULL) { 6342882Svi117747 if (thdr != NULL) 6352882Svi117747 sip_free_header(thdr); 6362882Svi117747 return (NULL); 6372882Svi117747 } 6382882Svi117747 dialog = calloc(1, sizeof (_sip_dialog_t)); 6392882Svi117747 if (dialog == NULL) { 6402882Svi117747 if (thdr != NULL) 6412882Svi117747 sip_free_header(thdr); 6422882Svi117747 return (NULL); 6432882Svi117747 } 6442882Svi117747 /* 6452882Svi117747 * We will take the TO header with the tag when we complete this 6462882Svi117747 * dialog 6472882Svi117747 */ 6482882Svi117747 if (dlg_type == SIP_UAS_DIALOG) { 6492882Svi117747 dialog->sip_dlg_remote_uri_tag = thdr; 6502882Svi117747 /* 6512882Svi117747 * We take the remote target from the incoming request on the 6522882Svi117747 * UAS. For the UAC, we will take it from the response. 6532882Svi117747 */ 6542882Svi117747 if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == 6552882Svi117747 NULL) { 6562882Svi117747 goto dia_err; 6572882Svi117747 } 6582882Svi117747 } else { 6592882Svi117747 if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) == 6602882Svi117747 NULL) { 6612882Svi117747 goto dia_err; 6622882Svi117747 } 6632882Svi117747 } 6642882Svi117747 if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL) 6652882Svi117747 goto dia_err; 6662882Svi117747 if (method == SUBSCRIBE) { 6672882Svi117747 dialog->sip_dlg_event = sip_dup_header(evhdr); 6682882Svi117747 if (dialog->sip_dlg_event == NULL) { 6692882Svi117747 goto dia_err; 6702882Svi117747 } 6712882Svi117747 } 6722882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 6732882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 6742882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 6752882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 6762882Svi117747 /* 6772882Svi117747 * Get the route set from the request, if present 6782882Svi117747 */ 6792882Svi117747 if (dlg_type == SIP_UAS_DIALOG && 6802882Svi117747 sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) { 6812882Svi117747 goto dia_err; 6822882Svi117747 } 6832882Svi117747 if (dlg_type == SIP_UAC_DIALOG) 6842882Svi117747 dialog->sip_dlg_local_cseq = cseq; 6852882Svi117747 else 6862882Svi117747 dialog->sip_dlg_remote_cseq = cseq; 6872882Svi117747 dialog->sip_dlg_type = dlg_type; 6882882Svi117747 dialog->sip_dlg_on_fork = dlg_on_fork; 6892882Svi117747 dialog->sip_dlg_method = method; 6902882Svi117747 /* 6912882Svi117747 * Set the partial dialog timer with the INVITE timeout val 6922882Svi117747 */ 6932882Svi117747 if (sip_conn_timer1 != NULL) 6942882Svi117747 timer1 = sip_conn_timer1(obj); 6952882Svi117747 SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1); 6962882Svi117747 tim_obj->dialog = dialog; 6972882Svi117747 /* 6982882Svi117747 * Since at the client we never pass the partial dialog, we need not 6992882Svi117747 * invoke the callback when the partial dialog self-destructs. 7002882Svi117747 */ 7012882Svi117747 if (dlg_type == SIP_UAS_DIALOG) 7022882Svi117747 tim_obj->func = sip_ulp_dlg_del_cb; 7032882Svi117747 SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj, 7042882Svi117747 sip_dlg_self_destruct); 7052882Svi117747 if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 7062882Svi117747 goto dia_err; 7072882Svi117747 (void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL); 7082882Svi117747 7092882Svi117747 if (dlg_type == SIP_UAC_DIALOG) { 7102882Svi117747 const sip_str_t *local_tag; 7112882Svi117747 7122882Svi117747 local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 7132882Svi117747 assert(local_tag != NULL); 7142882Svi117747 sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len, 7152882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 7162882Svi117747 NULL, 0, NULL, 0, NULL, 0, NULL, 0, 7172882Svi117747 (uchar_t *)dialog->sip_dlg_id); 7182882Svi117747 7192882Svi117747 7202882Svi117747 /* 7212882Svi117747 * Add it to the partial hash table 7222882Svi117747 */ 7232882Svi117747 if (sip_hash_add(sip_dialog_phash, (void *)dialog, 7242882Svi117747 SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 7252882Svi117747 goto dia_err; 7262882Svi117747 } 7272882Svi117747 } 7282882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 7292882Svi117747 return ((sip_dialog_t)dialog); 7302882Svi117747 dia_err: 7312882Svi117747 sip_release_dialog_res(dialog); 7322882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 7332882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 7342882Svi117747 if (tim_obj != NULL) 7352882Svi117747 free(tim_obj); 7362882Svi117747 return (NULL); 7372882Svi117747 } 7382882Svi117747 7392882Svi117747 /* 7402882Svi117747 * When creating a dialog from a NOTIFY request, we need to get the FROM 7412882Svi117747 * header for the dialog from the TO header of the NOTIFY. 7422882Svi117747 */ 7432882Svi117747 _sip_header_t * 7442882Svi117747 sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what) 7452882Svi117747 { 7462882Svi117747 int len; 7472882Svi117747 _sip_header_t *newhdr; 7482882Svi117747 int cnt; 7492882Svi117747 const struct sip_header *hdr; 7502882Svi117747 int hdrsize; 7512882Svi117747 int error; 7522882Svi117747 7532882Svi117747 hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM : 7542882Svi117747 SIP_TO, NULL, &error); 7552882Svi117747 if (error != 0 || hdr == NULL) 7562882Svi117747 return (NULL); 7572882Svi117747 if (sip_parse_goto_values((_sip_header_t *)hdr) != 0) 7582882Svi117747 return (NULL); 7592882Svi117747 len = hdr->sip_hdr_end - hdr->sip_hdr_current; 7602882Svi117747 if (what == SIP_DLG_XCHG_FROM) { 7612882Svi117747 hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) + 7622882Svi117747 SIP_SPACE_LEN; 7632882Svi117747 } else { 7642882Svi117747 hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN + 7652882Svi117747 sizeof (char) + SIP_SPACE_LEN; 7662882Svi117747 } 7672882Svi117747 newhdr = sip_new_header(hdrsize); 7682882Svi117747 if (newhdr == NULL) 7692882Svi117747 return (NULL); 7702882Svi117747 if (what == SIP_DLG_XCHG_FROM) { 7712882Svi117747 cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 7722882Svi117747 "%s %c ", SIP_TO, SIP_HCOLON); 7732882Svi117747 } else { 7742882Svi117747 cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 7752882Svi117747 "%s %c ", SIP_FROM, SIP_HCOLON); 7762882Svi117747 } 7772882Svi117747 newhdr->sip_hdr_current += cnt; 7782882Svi117747 (void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len); 7792882Svi117747 newhdr->sip_hdr_current += len; 7802882Svi117747 assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end); 7812882Svi117747 assert(hdr->sip_header_functions != NULL); 7822882Svi117747 7832882Svi117747 /* 7842882Svi117747 * FROM and TO have common parsing functions 7852882Svi117747 */ 7862882Svi117747 newhdr->sip_header_functions = hdr->sip_header_functions; 7872882Svi117747 newhdr->sip_hdr_current = newhdr->sip_hdr_start; 7882882Svi117747 7892882Svi117747 return (newhdr); 7902882Svi117747 } 7912882Svi117747 7922882Svi117747 /* 7932882Svi117747 * This is the response that completes the dialog that was created 7942882Svi117747 * in sip_seed_dialog(). 7952882Svi117747 */ 7962882Svi117747 sip_dialog_t 7972882Svi117747 sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog) 7982882Svi117747 { 7992882Svi117747 _sip_header_t *thdr; 8002882Svi117747 _sip_header_t *evhdr = NULL; 8012882Svi117747 _sip_header_t *substate = NULL; 8022882Svi117747 sip_header_t chdr = NULL; 8032882Svi117747 int resp_code; 8042882Svi117747 const sip_str_t *ttag; 8052882Svi117747 const sip_str_t *remtag; 8062882Svi117747 const sip_str_t *callid; 8072882Svi117747 const struct sip_value *val; 8082882Svi117747 sip_method_t method; 8092882Svi117747 int error = 0; 8102882Svi117747 int prev_state; 8112882Svi117747 boolean_t alloc_thdr = B_FALSE; 8122882Svi117747 8132882Svi117747 if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0) 8142882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 8152882Svi117747 else 8162882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 8172882Svi117747 if (error != 0 || dialog == NULL || 8182882Svi117747 (sip_msg_is_request((sip_msg_t)sip_msg, &error) && 8192882Svi117747 (dialog->sip_dlg_method == INVITE || method != NOTIFY))) { 8202882Svi117747 return (NULL); 8212882Svi117747 } 8222882Svi117747 if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY && 8232882Svi117747 sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 8242882Svi117747 dialog->sip_dlg_local_cseq) || 8252882Svi117747 (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY && 8262882Svi117747 sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 8272882Svi117747 dialog->sip_dlg_remote_cseq)) { 8282882Svi117747 return (NULL); 8292882Svi117747 } 8302882Svi117747 if (method == NOTIFY) { 8312882Svi117747 const sip_str_t *sstate; 8322882Svi117747 8332882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 8342882Svi117747 SIP_DLG_XCHG_FROM); 8352882Svi117747 if (thdr == NULL) 8362882Svi117747 return (NULL); 8372882Svi117747 alloc_thdr = B_TRUE; 8382882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 8392882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 8402882Svi117747 if (chdr == NULL) { 8412882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8422882Svi117747 sip_free_header(thdr); 8432882Svi117747 return (NULL); 8442882Svi117747 } 8452882Svi117747 evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 8462882Svi117747 if (evhdr == NULL) { 8472882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8482882Svi117747 sip_free_header(thdr); 8492882Svi117747 return (NULL); 8502882Svi117747 } 8512882Svi117747 substate = sip_search_for_header(sip_msg, 8522882Svi117747 SIP_SUBSCRIPTION_STATE, NULL); 8532882Svi117747 if (substate == NULL) { 8542882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8552882Svi117747 sip_free_header(thdr); 8562882Svi117747 return (NULL); 8572882Svi117747 } 8582882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8592882Svi117747 sstate = sip_get_substate((sip_msg_t)sip_msg, &error); 8602882Svi117747 if (sstate == NULL || error != 0) { 8612882Svi117747 sip_free_header(thdr); 8622882Svi117747 return (NULL); 8632882Svi117747 } 8642882Svi117747 if ((sstate->sip_str_len != strlen("pending") && 8652882Svi117747 sstate->sip_str_len != strlen("active")) || 8662882Svi117747 ((sstate->sip_str_len == strlen("pending") && 8672882Svi117747 strncasecmp(sstate->sip_str_ptr, "pending", 8682882Svi117747 strlen("pending")) != 0) || 8692882Svi117747 (sstate->sip_str_len == strlen("active") && 8702882Svi117747 strncasecmp(sstate->sip_str_ptr, "active", 8712882Svi117747 strlen("active")) != 0))) { 8722882Svi117747 sip_free_header(thdr); 8732882Svi117747 return (NULL); 8742882Svi117747 } 8752882Svi117747 ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 8762882Svi117747 } else { 8772882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 8782882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 8792882Svi117747 SIP_DLG_XCHG_TO); 8802882Svi117747 alloc_thdr = B_TRUE; 8812882Svi117747 } else { 8822882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 8832882Svi117747 thdr = sip_search_for_header(sip_msg, SIP_TO, NULL); 8842882Svi117747 if (dialog->sip_dlg_remote_target == NULL) { 8852882Svi117747 chdr = sip_search_for_header(sip_msg, 8862882Svi117747 SIP_CONTACT, NULL); 8872882Svi117747 } 8882882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8892882Svi117747 } 8902882Svi117747 if (thdr == NULL) { 8912882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8922882Svi117747 return (NULL); 8932882Svi117747 } 8942882Svi117747 ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL); 8952882Svi117747 } 8962882Svi117747 if (ttag == NULL) { 8972882Svi117747 if (alloc_thdr) 8982882Svi117747 sip_free_header(thdr); 8992882Svi117747 return (NULL); 9002882Svi117747 } 9012882Svi117747 prev_state = dialog->sip_dlg_state; 9022882Svi117747 9032882Svi117747 if (method == NOTIFY) { 9042882Svi117747 int error; 9052882Svi117747 const sip_str_t *dlg_id_val = NULL; 9062882Svi117747 const sip_str_t *event; 9072882Svi117747 const sip_str_t *id_val = NULL; 9082882Svi117747 sip_header_value_t ev_val; 9092882Svi117747 sip_hdr_value_t *dlg_ev_val = NULL; 9102882Svi117747 9112882Svi117747 event = sip_get_event((sip_msg_t)sip_msg, &error); 9122882Svi117747 if (event == NULL || error != 0) { 9132882Svi117747 sip_free_header(thdr); 9142882Svi117747 return (NULL); 9152882Svi117747 } 9162882Svi117747 ev_val = (sip_header_value_t)sip_get_header_value(evhdr, 9172882Svi117747 &error); 9182882Svi117747 if (ev_val != NULL) 9192882Svi117747 id_val = sip_get_param_value(ev_val, "id", &error); 9202882Svi117747 if (error == 0) { 9212882Svi117747 dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value( 9222882Svi117747 dialog->sip_dlg_event, &error); 9232882Svi117747 } 9242882Svi117747 if (dlg_ev_val == NULL || error != 0) { 9252882Svi117747 sip_free_header(thdr); 9262882Svi117747 return (NULL); 9272882Svi117747 } 9282882Svi117747 dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val, 9292882Svi117747 "id", &error); 9302882Svi117747 if (error != 0 || 9312882Svi117747 dlg_ev_val->str_val_len != event->sip_str_len || 9322882Svi117747 strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr, 9332882Svi117747 event->sip_str_len != 0)) { 9342882Svi117747 sip_free_header(thdr); 9352882Svi117747 return (NULL); 9362882Svi117747 } 9372882Svi117747 if ((dlg_id_val == NULL && id_val != NULL) || 9382882Svi117747 (dlg_id_val != NULL && id_val == NULL)) { 9392882Svi117747 sip_free_header(thdr); 9402882Svi117747 return (NULL); 9412882Svi117747 } else if (dlg_id_val != NULL && id_val != NULL) { 9422882Svi117747 if (dlg_id_val->sip_str_len != id_val->sip_str_len || 9432882Svi117747 strncasecmp(dlg_id_val->sip_str_ptr, 9442882Svi117747 id_val->sip_str_ptr, dlg_id_val->sip_str_len) != 9452882Svi117747 0) { 9462882Svi117747 sip_free_header(thdr); 9472882Svi117747 return (NULL); 9482882Svi117747 } 9492882Svi117747 } 9502882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 9512882Svi117747 dialog->sip_dlg_remote_uri_tag = thdr; 9522882Svi117747 if ((dialog->sip_dlg_remote_target = 9532882Svi117747 sip_dup_header(chdr)) == NULL) { 9542882Svi117747 sip_free_header(thdr); 9552882Svi117747 return (NULL); 9562882Svi117747 } 9572882Svi117747 } else { 9582882Svi117747 dialog->sip_dlg_local_uri_tag = thdr; 9592882Svi117747 } 9602882Svi117747 dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 9612882Svi117747 } else { 9622882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 9632882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 9642882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_NEW); 9652882Svi117747 if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) { 9662882Svi117747 assert(dialog->sip_dlg_type == SIP_UAC_DIALOG); 9672882Svi117747 if ((dialog->sip_dlg_remote_target = 9682882Svi117747 sip_dup_header(chdr)) == NULL) { 9692882Svi117747 (void) pthread_mutex_unlock( 9702882Svi117747 &dialog->sip_dlg_mutex); 9712882Svi117747 if (alloc_thdr) 9722882Svi117747 sip_free_header(thdr); 9733439Svi117747 goto terminate_new_dlg; 9742882Svi117747 } 9752882Svi117747 if (sip_dialog_get_route_set(dialog, sip_msg, 9762882Svi117747 dialog->sip_dlg_type) != 0) { 9772882Svi117747 (void) pthread_mutex_unlock( 9782882Svi117747 &dialog->sip_dlg_mutex); 9792882Svi117747 if (alloc_thdr) 9802882Svi117747 sip_free_header(thdr); 9813439Svi117747 goto terminate_new_dlg; 9822882Svi117747 } 9832882Svi117747 } 9842882Svi117747 if (SIP_PROVISIONAL_RESP(resp_code)) { 9852882Svi117747 dialog->sip_dlg_state = SIP_DLG_EARLY; 9862882Svi117747 } else if (SIP_OK_RESP(resp_code)) { 9872882Svi117747 /* 9882882Svi117747 * Per 12.1 the UAS must include the contact header 9892882Svi117747 * for a dialog establishing response, so if we 9902882Svi117747 * don't find one, we terminate it. 9912882Svi117747 */ 9922882Svi117747 if (dialog->sip_dlg_remote_target == NULL) { 9932882Svi117747 (void) pthread_mutex_unlock( 9942882Svi117747 &dialog->sip_dlg_mutex); 9952882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 9962882Svi117747 sip_ulp_dlg_del_cb(dialog, 9972882Svi117747 (sip_msg_t)sip_msg, NULL); 9982882Svi117747 } 9992882Svi117747 if (alloc_thdr) 10002882Svi117747 sip_free_header(thdr); 10013439Svi117747 goto terminate_new_dlg; 10022882Svi117747 } 10032882Svi117747 dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 10042882Svi117747 } else { 10052882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 10062882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 10072882Svi117747 sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg, 10082882Svi117747 NULL); 10092882Svi117747 } 10102882Svi117747 if (alloc_thdr) 10112882Svi117747 sip_free_header(thdr); 10123439Svi117747 goto terminate_new_dlg; 10132882Svi117747 } 10142882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 10152882Svi117747 dialog->sip_dlg_local_uri_tag = thdr; 10162882Svi117747 } else { 10172882Svi117747 if ((dialog->sip_dlg_remote_uri_tag = 10182882Svi117747 sip_dup_header(thdr)) == NULL) { 10192882Svi117747 (void) pthread_mutex_unlock( 10202882Svi117747 &dialog->sip_dlg_mutex); 10213439Svi117747 goto terminate_new_dlg; 10222882Svi117747 } 10232882Svi117747 } 10242882Svi117747 } 10252882Svi117747 10262882Svi117747 /* 10272882Svi117747 * Cancel the partial dialog timer 10282882Svi117747 */ 10292882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 10302882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 10312882Svi117747 10322882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 10332882Svi117747 val = sip_get_header_value(dialog->sip_dlg_local_uri_tag, 10342882Svi117747 &error); 10352882Svi117747 } else { 10362882Svi117747 val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag, 10372882Svi117747 &error); 10382882Svi117747 } 10392882Svi117747 assert(val != NULL && error == 0); 10402882Svi117747 remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error); 10412882Svi117747 10422882Svi117747 val = sip_get_header_value(dialog->sip_dlg_call_id, &error); 10432882Svi117747 callid = &((sip_hdr_value_t *)val)->str_val; 10442882Svi117747 10452882Svi117747 /* 10462882Svi117747 * Get an ID for this dialog 10472882Svi117747 */ 10482882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 10492882Svi117747 sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len, 10502882Svi117747 ttag->sip_str_ptr, ttag->sip_str_len, 10512882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 10522882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 10532882Svi117747 } else { 10542882Svi117747 sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len, 10552882Svi117747 remtag->sip_str_ptr, remtag->sip_str_len, 10562882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 10572882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 10582882Svi117747 } 10592882Svi117747 10602882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 10612882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 10622882Svi117747 10632882Svi117747 /* 10642882Svi117747 * Add it to the hash table 10652882Svi117747 */ 10662882Svi117747 if (sip_hash_add(sip_dialog_hash, (void *)dialog, 10672882Svi117747 SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 10683439Svi117747 terminate_new_dlg: 10692882Svi117747 /* 10702882Svi117747 * So that sip_dialog_delete() does not try to remove 10712882Svi117747 * this from the hash table. 10722882Svi117747 */ 10732882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 10742882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 10753439Svi117747 if (dialog->sip_dlg_local_uri_tag != NULL) { 10763439Svi117747 sip_free_header(dialog->sip_dlg_local_uri_tag); 10773439Svi117747 dialog->sip_dlg_local_uri_tag = NULL; 10783439Svi117747 } 10792882Svi117747 } else { 10803439Svi117747 if (dialog->sip_dlg_remote_uri_tag != NULL) { 10813439Svi117747 sip_free_header(dialog->sip_dlg_remote_uri_tag); 10823439Svi117747 dialog->sip_dlg_remote_uri_tag = NULL; 10833439Svi117747 } 10842882Svi117747 } 10852882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 10862882Svi117747 sip_dialog_terminate(dialog, (sip_msg_t)sip_msg); 10872882Svi117747 return (NULL); 10882882Svi117747 } 10892882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 10902882Svi117747 sip_dlg_ulp_state_cb((sip_dialog_t)dialog, 10912882Svi117747 (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state); 10922882Svi117747 } 10932882Svi117747 return ((sip_dialog_t)dialog); 10942882Svi117747 } 10952882Svi117747 10962882Svi117747 /* 10972882Svi117747 * Check if this dialog is a match. 10982882Svi117747 */ 10992882Svi117747 boolean_t 11002882Svi117747 sip_dialog_match(void *obj, void *hindex) 11012882Svi117747 { 11022882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 11032882Svi117747 11042882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11052882Svi117747 if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 11062882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11072882Svi117747 return (B_FALSE); 11082882Svi117747 } 11092882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, 11102882Svi117747 sizeof (dialog->sip_dlg_id)) == 0) { 11112882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 11122882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11132882Svi117747 return (B_TRUE); 11142882Svi117747 } 11152882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11162882Svi117747 return (B_FALSE); 11172882Svi117747 } 11182882Svi117747 11192882Svi117747 /* 11202882Svi117747 * Don't delete, just take it out of the hash 11212882Svi117747 */ 11222882Svi117747 boolean_t 11232882Svi117747 sip_dialog_dontfree(void *obj, void *hindex, int *found) 11242882Svi117747 { 11252882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 11262882Svi117747 11272882Svi117747 *found = 0; 11282882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11292882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 11302882Svi117747 == 0) { 11312882Svi117747 *found = 1; 11322882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11332882Svi117747 return (B_TRUE); 11342882Svi117747 } 11352882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11362882Svi117747 return (B_FALSE); 11372882Svi117747 } 11382882Svi117747 11392882Svi117747 /* 11402882Svi117747 * Free resources associated with the dialog, the object will be removed 11412882Svi117747 * from the hash list by sip_hash_delete. 11422882Svi117747 */ 11432882Svi117747 boolean_t 11442882Svi117747 sip_dialog_free(void *obj, void *hindex, int *found) 11452882Svi117747 { 11462882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 11472882Svi117747 11482882Svi117747 *found = 0; 11492882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11502882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 11512882Svi117747 == 0) { 11522882Svi117747 *found = 1; 11532882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED); 11542882Svi117747 if (dialog->sip_dlg_ref_cnt != 0) { 11552882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11562882Svi117747 return (B_FALSE); 11572882Svi117747 } 11582882Svi117747 sip_release_dialog_res(dialog); 11592882Svi117747 return (B_TRUE); 11602882Svi117747 } 11612882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11622882Svi117747 return (B_FALSE); 11632882Svi117747 } 11642882Svi117747 11652882Svi117747 /* 11662882Svi117747 * The UAS will receive the request from the transaction layer. If the 11672882Svi117747 * request has a tag in the To header field, the UAS core computes the 11682882Svi117747 * dialog identifier corresponding to the request and compares it with 11692882Svi117747 * existing dialogs. If there is a match, this is a mid-dialog request. 11702882Svi117747 */ 11712882Svi117747 sip_dialog_t 11722882Svi117747 sip_dialog_find(_sip_msg_t *sip_msg) 11732882Svi117747 { 11742882Svi117747 const sip_str_t *localtag; 11752882Svi117747 const sip_str_t *remtag; 11762882Svi117747 const sip_str_t *callid; 11772882Svi117747 uint16_t digest[8]; 11782882Svi117747 _sip_dialog_t *dialog; 11792882Svi117747 boolean_t is_request; 11802882Svi117747 int error; 11812882Svi117747 11822882Svi117747 is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 11832882Svi117747 if (error != 0) 11842882Svi117747 return (NULL); 11852882Svi117747 if (is_request) { 11862882Svi117747 localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 11872882Svi117747 if (error == 0) 11882882Svi117747 remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 11892882Svi117747 } else { 11902882Svi117747 remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 11912882Svi117747 if (error == 0) 11922882Svi117747 localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 11932882Svi117747 } 11942882Svi117747 if (error != 0) 11952882Svi117747 return (NULL); 11962882Svi117747 callid = sip_get_callid((sip_msg_t)sip_msg, &error); 11972882Svi117747 if (error != 0 || remtag == NULL || localtag == NULL || 11982882Svi117747 callid == NULL) { 11992882Svi117747 return (NULL); 12002882Svi117747 } 12012882Svi117747 sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 12022882Svi117747 remtag->sip_str_ptr, remtag->sip_str_len, 12032882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 12042882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 12052882Svi117747 12062882Svi117747 dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash, 12072882Svi117747 (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match); 12082882Svi117747 if (dialog == NULL) { 12092882Svi117747 sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 12102882Svi117747 NULL, 0, callid->sip_str_ptr, callid->sip_str_len, 12112882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 12122882Svi117747 dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash, 12132882Svi117747 (void *)digest, SIP_DIGEST_TO_HASH(digest), 12142882Svi117747 sip_dialog_match); 12152882Svi117747 } 12162882Svi117747 return ((sip_dialog_t)dialog); 12172882Svi117747 } 12182882Svi117747 12192882Svi117747 /* 12202882Svi117747 * We keep this partial dialog for the duration of the INVITE 12212882Svi117747 * transaction timeout duration, i.e. Timer B. 12222882Svi117747 */ 12232882Svi117747 void 12242882Svi117747 sip_dlg_self_destruct(void *args) 12252882Svi117747 { 12262882Svi117747 sip_dialog_timer_obj_t *tim_obj = (sip_dialog_timer_obj_t *)args; 12272882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)tim_obj->dialog; 12282882Svi117747 int index; 12292882Svi117747 12302882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 12312882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_NEW); 12322882Svi117747 dialog->sip_dlg_state = SIP_DLG_DESTROYED; 12332882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 12342882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 12352882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12362882Svi117747 sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id, 12372882Svi117747 index, sip_dialog_dontfree); 12382882Svi117747 } else { 12392882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12402882Svi117747 } 12412882Svi117747 if (tim_obj->func != NULL) 12422882Svi117747 tim_obj->func(dialog, NULL, NULL); 12432882Svi117747 free(tim_obj); 12442882Svi117747 SIP_DLG_REFCNT_DECR(dialog); 12452882Svi117747 } 12462882Svi117747 12472882Svi117747 /* 12482882Svi117747 * Terminate a dialog 12492882Svi117747 */ 12502882Svi117747 void 12512882Svi117747 sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg) 12522882Svi117747 { 12532882Svi117747 int prev_state; 12542882Svi117747 12552882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 12562882Svi117747 prev_state = dialog->sip_dlg_state; 12572882Svi117747 dialog->sip_dlg_state = SIP_DLG_DESTROYED; 12582882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12592882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 12602882Svi117747 sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state, 12612882Svi117747 dialog->sip_dlg_state); 12622882Svi117747 } 12632882Svi117747 SIP_DLG_REFCNT_DECR(dialog); 12642882Svi117747 } 12652882Svi117747 12662882Svi117747 /* 12672882Svi117747 * Delete a dialog 12682882Svi117747 */ 12692882Svi117747 void 12702882Svi117747 sip_dialog_delete(_sip_dialog_t *dialog) 12712882Svi117747 { 12722882Svi117747 int index; 12732882Svi117747 12742882Svi117747 /* 12752882Svi117747 * partial dialog, not in the hash table 12762882Svi117747 */ 12772882Svi117747 if (dialog->sip_dlg_local_uri_tag == NULL || 12782882Svi117747 dialog->sip_dlg_remote_uri_tag == NULL) { 12792882Svi117747 /* 12802882Svi117747 * Cancel the partial dialog timer 12812882Svi117747 */ 12822882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 12832882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 12842882Svi117747 sip_release_dialog_res(dialog); 12852882Svi117747 return; 12862882Svi117747 } 12872882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 12882882Svi117747 sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index, 12892882Svi117747 sip_dialog_free); 12902882Svi117747 } 12912882Svi117747 12922882Svi117747 /* 12932882Svi117747 * Get the remote target from the CONTACT header from the 200 OK response 12942882Svi117747 */ 12952882Svi117747 static boolean_t 12962882Svi117747 sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg) 12972882Svi117747 { 12982882Svi117747 sip_header_t chdr; 12992882Svi117747 13002882Svi117747 if (dialog->sip_dlg_remote_target != NULL) 13012882Svi117747 return (B_TRUE); 13022882Svi117747 13032882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 13042882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 13052882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 13062882Svi117747 if (chdr == NULL) 13072882Svi117747 return (B_FALSE); 13082882Svi117747 if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL) 13092882Svi117747 return (B_FALSE); 13102882Svi117747 13112882Svi117747 return (B_TRUE); 13122882Svi117747 } 13132882Svi117747 13142882Svi117747 /* 13152882Svi117747 * Process an incoming request/response 13162882Svi117747 */ 13172882Svi117747 /* ARGSUSED */ 13182882Svi117747 int 13192882Svi117747 sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog) 13202882Svi117747 { 13212882Svi117747 boolean_t request; 13222882Svi117747 _sip_dialog_t *_dialog; 13232882Svi117747 int error; 13242882Svi117747 13252882Svi117747 request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 13262882Svi117747 if (error != 0) 13272882Svi117747 return (EINVAL); 13282882Svi117747 _dialog = (_sip_dialog_t *)*sip_dialog; 13292882Svi117747 if (request) { 13302882Svi117747 uint32_t cseq; 13312882Svi117747 sip_method_t method; 13322882Svi117747 13332882Svi117747 cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error); 13342882Svi117747 if (error != 0) 13352882Svi117747 return (EINVAL); 13362882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 13372882Svi117747 if (error != 0) 13382882Svi117747 return (EINVAL); 13392882Svi117747 if (sip_get_request_method((sip_msg_t)sip_msg, &error) != 13402882Svi117747 method) { 13412882Svi117747 return (EINVAL); 13422882Svi117747 } 13432882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 13442882Svi117747 /* 13452882Svi117747 * Requests that do not change in any way the state 13462882Svi117747 * of a dialog may be received within a dialog. 13472882Svi117747 * They are processed as if they had been received 13482882Svi117747 * outside the dialog. 13492882Svi117747 * For dialogs that have been established with an 13502882Svi117747 * INVITE, the only target refresh request defined is 13512882Svi117747 * re-INVITE. 13522882Svi117747 */ 13532882Svi117747 if (_dialog->sip_dlg_method == INVITE && 13542882Svi117747 method == INVITE && _dialog->sip_dlg_remote_cseq != 0 && 13552882Svi117747 SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) { 13562882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 13572882Svi117747 return (EPROTO); 13582882Svi117747 } 13592882Svi117747 /* 13602882Svi117747 * Target-Refresh request 13612882Svi117747 */ 13622882Svi117747 if (_dialog->sip_dlg_method == INVITE && method == INVITE) { 13632882Svi117747 sip_header_t chdr; 13642882Svi117747 sip_header_t nchdr; 13652882Svi117747 13662882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 13672882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 13682882Svi117747 NULL); 13692882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 13702882Svi117747 if (chdr != NULL && 13712882Svi117747 (nchdr = sip_dup_header(chdr)) != NULL) { 13722882Svi117747 if (_dialog->sip_dlg_remote_target != NULL) { 13732882Svi117747 sip_free_header( 13742882Svi117747 _dialog->sip_dlg_remote_target); 13752882Svi117747 } 13762882Svi117747 _dialog->sip_dlg_remote_target = nchdr; 13772882Svi117747 } 13782882Svi117747 } 13792882Svi117747 _dialog->sip_dlg_remote_cseq = cseq; 13802882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 13812882Svi117747 } else { 13822882Svi117747 int resp_code; 13832882Svi117747 sip_method_t method; 13842882Svi117747 int error; 13852882Svi117747 13862882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 13872882Svi117747 if (error == 0) { 13882882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, 13892882Svi117747 &error); 13902882Svi117747 } 13912882Svi117747 if (error != 0) 13922882Svi117747 return (error); 13932882Svi117747 13942882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 1395*4641Sgm209912 if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 1396*4641Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1397*4641Sgm209912 return (0); 1398*4641Sgm209912 } 13992882Svi117747 assert(_dialog->sip_dlg_state == SIP_DLG_EARLY || 14002882Svi117747 _dialog->sip_dlg_state == SIP_DLG_CONFIRMED); 14012882Svi117747 /* 14022882Svi117747 * Let the user delete the dialog if it is not a 1XX/2XX resp 14032882Svi117747 * for an early INVITE dialog. 14042882Svi117747 */ 14052882Svi117747 if (SIP_OK_RESP(resp_code)) { 14062882Svi117747 if (method == INVITE) { 14072882Svi117747 if (!sip_get_rtarg(_dialog, sip_msg)) { 14082882Svi117747 (void) pthread_mutex_unlock( 14092882Svi117747 &_dialog->sip_dlg_mutex); 14102882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 14112882Svi117747 sip_ulp_dlg_del_cb( 14122882Svi117747 (sip_dialog_t)_dialog, 14132882Svi117747 (sip_msg_t)sip_msg, NULL); 14142882Svi117747 } 14152882Svi117747 sip_dialog_terminate(_dialog, 14162882Svi117747 (sip_msg_t)sip_msg); 14172882Svi117747 return (0); 14182882Svi117747 } 14192882Svi117747 if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 14202882Svi117747 _dialog->sip_dlg_state = 14212882Svi117747 SIP_DLG_CONFIRMED; 14222882Svi117747 (void) pthread_mutex_unlock( 14232882Svi117747 &_dialog->sip_dlg_mutex); 14242882Svi117747 (void) sip_dlg_recompute_rset(_dialog, 14252882Svi117747 sip_msg, SIP_UAC_DIALOG); 14262882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 14272882Svi117747 sip_dlg_ulp_state_cb( 14282882Svi117747 (sip_dialog_t)_dialog, 14292882Svi117747 sip_msg, SIP_DLG_EARLY, 14302882Svi117747 _dialog->sip_dlg_state); 14312882Svi117747 } 14322882Svi117747 return (0); 14332882Svi117747 } 14342882Svi117747 } 14352882Svi117747 } 14362882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 14372882Svi117747 } 14382882Svi117747 return (0); 14392882Svi117747 } 14402882Svi117747 14412882Svi117747 /* 14422882Svi117747 * Copy partial dialog to create a complete dialog 14432882Svi117747 */ 14442882Svi117747 _sip_dialog_t * 14452882Svi117747 sip_copy_partial_dialog(_sip_dialog_t *dialog) 14462882Svi117747 { 14472882Svi117747 _sip_dialog_t *new_dlg; 14482882Svi117747 14492882Svi117747 new_dlg = calloc(1, sizeof (_sip_dialog_t)); 14502882Svi117747 if (new_dlg == NULL) 14512882Svi117747 return (NULL); 14522882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 14532882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_ptr = 14542882Svi117747 malloc(dialog->sip_dlg_req_uri.sip_str_len + 1); 14552882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) { 14562882Svi117747 free(new_dlg); 14572882Svi117747 return (NULL); 14582882Svi117747 } 14592882Svi117747 (void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr, 14602882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr, 14612882Svi117747 dialog->sip_dlg_req_uri.sip_str_len); 14622882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_ptr[ 14632882Svi117747 dialog->sip_dlg_req_uri.sip_str_len] = '\0'; 14642882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_len = 14652882Svi117747 dialog->sip_dlg_req_uri.sip_str_len; 14662882Svi117747 } 14672882Svi117747 if (dialog->sip_dlg_route_set != NULL) { 14682882Svi117747 assert(dialog->sip_dlg_rset.sip_str_ptr != NULL); 14692882Svi117747 new_dlg->sip_dlg_rset.sip_str_ptr = 14702882Svi117747 malloc(dialog->sip_dlg_rset.sip_str_len + 1); 14712882Svi117747 if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) { 14722882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 14732882Svi117747 free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 14742882Svi117747 free(new_dlg); 14752882Svi117747 return (NULL); 14762882Svi117747 } 14772882Svi117747 (void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr, 14782882Svi117747 dialog->sip_dlg_rset.sip_str_ptr, 14792882Svi117747 dialog->sip_dlg_rset.sip_str_len); 14802882Svi117747 new_dlg->sip_dlg_rset.sip_str_ptr[ 14812882Svi117747 dialog->sip_dlg_rset.sip_str_len] = '\0'; 14822882Svi117747 new_dlg->sip_dlg_rset.sip_str_len = 14832882Svi117747 dialog->sip_dlg_rset.sip_str_len; 14842882Svi117747 14852882Svi117747 new_dlg->sip_dlg_route_set = 14862882Svi117747 sip_dup_header(dialog->sip_dlg_route_set); 14872882Svi117747 if (new_dlg->sip_dlg_route_set == NULL) { 14882882Svi117747 free(new_dlg->sip_dlg_rset.sip_str_ptr); 14892882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 14902882Svi117747 free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 14912882Svi117747 free(new_dlg); 14922882Svi117747 return (NULL); 14932882Svi117747 } 14942882Svi117747 } 14952882Svi117747 if ((new_dlg->sip_dlg_local_uri_tag = 14962882Svi117747 sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL || 14972882Svi117747 (new_dlg->sip_dlg_remote_target = 14982882Svi117747 sip_dup_header(dialog->sip_dlg_remote_target)) == NULL || 14992882Svi117747 (new_dlg->sip_dlg_call_id = 15002882Svi117747 sip_dup_header(dialog->sip_dlg_call_id)) == NULL) { 15012882Svi117747 sip_release_dialog_res(new_dlg); 15022882Svi117747 return (NULL); 15032882Svi117747 } 15042882Svi117747 if (dialog->sip_dlg_event != NULL) { 15052882Svi117747 new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event); 15062882Svi117747 if (new_dlg->sip_dlg_event == NULL) { 15072882Svi117747 sip_release_dialog_res(new_dlg); 15082882Svi117747 return (NULL); 15092882Svi117747 } 15102882Svi117747 } 15112882Svi117747 new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq; 15122882Svi117747 new_dlg->sip_dlg_type = dialog->sip_dlg_type; 15132882Svi117747 new_dlg->sip_dlg_on_fork = B_FALSE; 15142882Svi117747 (void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL); 15152882Svi117747 15162882Svi117747 return (new_dlg); 15172882Svi117747 } 15182882Svi117747 15192882Svi117747 /* 15202882Svi117747 * Update the dialog using the response 15212882Svi117747 */ 15222882Svi117747 sip_dialog_t 15232882Svi117747 sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg) 15242882Svi117747 { 15252882Svi117747 _sip_dialog_t *_dialog; 15262882Svi117747 boolean_t isreq; 15272882Svi117747 sip_method_t method; 15282882Svi117747 int resp_code = 0; 15292882Svi117747 int prev_state; 15302882Svi117747 boolean_t decr_ref = B_FALSE; 15312882Svi117747 int error; 15322882Svi117747 15332882Svi117747 isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error); 15342882Svi117747 if (error != 0) 15352882Svi117747 return (dialog); 15362882Svi117747 _dialog = (_sip_dialog_t *)dialog; 15372882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 15382882Svi117747 if (isreq) { 15392882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 15402882Svi117747 if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE || 15412882Svi117747 method != NOTIFY) { 15422882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15432882Svi117747 return (dialog); 15442882Svi117747 } 15452882Svi117747 } else { 15462882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 15472882Svi117747 if (error != 0) { 15482882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15492882Svi117747 return (dialog); 15502882Svi117747 } 15512882Svi117747 } 15522882Svi117747 prev_state = _dialog->sip_dlg_state; 15532882Svi117747 if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) { 15542882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15552882Svi117747 } else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 15562882Svi117747 /* 15572882Svi117747 * Let the user delete the dialog if it is not a 1XX/2XX resp 15582882Svi117747 * for an early dialog. 15592882Svi117747 */ 15602882Svi117747 assert(!isreq); 15612882Svi117747 if (SIP_OK_RESP(resp_code)) { 15622882Svi117747 _dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 15632882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15642882Svi117747 (void) sip_dlg_recompute_rset(_dialog, sip_msg, 15652882Svi117747 SIP_UAS_DIALOG); 15662882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 15672882Svi117747 sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg, 15682882Svi117747 prev_state, dialog->sip_dlg_state); 15692882Svi117747 } 15702882Svi117747 } else { 15712882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15722882Svi117747 } 15732882Svi117747 } else if (_dialog->sip_dlg_state == SIP_DLG_NEW) { 15742882Svi117747 if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE && 15752882Svi117747 SIP_PROVISIONAL_RESP(resp_code)) { 15762882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15772882Svi117747 return (dialog); 15782882Svi117747 } 15792882Svi117747 if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) { 15802882Svi117747 _sip_dialog_t *new_dlg; 15812882Svi117747 15822882Svi117747 if (_dialog->sip_dlg_on_fork) { 15832882Svi117747 new_dlg = sip_copy_partial_dialog(_dialog); 15842882Svi117747 if (new_dlg == NULL) { 15852882Svi117747 (void) pthread_mutex_unlock( 15862882Svi117747 &_dialog->sip_dlg_mutex); 15872882Svi117747 return (dialog); 15882882Svi117747 } 15892882Svi117747 /* 15902882Svi117747 * This decr/incr dance is because the caller 15912882Svi117747 * has incremented the ref on the partial 15922882Svi117747 * dialog, we release it here and incr the 15932882Svi117747 * ref on the new dialog which will be 15942882Svi117747 * released by the caller. 15952882Svi117747 */ 15962882Svi117747 (void) pthread_mutex_unlock( 15972882Svi117747 &_dialog->sip_dlg_mutex); 15982882Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 15992882Svi117747 _dialog = new_dlg; 16002882Svi117747 (void) pthread_mutex_lock( 16012882Svi117747 &_dialog->sip_dlg_mutex); 16022882Svi117747 SIP_DLG_REFCNT_INCR(_dialog); 16032882Svi117747 } else { 16042882Svi117747 int index; 16052882Svi117747 16062882Svi117747 /* 16072882Svi117747 * take it out of the list so that further 16082882Svi117747 * responses will not result in a dialog. 16092882Svi117747 * We will have an extra refcount when we 16102882Svi117747 * come back from sip_complete_dialog(), i.e. 16112882Svi117747 * one when the partial dialog was created - 16122882Svi117747 * in sip_seed_dialog(), one held by the caller 16132882Svi117747 * and one that will be added by 16142882Svi117747 * sip_complete_dialog(). We need to release 16152882Svi117747 * the one added by the sip_seed_dialog(), 16162882Svi117747 * since the one in sip_complete_dialog() 16172882Svi117747 * is for the same purpose. 16182882Svi117747 */ 16192882Svi117747 if (SIP_IS_TIMER_RUNNING( 16202882Svi117747 _dialog->sip_dlg_timer)) { 16212882Svi117747 SIP_CANCEL_TIMER( 16222882Svi117747 _dialog->sip_dlg_timer); 16232882Svi117747 } 16242882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 16252882Svi117747 (void) pthread_mutex_unlock( 16262882Svi117747 &_dialog->sip_dlg_mutex); 16272882Svi117747 sip_hash_delete(sip_dialog_phash, 16282882Svi117747 (void *)_dialog->sip_dlg_id, 16292882Svi117747 index, sip_dialog_dontfree); 16302882Svi117747 (void) pthread_mutex_lock( 16312882Svi117747 &_dialog->sip_dlg_mutex); 16322882Svi117747 decr_ref = B_TRUE; 16332882Svi117747 } 16342882Svi117747 } else { 16352882Svi117747 decr_ref = B_TRUE; 16362882Svi117747 } 16372882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16382882Svi117747 if ((dialog = sip_complete_dialog(sip_msg, _dialog)) == 16392882Svi117747 NULL) { 16403439Svi117747 if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref) 16413439Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 16422882Svi117747 return (NULL); 16432882Svi117747 } 16442882Svi117747 if (decr_ref) 16452882Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 16462882Svi117747 } else { 16472882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16482882Svi117747 } 16492882Svi117747 return (dialog); 16502882Svi117747 } 16512882Svi117747 16522882Svi117747 /* 16532882Svi117747 * Initialize the hash table 16542882Svi117747 */ 16552882Svi117747 void 16562882Svi117747 sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *), 16572882Svi117747 void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int)) 16582882Svi117747 { 16592882Svi117747 int cnt; 16602882Svi117747 16612882Svi117747 for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) { 16622882Svi117747 sip_dialog_hash[cnt].hash_count = 0; 16632882Svi117747 sip_dialog_hash[cnt].hash_head = NULL; 16642882Svi117747 sip_dialog_hash[cnt].hash_tail = NULL; 16652882Svi117747 (void) pthread_mutex_init( 16662882Svi117747 &sip_dialog_hash[cnt].sip_hash_mutex, NULL); 16672882Svi117747 sip_dialog_phash[cnt].hash_count = 0; 16682882Svi117747 sip_dialog_phash[cnt].hash_head = NULL; 16692882Svi117747 sip_dialog_phash[cnt].hash_tail = NULL; 16702882Svi117747 (void) pthread_mutex_init( 16712882Svi117747 &sip_dialog_phash[cnt].sip_hash_mutex, NULL); 16722882Svi117747 } 16732882Svi117747 if (ulp_dlg_del != NULL) 16742882Svi117747 sip_ulp_dlg_del_cb = ulp_dlg_del; 16752882Svi117747 16762882Svi117747 if (ulp_state_cb != NULL) 16772882Svi117747 sip_dlg_ulp_state_cb = ulp_state_cb; 16782882Svi117747 } 1679