LCOV - code coverage report
Current view: top level - media/webrtc/signaling/src/sdp/sipcc - sdp_attr.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 2475 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 98 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include <errno.h>
       6             : #include <limits.h>
       7             : #include <stdio.h>
       8             : 
       9             : #include "plstr.h"
      10             : #include "sdp_os_defs.h"
      11             : #include "sdp.h"
      12             : #include "sdp_private.h"
      13             : #include "sdp_base64.h"
      14             : 
      15             : #include "CSFLog.h"
      16             : 
      17             : static const char* logTag = "sdp_attr";
      18             : 
      19             : /*
      20             :  * Macro for sdp_build_attr_fmtp
      21             :  * Adds name-value pair where value is char*
      22             :  */
      23             : #define FMTP_BUILD_STRING(condition, name, value) \
      24             :   if ((condition)) { \
      25             :     sdp_append_name_and_string(fs, (name), (value), semicolon); \
      26             :     semicolon = TRUE; \
      27             :   }
      28             : 
      29             : /*
      30             :  * Macro for sdp_build_attr_fmtp
      31             :  * Adds name-value pair where value is unsigned
      32             :  */
      33             : #define FMTP_BUILD_UNSIGNED(condition, name, value) \
      34             :   if ((condition)) { \
      35             :     sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \
      36             :     semicolon = TRUE; \
      37             :   }
      38             : 
      39             : /*
      40             :  * Macro for sdp_build_attr_fmtp
      41             :  * Adds flag string on condition
      42             :  */
      43             : #define FMTP_BUILD_FLAG(condition, name) \
      44             :   if ((condition)) { \
      45             :     if (semicolon) { \
      46             :       flex_string_append(fs, ";"); \
      47             :     } \
      48             :     flex_string_append(fs, name); \
      49             :     semicolon = TRUE; \
      50             :   }
      51             : 
      52           0 : static int find_token_enum(const char *attr_name,
      53             :                            sdp_t *sdp_p,
      54             :                            const char **ptr,
      55             :                            const sdp_namearray_t *types,
      56             :                            int type_count,
      57             :                            int unknown_value)
      58             : {
      59           0 :     sdp_result_e  result = SDP_SUCCESS;
      60             :     char          tmp[SDP_MAX_STRING_LEN+1];
      61             :     int           i;
      62             : 
      63           0 :     *ptr = sdp_getnextstrtok(*ptr, tmp, sizeof(tmp), " \t", &result);
      64           0 :     if (result != SDP_SUCCESS) {
      65           0 :         sdp_parse_error(sdp_p,
      66           0 :             "%s Warning: problem parsing %s", sdp_p->debug_str, attr_name);
      67           0 :         sdp_p->conf_p->num_invalid_param++;
      68           0 :         return -1;
      69             :     }
      70             : 
      71           0 :     for (i=0; i < type_count; i++) {
      72           0 :         if (!cpr_strncasecmp(tmp, types[i].name, types[i].strlen)) {
      73           0 :             return i;
      74             :         }
      75             :     }
      76           0 :     return unknown_value;
      77             : }
      78             : 
      79             : /*
      80             :  * Helper function for adding nv-pair where value is string.
      81             :  */
      82           0 : static void sdp_append_name_and_string(flex_string *fs,
      83             :   const char *name,
      84             :   const char *value,
      85             :   tinybool semicolon)
      86             : {
      87           0 :   flex_string_sprintf(fs, "%s%s=%s",
      88             :     semicolon ? ";" : "",
      89             :     name,
      90             :     value);
      91           0 : }
      92             : 
      93             : /*
      94             :  * Helper function for adding nv-pair where value is unsigned.
      95             :  */
      96           0 : static void sdp_append_name_and_unsigned(flex_string *fs,
      97             :   const char *name,
      98             :   unsigned int value,
      99             :   tinybool semicolon)
     100             : {
     101           0 :   flex_string_sprintf(fs, "%s%s=%u",
     102             :     semicolon ? ";" : "",
     103             :     name,
     104             :     value);
     105           0 : }
     106             : 
     107             : /* Function:    sdp_parse_attribute
     108             :  * Description: Figure out the type of attribute and call the appropriate
     109             :  *              parsing routine.  If parsing errors are encountered,
     110             :  *              warnings will be printed and the attribute will be ignored.
     111             :  *              Unrecognized/invalid attributes do not cause overall parsing
     112             :  *              errors.  All errors detected are noted as warnings.
     113             :  * Parameters:  sdp_p       The SDP handle returned by sdp_init_description.
     114             :  *              level       The level to check for the attribute.
     115             :  *              ptr         Pointer to the attribute string to parse.
     116             :  */
     117           0 : sdp_result_e sdp_parse_attribute (sdp_t *sdp_p, uint16_t level, const char *ptr)
     118             : {
     119             :     int           i;
     120           0 :     uint8_t            xcpar_flag = FALSE;
     121             :     sdp_result_e  result;
     122           0 :     sdp_mca_t    *mca_p=NULL;
     123             :     sdp_attr_t   *attr_p;
     124             :     sdp_attr_t   *next_attr_p;
     125           0 :     sdp_attr_t   *prev_attr_p = NULL;
     126             :     char          tmp[SDP_MAX_STRING_LEN];
     127             : 
     128             :     /* Validate the level */
     129           0 :     if (level != SDP_SESSION_LEVEL) {
     130           0 :         mca_p = sdp_find_media_level(sdp_p, level);
     131           0 :         if (mca_p == NULL) {
     132           0 :             return (SDP_FAILURE);
     133             :         }
     134             :     }
     135             : 
     136             :     /* Find the attribute type. */
     137           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
     138           0 :     if (ptr == NULL) {
     139           0 :         sdp_parse_error(sdp_p,
     140           0 :           "%s No attribute type specified, parse failed.", sdp_p->debug_str);
     141           0 :         sdp_p->conf_p->num_invalid_param++;
     142           0 :         return (SDP_INVALID_PARAMETER);
     143             :     }
     144           0 :     if (ptr[0] == ':') {
     145             :         /* Skip the ':' char for parsing attribute parameters. */
     146           0 :         ptr++;
     147             :     }
     148           0 :     if (result != SDP_SUCCESS) {
     149           0 :         sdp_parse_error(sdp_p,
     150           0 :           "%s No attribute type specified, parse failed.", sdp_p->debug_str);
     151           0 :         sdp_p->conf_p->num_invalid_param++;
     152           0 :         return (SDP_INVALID_PARAMETER);
     153             :     }
     154             : 
     155           0 :     attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
     156           0 :     if (attr_p == NULL) {
     157           0 :         sdp_p->conf_p->num_no_resource++;
     158           0 :         return (SDP_NO_RESOURCE);
     159             :     }
     160           0 :     attr_p->line_number = sdp_p->parse_line;
     161           0 :     attr_p->type = SDP_ATTR_INVALID;
     162           0 :     attr_p->next_p = NULL;
     163           0 :     for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
     164           0 :         if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
     165           0 :             attr_p->type = (sdp_attr_e)i;
     166           0 :             break;
     167             :         }
     168             :     }
     169           0 :     if (attr_p->type == SDP_ATTR_INVALID) {
     170           0 :         sdp_parse_error(sdp_p,
     171             :           "%s Warning: Unrecognized attribute (%s) ",
     172           0 :           sdp_p->debug_str, tmp);
     173           0 :         sdp_free_attr(attr_p);
     174           0 :         return (SDP_SUCCESS);
     175             :     }
     176             : 
     177             :     /* If this is an X-cpar or cpar attribute, set the flag.  The attribute
     178             :      * type will be changed by the parse. */
     179           0 :     if ((attr_p->type == SDP_ATTR_X_CPAR) ||
     180           0 :         (attr_p->type == SDP_ATTR_CPAR)) {
     181           0 :         xcpar_flag = TRUE;
     182             :     }
     183             : 
     184             :     /* Parse the attribute. */
     185           0 :     result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
     186           0 :     if (result != SDP_SUCCESS) {
     187           0 :         sdp_free_attr(attr_p);
     188             :         /* Return success so the parse won't fail.  We don't want to
     189             :          * fail on errors with attributes but just ignore them.
     190             :          */
     191           0 :         return (SDP_SUCCESS);
     192             :     }
     193             : 
     194             :     /* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc
     195             :      * structure, so we're finished.
     196             :      */
     197           0 :     if (xcpar_flag == TRUE) {
     198           0 :         return (result);
     199             :     }
     200             : 
     201             :     /* Add the attribute in the appropriate place. */
     202           0 :     if (level == SDP_SESSION_LEVEL) {
     203           0 :         for (next_attr_p = sdp_p->sess_attrs_p; next_attr_p != NULL;
     204           0 :              prev_attr_p = next_attr_p,
     205           0 :                  next_attr_p = next_attr_p->next_p) {
     206             :             ; /* Empty for */
     207             :         }
     208           0 :         if (prev_attr_p == NULL) {
     209           0 :             sdp_p->sess_attrs_p = attr_p;
     210             :         } else {
     211           0 :             prev_attr_p->next_p = attr_p;
     212             :         }
     213             :     } else {
     214           0 :         for (next_attr_p = mca_p->media_attrs_p; next_attr_p != NULL;
     215           0 :              prev_attr_p = next_attr_p,
     216           0 :                  next_attr_p = next_attr_p->next_p) {
     217             :             ; /* Empty for */
     218             :         }
     219           0 :         if (prev_attr_p == NULL) {
     220           0 :             mca_p->media_attrs_p = attr_p;
     221             :         } else {
     222           0 :             prev_attr_p->next_p = attr_p;
     223             :         }
     224             :     }
     225             : 
     226           0 :     return (result);
     227             : }
     228             : 
     229             : /* Build all of the attributes defined for the specified level. */
     230           0 : sdp_result_e sdp_build_attribute (sdp_t *sdp_p, uint16_t level, flex_string *fs)
     231             : {
     232             :     sdp_attr_t   *attr_p;
     233           0 :     sdp_mca_t    *mca_p=NULL;
     234             :     sdp_result_e  result;
     235             : 
     236           0 :     if (level == SDP_SESSION_LEVEL) {
     237           0 :         attr_p = sdp_p->sess_attrs_p;
     238             :     } else {
     239           0 :         mca_p = sdp_find_media_level(sdp_p, level);
     240           0 :         if (mca_p == NULL) {
     241           0 :             return (SDP_FAILURE);
     242             :         }
     243           0 :         attr_p = mca_p->media_attrs_p;
     244             :     }
     245             :     /* Re-initialize the current capability number for this new level. */
     246           0 :     sdp_p->cur_cap_num = 1;
     247             : 
     248             :     /* Build all of the attributes for this level. Note that if there
     249             :      * is a problem building an attribute, we don't fail but just ignore it.*/
     250           0 :     while (attr_p != NULL) {
     251           0 :         if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
     252           0 :             if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
     253           0 :                 CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
     254             :                          sdp_p->debug_str, (unsigned)attr_p->type);
     255             :             }
     256             :         } else {
     257           0 :             result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
     258             : 
     259           0 :             if (result != SDP_SUCCESS) {
     260           0 :               CSFLogError(logTag, "%s error building attribute %d", __FUNCTION__, result);
     261           0 :               return result;
     262             :             }
     263             : 
     264           0 :             if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
     265           0 :                 SDP_PRINT("%s Built a=%s attribute line", sdp_p->debug_str,
     266             :                           sdp_get_attr_name(attr_p->type));
     267             :             }
     268             :         }
     269           0 :         attr_p = attr_p->next_p;
     270             :     }
     271             : 
     272           0 :     return SDP_SUCCESS;
     273             : }
     274             : 
     275           0 : sdp_result_e sdp_parse_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
     276             :                                            const char *ptr)
     277             : {
     278             :     sdp_result_e  result;
     279             : 
     280           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
     281             :       sizeof(attr_p->attr.string_val), " \t", &result);
     282             : 
     283           0 :     if (result != SDP_SUCCESS) {
     284           0 :         sdp_parse_error(sdp_p,
     285             :             "%s Warning: No string token found for %s attribute",
     286           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
     287           0 :         sdp_p->conf_p->num_invalid_param++;
     288           0 :         return (SDP_INVALID_PARAMETER);
     289             :     } else {
     290           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
     291           0 :             SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
     292             :                       sdp_get_attr_name(attr_p->type),
     293             :                       attr_p->attr.string_val);
     294             :         }
     295           0 :         return (SDP_SUCCESS);
     296             :     }
     297             : }
     298             : 
     299           0 : sdp_result_e sdp_build_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
     300             :   flex_string *fs)
     301             : {
     302           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
     303           0 :     attr_p->attr.string_val);
     304             : 
     305           0 :   return SDP_SUCCESS;
     306             : }
     307             : 
     308           0 : sdp_result_e sdp_parse_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
     309             :                                         const char *ptr)
     310             : {
     311             :     sdp_result_e  result;
     312             : 
     313           0 :     attr_p->attr.u32_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
     314             : 
     315           0 :     if (result != SDP_SUCCESS) {
     316           0 :         sdp_parse_error(sdp_p,
     317             :             "%s Warning: Numeric token for %s attribute not found",
     318           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
     319           0 :         sdp_p->conf_p->num_invalid_param++;
     320           0 :         return (SDP_INVALID_PARAMETER);
     321             :     } else {
     322           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
     323           0 :             SDP_PRINT("%s Parsed a=%s, %u", sdp_p->debug_str,
     324             :                       sdp_get_attr_name(attr_p->type), attr_p->attr.u32_val);
     325             :         }
     326           0 :         return (SDP_SUCCESS);
     327             :     }
     328             : }
     329             : 
     330           0 : sdp_result_e sdp_build_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
     331             :   flex_string *fs)
     332             : {
     333           0 :   flex_string_sprintf(fs, "a=%s:%u\r\n", sdp_attr[attr_p->type].name,
     334             :     attr_p->attr.u32_val);
     335             : 
     336           0 :   return SDP_SUCCESS;
     337             : }
     338             : 
     339           0 : sdp_result_e sdp_parse_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
     340             :                                          const char *ptr)
     341             : {
     342             :     sdp_result_e  result;
     343             : 
     344           0 :     if (sdp_getnextnumtok(ptr, &ptr, " \t", &result) == 0) {
     345           0 :         attr_p->attr.boolean_val = FALSE;
     346             :     } else {
     347           0 :         attr_p->attr.boolean_val= TRUE;
     348             :     }
     349             : 
     350           0 :     if (result != SDP_SUCCESS) {
     351           0 :         sdp_parse_error(sdp_p,
     352             :             "%s Warning: Boolean token for %s attribute not found",
     353           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
     354           0 :         sdp_p->conf_p->num_invalid_param++;
     355           0 :         return (SDP_INVALID_PARAMETER);
     356             :     } else {
     357           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
     358           0 :             if (attr_p->attr.boolean_val) {
     359           0 :                 SDP_PRINT("%s Parsed a=%s, boolean is TRUE", sdp_p->debug_str,
     360             :                           sdp_get_attr_name(attr_p->type));
     361             :             } else {
     362           0 :                 SDP_PRINT("%s Parsed a=%s, boolean is FALSE", sdp_p->debug_str,
     363             :                           sdp_get_attr_name(attr_p->type));
     364             :             }
     365             :         }
     366           0 :         return (SDP_SUCCESS);
     367             :     }
     368             : }
     369             : 
     370           0 : sdp_result_e sdp_build_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
     371             :   flex_string *fs)
     372             : {
     373           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
     374           0 :     attr_p->attr.boolean_val ? "1" : "0");
     375             : 
     376           0 :   return SDP_SUCCESS;
     377             : }
     378             : 
     379             : /*
     380             :  * sdp_parse_attr_maxprate
     381             :  *
     382             :  * This function parses maxprate attribute lines. The ABNF for this a=
     383             :  * line is:
     384             :  *    max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
     385             :  *    packet-rate = 1*DIGIT ["." 1*DIGIT]
     386             :  *
     387             :  * Returns:
     388             :  * SDP_INVALID_PARAMETER - If we are unable to parse the string OR if
     389             :  *                         packet-rate is not in the right format as per
     390             :  *                         the ABNF.
     391             :  *
     392             :  * SDP_SUCCESS - If we are able to successfully parse the a= line.
     393             :  */
     394           0 : sdp_result_e sdp_parse_attr_maxprate (sdp_t *sdp_p, sdp_attr_t *attr_p,
     395             :                                       const char *ptr)
     396             : {
     397             :     sdp_result_e  result;
     398             : 
     399           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
     400             :       sizeof(attr_p->attr.string_val), " \t", &result);
     401             : 
     402           0 :     if (result != SDP_SUCCESS) {
     403           0 :         sdp_parse_error(sdp_p,
     404             :             "%s Warning: No string token found for %s attribute",
     405           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
     406           0 :         sdp_p->conf_p->num_invalid_param++;
     407           0 :         return (SDP_INVALID_PARAMETER);
     408             :     } else {
     409           0 :         if (!sdp_validate_maxprate(attr_p->attr.string_val)) {
     410           0 :             sdp_parse_error(sdp_p,
     411             :                 "%s is not a valid maxprate value.",
     412           0 :                 attr_p->attr.string_val);
     413           0 :             sdp_p->conf_p->num_invalid_param++;
     414           0 :             return (SDP_INVALID_PARAMETER);
     415             :         }
     416             : 
     417           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
     418           0 :             SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
     419             :                       sdp_get_attr_name(attr_p->type),
     420             :                       attr_p->attr.string_val);
     421             :         }
     422           0 :         return (SDP_SUCCESS);
     423             :     }
     424             : }
     425             : 
     426             : /*
     427             :  * sdp_attr_fmtp_no_value
     428             :  * Helper function for sending the warning when a parameter value is
     429             :  * missing.
     430             :  *
     431             :  */
     432           0 : static void sdp_attr_fmtp_no_value(sdp_t *sdp, const char *param_name)
     433             : {
     434           0 :   sdp_parse_error(sdp,
     435             :     "%s Warning: No %s value specified for fmtp attribute",
     436           0 :     sdp->debug_str, param_name);
     437           0 :   sdp->conf_p->num_invalid_param++;
     438           0 : }
     439             : 
     440             : /*
     441             :  * sdp_attr_fmtp_invalid_value
     442             :  * Helper function for sending the warning when a parameter value is
     443             :  * incorrect.
     444             :  *
     445             :  */
     446           0 : static void sdp_attr_fmtp_invalid_value(sdp_t *sdp, const char *param_name,
     447             :   const char* param_value)
     448             : {
     449           0 :   sdp_parse_error(sdp,
     450             :     "%s Warning: Invalid %s: %s specified for fmtp attribute",
     451           0 :     sdp->debug_str, param_name, param_value);
     452           0 :   sdp->conf_p->num_invalid_param++;
     453           0 : }
     454             : 
     455             : /*
     456             :  * sdp_verify_attr_fmtp_telephone_event
     457             :  * Helper function for verifying the telephone-event fmtp format
     458             :  */
     459           0 : static sdp_result_e sdp_verify_attr_fmtp_telephone_event(char *fmtpVal)
     460             : {
     461           0 :   size_t len = fmtpVal ? strlen(fmtpVal) : 0;
     462             : 
     463             :   // make sure the basics are good:
     464             :   // - at least 1 character
     465             :   // - no illegal chars
     466             :   // - first char is a number
     467           0 :   if (len < 1
     468           0 :       || strspn(fmtpVal, "0123456789,-") != len
     469           0 :       || PL_strstr(fmtpVal, ",,")
     470           0 :       || fmtpVal[len-1] == ','
     471           0 :       || !('0' <= fmtpVal[0] && fmtpVal[0] <= '9')) {
     472           0 :     return SDP_INVALID_PARAMETER;
     473             :   }
     474             : 
     475             :   // Now that we've passed the basic sanity test, copy the string so we
     476             :   // can tokenize and check the format of the tokens without disturbing
     477             :   // the input string.
     478             :   char dtmf_tones[SDP_MAX_STRING_LEN+1];
     479           0 :   PL_strncpyz(dtmf_tones, fmtpVal, sizeof(dtmf_tones));
     480             : 
     481             :   char *strtok_state;
     482           0 :   char *temp = PL_strtok_r(dtmf_tones, ",", &strtok_state);
     483             : 
     484           0 :   while (temp != NULL) {
     485           0 :     len = strlen(temp);
     486           0 :     if (len > 5) {
     487             :       // an example of a max size token is "11-15", so if the
     488             :       // token is longer than 5 it is bad
     489           0 :       return SDP_INVALID_PARAMETER;
     490             :     }
     491             : 
     492             :     // case where we have 1 or 2 characters, example 4 or 23
     493           0 :     if (len < 3 && strspn(temp, "0123456789") != len) {
     494           0 :       return SDP_INVALID_PARAMETER;
     495           0 :     } else if (len >= 3) {
     496             :       // case where we have 3-5 characters, ex 3-5, 2-33, or 10-20
     497           0 :       sdp_result_e result1 = SDP_SUCCESS;
     498           0 :       sdp_result_e result2 = SDP_SUCCESS;
     499             :       uint8_t low_val;
     500             :       uint8_t high_val;
     501           0 :       low_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
     502             :                                            "-", &result1);
     503           0 :       high_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
     504             :                                             "-", &result2);
     505           0 :       if (temp[0] // we don't want to find a second hyphen
     506           0 :           || result1 != SDP_SUCCESS
     507           0 :           || result2 != SDP_SUCCESS) {
     508           0 :         return SDP_INVALID_PARAMETER;
     509             :       }
     510             : 
     511           0 :       if (low_val > 99
     512           0 :           || high_val > 99
     513           0 :           || high_val <= low_val) {
     514           0 :         return SDP_INVALID_PARAMETER;
     515             :       }
     516             :     }
     517             : 
     518           0 :     temp=PL_strtok_r(NULL, ",", &strtok_state);
     519             :   }
     520             : 
     521           0 :   return SDP_SUCCESS;
     522             : }
     523             : 
     524             : /* Note:  The fmtp attribute formats currently handled are:
     525             :  *        fmtp:<payload type> <event>,<event>...
     526             :  *        fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>]
     527             :  *        [QCIF =<value>] [CIF =<value>] [MaxBR = <value>] one or more
     528             :  *        Other FMTP params as per H.263, H.263+, H.264 codec support.
     529             :  *        Note -"value" is a numeric value > 0 and each event is a
     530             :  *        single number or a range separated by a '-'.
     531             :  *        Example:  fmtp:101 1,3-15,20
     532             :  * Video codecs have annexes that can be listed in the following legal formats:
     533             :  * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3
     534             :  * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T
     535             :  * c) a=fmtp:34 param1=token;D;I;J
     536             :  *
     537             :  */
     538           0 : sdp_result_e sdp_get_fmtp_tok(sdp_t *sdp_p,
     539             :                               const char** fmtp_ptr,
     540             :                               const char* fmtp_name,
     541             :                               char* buf,
     542             :                               size_t buf_size,
     543             :                               char** tok)
     544             : {
     545           0 :     sdp_result_e result1 = SDP_SUCCESS;
     546             : 
     547           0 :     *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, "; \t", &result1);
     548           0 :     if (result1 != SDP_SUCCESS) {
     549           0 :         *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, " \t", &result1);
     550           0 :         if (result1 != SDP_SUCCESS) {
     551           0 :             sdp_attr_fmtp_no_value(sdp_p, fmtp_name);
     552           0 :             return SDP_INVALID_PARAMETER;
     553             :         }
     554             :     }
     555           0 :     *tok = buf;
     556           0 :     (*tok)++;
     557             : 
     558           0 :     return SDP_SUCCESS;
     559             : }
     560             : 
     561           0 : sdp_result_e sdp_get_fmtp_tok_val(sdp_t *sdp_p,
     562             :                               const char** fmtp_ptr,
     563             :                               const char* fmtp_name,
     564             :                               char* buf,
     565             :                               size_t buf_size,
     566             :                               char** tok,
     567             :                               unsigned long* strtoul_result,
     568             :                               unsigned long illegal_value,
     569             :                               unsigned long min_limit,
     570             :                               unsigned long max_limit)
     571             : {
     572           0 :   sdp_result_e result1 = SDP_SUCCESS;
     573             :   unsigned long value;
     574             :   char* strtoul_end;
     575             : 
     576           0 :   result1 = sdp_get_fmtp_tok(sdp_p, fmtp_ptr, fmtp_name, buf, buf_size, tok);
     577           0 :   if (result1 != SDP_SUCCESS) return result1;
     578             : 
     579           0 :   errno = 0;
     580           0 :   value = strtoul(*tok, &strtoul_end, 10);
     581             : 
     582           0 :   if (errno
     583           0 :       || (*tok == strtoul_end)
     584           0 :       || (illegal_value != ULONG_MAX && value == illegal_value)
     585           0 :       || (min_limit != ULONG_MAX && value < min_limit)
     586           0 :       || (max_limit != ULONG_MAX && value > max_limit)) {
     587           0 :     sdp_attr_fmtp_invalid_value(sdp_p, fmtp_name, *tok);
     588           0 :     return SDP_INVALID_PARAMETER;
     589             :   }
     590           0 :   *strtoul_result = value;
     591             : 
     592           0 :   return SDP_SUCCESS;
     593             : }
     594             : 
     595           0 : sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
     596             :                                   const char *ptr)
     597             : {
     598             :     uint16_t           i;
     599             :     uint32_t           mapword;
     600             :     uint32_t           bmap;
     601             :     uint8_t            low_val;
     602             :     uint8_t            high_val;
     603             :     const char    *ptr2;
     604             :     const char    *fmtp_ptr;
     605           0 :     sdp_result_e  result1 = SDP_SUCCESS;
     606           0 :     sdp_result_e  result2 = SDP_SUCCESS;
     607           0 :     tinybool      done = FALSE;
     608           0 :     tinybool      codec_info_found = FALSE;
     609             :     sdp_fmtp_t   *fmtp_p;
     610             :     char          tmp[SDP_MAX_STRING_LEN];
     611             :     char          *src_ptr;
     612           0 :     char          *temp_ptr = NULL;
     613           0 :     char         *tok=NULL;
     614           0 :     char         *temp=NULL;
     615           0 :     uint16_t          custom_x=0;
     616           0 :     uint16_t          custom_y=0;
     617           0 :     uint16_t          custom_mpi=0;
     618           0 :     uint16_t          par_height=0;
     619           0 :     uint16_t          par_width=0;
     620           0 :     uint16_t          cpcf=0;
     621           0 :     uint16_t          iter=0;
     622             : 
     623           0 :     ulong        l_val = 0;
     624             :     char*        strtok_state;
     625             :     unsigned long strtoul_result;
     626             :     char*        strtoul_end;
     627             : 
     628             :     /* Find the payload type number. */
     629           0 :     attr_p->attr.fmtp.payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
     630             :                                                       " \t", &result1);
     631           0 :     if (result1 != SDP_SUCCESS) {
     632           0 :         sdp_attr_fmtp_no_value(sdp_p, "payload type");
     633           0 :         return SDP_INVALID_PARAMETER;
     634             :     }
     635           0 :     fmtp_p = &(attr_p->attr.fmtp);
     636           0 :     fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE;
     637           0 :     fmtp_p->parameter_add = 1;
     638           0 :     fmtp_p->flag = 0;
     639             : 
     640             :     /*
     641             :      * set default value of packetization mode and level-asymmetry-allowed. If
     642             :      * remote sdp does not specify any value for these two parameters, then the
     643             :      * default value will be assumed for remote sdp. If remote sdp does specify
     644             :      * any value for these parameters, then default value will be overridden.
     645             :     */
     646           0 :     fmtp_p->packetization_mode = SDP_DEFAULT_PACKETIZATION_MODE_VALUE;
     647           0 :     fmtp_p->level_asymmetry_allowed = SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE;
     648             : 
     649           0 :     temp_ptr = cpr_strdup(ptr);
     650           0 :     if (temp_ptr == NULL) {
     651           0 :         return (SDP_FAILURE);
     652             :     }
     653           0 :     fmtp_ptr = src_ptr = temp_ptr;
     654             : 
     655           0 :     src_ptr = temp_ptr;
     656           0 :     while (!done) {
     657           0 :       fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1);
     658           0 :       if (result1 == SDP_SUCCESS) {
     659           0 :         if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[1].name,
     660           0 :                         sdp_fmtp_codec_param[1].strlen) == 0) {
     661           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexb", tmp, sizeof(tmp), &tok);
     662           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     663             : 
     664           0 :             if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
     665           0 :                             sdp_fmtp_codec_param_val[0].strlen) == 0) {
     666           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     667           0 :                 fmtp_p->annexb_required = TRUE;
     668           0 :                 fmtp_p->annexb = TRUE;
     669           0 :             } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
     670           0 :                                    sdp_fmtp_codec_param_val[1].strlen) == 0) {
     671           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     672           0 :                 fmtp_p->annexb_required = TRUE;
     673           0 :                 fmtp_p->annexb = FALSE;
     674             :             } else {
     675           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok);
     676           0 :                 SDP_FREE(temp_ptr);
     677           0 :                 return SDP_INVALID_PARAMETER;
     678             :             }
     679           0 :             codec_info_found = TRUE;
     680             : 
     681           0 :         } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[0].name,
     682           0 :                                sdp_fmtp_codec_param[0].strlen) == 0) {
     683           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexa", tmp, sizeof(tmp), &tok);
     684           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     685             : 
     686           0 :             if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
     687           0 :                             sdp_fmtp_codec_param_val[0].strlen) == 0) {
     688           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     689           0 :                 fmtp_p->annexa = TRUE;
     690           0 :                 fmtp_p->annexa_required = TRUE;
     691           0 :             } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
     692           0 :                                    sdp_fmtp_codec_param_val[1].strlen) == 0) {
     693           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     694           0 :                 fmtp_p->annexa = FALSE;
     695           0 :                 fmtp_p->annexa_required = TRUE;
     696             :             } else {
     697           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok);
     698           0 :                 SDP_FREE(temp_ptr);
     699           0 :                 return SDP_INVALID_PARAMETER;
     700             :             }
     701           0 :             codec_info_found = TRUE;
     702             : 
     703           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[2].name,
     704           0 :                                sdp_fmtp_codec_param[2].strlen) == 0) {
     705           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bitrate", tmp, sizeof(tmp),
     706             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
     707           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     708             : 
     709           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     710           0 :             fmtp_p->bitrate = (uint32_t) strtoul_result;
     711           0 :             codec_info_found = TRUE;
     712             : 
     713           0 :          } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[41].name,
     714           0 :                                sdp_fmtp_codec_param[41].strlen) == 0) {
     715           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "mode", tmp, sizeof(tmp),
     716             :                                            &tok, &strtoul_result, -1, -1, UINT_MAX);
     717           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     718             : 
     719           0 :             fmtp_p->fmtp_format = SDP_FMTP_MODE;
     720           0 :             fmtp_p->mode = (uint32_t) strtoul_result;
     721           0 :             codec_info_found = TRUE;
     722             : 
     723           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[3].name,
     724           0 :                                sdp_fmtp_codec_param[3].strlen) == 0) {
     725           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "qcif", tmp, sizeof(tmp),
     726             :                                            &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
     727           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     728             : 
     729           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     730           0 :             fmtp_p->qcif = (uint16_t) strtoul_result;
     731           0 :             codec_info_found = TRUE;
     732             : 
     733           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[4].name,
     734           0 :                                sdp_fmtp_codec_param[4].strlen) == 0) {
     735           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif", tmp, sizeof(tmp),
     736             :                                            &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
     737           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     738             : 
     739           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     740           0 :             fmtp_p->cif = (uint16_t) strtoul_result;
     741           0 :             codec_info_found = TRUE;
     742             : 
     743           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[5].name,
     744           0 :                                sdp_fmtp_codec_param[5].strlen) == 0) {
     745           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxbr", tmp, sizeof(tmp),
     746             :                                            &tok, &strtoul_result, 0, -1, USHRT_MAX);
     747           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     748             : 
     749           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     750           0 :             fmtp_p->maxbr = (uint16_t) strtoul_result;
     751           0 :             codec_info_found = TRUE;
     752             : 
     753           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[6].name,
     754           0 :                                sdp_fmtp_codec_param[6].strlen) == 0) {
     755           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "sqcif", tmp, sizeof(tmp),
     756             :                                            &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
     757           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     758             : 
     759           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     760           0 :             fmtp_p->sqcif = (uint16_t) strtoul_result;
     761           0 :             codec_info_found = TRUE;
     762             : 
     763           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[7].name,
     764           0 :                                sdp_fmtp_codec_param[7].strlen) == 0) {
     765           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif4", tmp, sizeof(tmp),
     766             :                                            &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
     767           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     768             : 
     769           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     770           0 :             fmtp_p->cif4 = (uint16_t) strtoul_result;
     771           0 :             codec_info_found = TRUE;
     772             : 
     773           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[8].name,
     774           0 :                                sdp_fmtp_codec_param[8].strlen) == 0) {
     775           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif16", tmp, sizeof(tmp),
     776             :                                            &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
     777           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     778             : 
     779           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     780           0 :             fmtp_p->cif16 = (uint16_t) strtoul_result;
     781           0 :             codec_info_found = TRUE;
     782             : 
     783           0 :         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[9].name,
     784           0 :                                sdp_fmtp_codec_param[9].strlen) == 0) {
     785           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "custom", tmp, sizeof(tmp), &tok);
     786           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     787             : 
     788           0 :             temp=PL_strtok_r(tok, ",", &strtok_state);
     789           0 :             iter++;
     790           0 :         if (temp) {
     791           0 :             iter=1;
     792           0 :             while (temp != NULL) {
     793           0 :                 errno = 0;
     794           0 :                 strtoul_result = strtoul(temp, &strtoul_end, 10);
     795             : 
     796           0 :                 if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX){
     797           0 :                     custom_x = custom_y = custom_mpi = 0;
     798           0 :                     break;
     799             :                 }
     800             : 
     801           0 :                 if (iter == 1)
     802           0 :                     custom_x = (uint16_t) strtoul_result;
     803           0 :                 if (iter == 2)
     804           0 :                     custom_y = (uint16_t) strtoul_result;
     805           0 :                 if (iter == 3)
     806           0 :                     custom_mpi = (uint16_t) strtoul_result;
     807             : 
     808           0 :                 temp=PL_strtok_r(NULL, ",", &strtok_state);
     809           0 :                 iter++;
     810             :             }
     811             :         }
     812             : 
     813             :         /* custom x,y and mpi values from tmp */
     814           0 :             if (!custom_x || !custom_y || !custom_mpi) {
     815           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "x/y/MPI", temp);
     816           0 :                 SDP_FREE(temp_ptr);
     817           0 :                 return SDP_INVALID_PARAMETER;
     818             :             }
     819           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     820           0 :             fmtp_p->custom_x = custom_x;
     821           0 :             fmtp_p->custom_y = custom_y;
     822           0 :             fmtp_p->custom_mpi = custom_mpi;
     823           0 :             codec_info_found = TRUE;
     824             : 
     825           0 :         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[10].name,
     826           0 :                                sdp_fmtp_codec_param[10].strlen) == 0) {
     827           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "par", tmp, sizeof(tmp), &tok);
     828           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     829             : 
     830           0 :             temp=PL_strtok_r(tok, ":", &strtok_state);
     831           0 :         if (temp) {
     832           0 :             iter=1;
     833             :             /* get par width and par height for the aspect ratio */
     834           0 :             while (temp != NULL) {
     835           0 :                 errno = 0;
     836           0 :                 strtoul_result = strtoul(temp, &strtoul_end, 10);
     837             : 
     838           0 :                 if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
     839           0 :                     par_width = par_height = 0;
     840           0 :                     break;
     841             :                 }
     842             : 
     843           0 :                 if (iter == 1)
     844           0 :                     par_width = (uint16_t) strtoul_result;
     845             :                 else
     846           0 :                     par_height = (uint16_t) strtoul_result;
     847             : 
     848           0 :                 temp=PL_strtok_r(NULL, ",", &strtok_state);
     849           0 :                 iter++;
     850             :             }
     851             :         }
     852           0 :             if (!par_width || !par_height) {
     853           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp);
     854           0 :                 SDP_FREE(temp_ptr);
     855           0 :                 return SDP_INVALID_PARAMETER;
     856             :             }
     857           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     858           0 :             fmtp_p->par_width = par_width;
     859           0 :             fmtp_p->par_height = par_height;
     860           0 :             codec_info_found = TRUE;
     861             : 
     862           0 :         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[11].name,
     863           0 :                                sdp_fmtp_codec_param[11].strlen) == 0) {
     864           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "cpcf", tmp, sizeof(tmp), &tok);
     865           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     866             : 
     867           0 :             temp=PL_strtok_r(tok, ".", &strtok_state);
     868           0 :         if ( temp != NULL  ) {
     869           0 :             errno = 0;
     870           0 :             strtoul_result = strtoul(temp, &strtoul_end, 10);
     871             : 
     872           0 :             if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
     873           0 :                 cpcf = 0;
     874             :             } else {
     875           0 :                 cpcf = (uint16_t) strtoul_result;
     876             :             }
     877             :         }
     878             : 
     879           0 :             if (!cpcf) {
     880           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok);
     881           0 :                 SDP_FREE(temp_ptr);
     882           0 :                 return SDP_INVALID_PARAMETER;
     883             :             }
     884           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     885           0 :             fmtp_p->cpcf = cpcf;
     886           0 :             codec_info_found = TRUE;
     887             : 
     888           0 :         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[12].name,
     889           0 :                                sdp_fmtp_codec_param[12].strlen) == 0) {
     890           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bpp", tmp, sizeof(tmp),
     891             :                                            &tok, &strtoul_result, 0, -1, USHRT_MAX);
     892           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     893             : 
     894           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     895           0 :         fmtp_p->bpp = (uint16_t) strtoul_result;
     896           0 :             codec_info_found = TRUE;
     897             : 
     898           0 :         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[13].name,
     899           0 :                                sdp_fmtp_codec_param[13].strlen) == 0) {
     900           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "hrd", tmp, sizeof(tmp),
     901             :                                            &tok, &strtoul_result, 0, -1, USHRT_MAX);
     902           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     903             : 
     904           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     905           0 :             fmtp_p->hrd = (uint16_t) strtoul_result;
     906           0 :             codec_info_found = TRUE;
     907             : 
     908           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[14].name,
     909           0 :                                sdp_fmtp_codec_param[14].strlen) == 0) {
     910           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "profile", tmp, sizeof(tmp),
     911             :                                            &tok, &strtoul_result, -1, -1, SDP_MAX_PROFILE_VALUE);
     912           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     913             : 
     914           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     915           0 :             fmtp_p->profile = (short) strtoul_result;
     916           0 :             codec_info_found = TRUE;
     917             : 
     918           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[15].name,
     919           0 :                                sdp_fmtp_codec_param[15].strlen) == 0) {
     920           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level", tmp, sizeof(tmp),
     921             :                                            &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_VALUE);
     922           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     923             : 
     924           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     925           0 :             fmtp_p->level = (short) strtoul_result;
     926           0 :             codec_info_found = TRUE;
     927             : 
     928           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name,
     929           0 :                                sdp_fmtp_codec_param[16].strlen) == 0) {
     930           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     931           0 :             fmtp_p->is_interlace = TRUE;
     932           0 :             codec_info_found = TRUE;
     933             : 
     934           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[17].name,
     935           0 :                                sdp_fmtp_codec_param[17].strlen) == 0) {
     936           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "profile_level_id", tmp, sizeof(tmp), &tok);
     937           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     938             : 
     939           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     940           0 :             sstrncpy(fmtp_p->profile_level_id , tok, sizeof(fmtp_p->profile_level_id));
     941           0 :             codec_info_found = TRUE;
     942             : 
     943           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[18].name,
     944           0 :                                sdp_fmtp_codec_param[18].strlen) == 0) {
     945           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "parameter_sets", tmp, sizeof(tmp), &tok);
     946           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     947             : 
     948           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     949           0 :             sstrncpy(fmtp_p->parameter_sets , tok, sizeof(fmtp_p->parameter_sets));
     950           0 :             codec_info_found = TRUE;
     951             : 
     952           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[19].name,
     953           0 :                                sdp_fmtp_codec_param[19].strlen) == 0) {
     954           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "packetization_mode", tmp, sizeof(tmp),
     955             :                                            &tok, &strtoul_result, -1, -1, 2);
     956             :             // this one is different for some reason. Most others don't increment
     957             :             // the num_invalid_param field. (mjf)
     958           0 :             if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
     959           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     960             : 
     961           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     962           0 :             fmtp_p->packetization_mode = (int16_t) strtoul_result;
     963           0 :             codec_info_found = TRUE;
     964             : 
     965           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[20].name,
     966           0 :                                sdp_fmtp_codec_param[20].strlen) == 0) {
     967           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "interleaving_depth", tmp, sizeof(tmp),
     968             :                                            &tok, &strtoul_result, 0, -1, USHRT_MAX);
     969           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     970             : 
     971           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     972           0 :             fmtp_p->interleaving_depth = (uint16_t) strtoul_result;
     973           0 :             codec_info_found = TRUE;
     974             : 
     975           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[21].name,
     976           0 :                                sdp_fmtp_codec_param[21].strlen) == 0) {
     977           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf", tmp, sizeof(tmp), &tok);
     978           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     979             : 
     980           0 :             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
     981           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     982           0 :                 fmtp_p->deint_buf_req = (uint32_t) l_val;
     983           0 :                 fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG;
     984           0 :                 codec_info_found = TRUE;
     985             :             } else {
     986           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok);
     987           0 :                 SDP_FREE(temp_ptr);
     988           0 :                 return SDP_INVALID_PARAMETER;
     989             :             }
     990             : 
     991           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[22].name,
     992           0 :                                sdp_fmtp_codec_param[22].strlen) == 0) {
     993           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_don_diff", tmp, sizeof(tmp),
     994             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
     995           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
     996             : 
     997           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
     998           0 :             fmtp_p->max_don_diff = (uint32_t) strtoul_result;
     999           0 :             codec_info_found = TRUE;
    1000             : 
    1001           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[23].name,
    1002           0 :                                sdp_fmtp_codec_param[23].strlen) == 0) {
    1003           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "init_buf_time", tmp, sizeof(tmp), &tok);
    1004           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1005             : 
    1006           0 :             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
    1007           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1008           0 :                 fmtp_p->init_buf_time = (uint32_t) l_val;
    1009           0 :                 fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG;
    1010           0 :                 codec_info_found = TRUE;
    1011             :             } else {
    1012           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok);
    1013           0 :                 SDP_FREE(temp_ptr);
    1014           0 :                 return SDP_INVALID_PARAMETER;
    1015             :             }
    1016             : 
    1017           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[24].name,
    1018           0 :                                sdp_fmtp_codec_param[24].strlen) == 0) {
    1019           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_mbps", tmp, sizeof(tmp),
    1020             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1021           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1022             : 
    1023           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1024           0 :         fmtp_p->max_mbps = (uint32_t) strtoul_result;
    1025           0 :             codec_info_found = TRUE;
    1026             : 
    1027           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[25].name,
    1028           0 :                                sdp_fmtp_codec_param[25].strlen) == 0) {
    1029           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fs", tmp, sizeof(tmp),
    1030             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1031           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1032             : 
    1033           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1034           0 :             fmtp_p->max_fs = (uint32_t) strtoul_result;
    1035           0 :             codec_info_found = TRUE;
    1036             : 
    1037           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[26].name,
    1038           0 :                                sdp_fmtp_codec_param[26].strlen) == 0) {
    1039           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_cbp", tmp, sizeof(tmp),
    1040             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1041           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1042             : 
    1043           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1044           0 :             fmtp_p->max_cpb = (uint32_t) strtoul_result;
    1045           0 :             codec_info_found = TRUE;
    1046             : 
    1047           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[27].name,
    1048           0 :                                sdp_fmtp_codec_param[27].strlen) == 0) {
    1049           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_dpb", tmp, sizeof(tmp),
    1050             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1051           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1052             : 
    1053           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1054           0 :             fmtp_p->max_dpb = (uint32_t) strtoul_result;
    1055           0 :             codec_info_found = TRUE;
    1056             : 
    1057           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[28].name,
    1058           0 :                                sdp_fmtp_codec_param[28].strlen) == 0) {
    1059           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_br", tmp, sizeof(tmp),
    1060             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1061           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1062             : 
    1063           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1064           0 :             fmtp_p->max_br = (uint32_t) strtoul_result;
    1065           0 :             codec_info_found = TRUE;
    1066             : 
    1067           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[29].name,
    1068           0 :                                sdp_fmtp_codec_param[29].strlen) == 0) {
    1069           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "redundant_pic_cap", tmp, sizeof(tmp),
    1070             :                                            &tok, &strtoul_result, 0, -1, 1);
    1071           0 :             fmtp_p->redundant_pic_cap = (result1 == SDP_SUCCESS);
    1072           0 :             codec_info_found = TRUE;
    1073             : 
    1074           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[30].name,
    1075           0 :                                sdp_fmtp_codec_param[30].strlen) == 0) {
    1076           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf_cap", tmp, sizeof(tmp), &tok);
    1077           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1078             : 
    1079           0 :             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
    1080           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1081           0 :                 fmtp_p->deint_buf_cap = (uint32_t) l_val;
    1082           0 :                 fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG;
    1083           0 :                 codec_info_found = TRUE;
    1084             :             } else {
    1085           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok);
    1086           0 :                 SDP_FREE(temp_ptr);
    1087           0 :                 return SDP_INVALID_PARAMETER;
    1088             :             }
    1089             : 
    1090           0 :         }  else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[31].name,
    1091           0 :                                sdp_fmtp_codec_param[31].strlen) == 0) {
    1092           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "max_rcmd_nalu_size", tmp, sizeof(tmp), &tok);
    1093           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1094             : 
    1095           0 :             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
    1096           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1097           0 :                 fmtp_p->max_rcmd_nalu_size = (uint32_t) l_val;
    1098           0 :                 fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG;
    1099           0 :                 codec_info_found = TRUE;
    1100             :             } else {
    1101           0 :                 sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok);
    1102           0 :                 SDP_FREE(temp_ptr);
    1103           0 :                 return SDP_INVALID_PARAMETER;
    1104             :             }
    1105             : 
    1106           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[32].name,
    1107           0 :                                sdp_fmtp_codec_param[32].strlen) == 0) {
    1108           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "parameter_add", tmp, sizeof(tmp),
    1109             :                                            &tok, &strtoul_result, 0, -1, 1);
    1110           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1111             : 
    1112           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1113           0 :             fmtp_p->parameter_add = (uint16_t) strtoul_result;
    1114           0 :             codec_info_found = TRUE;
    1115             : 
    1116           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[33].name,
    1117           0 :                                sdp_fmtp_codec_param[33].strlen) == 0) {
    1118           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1119           0 :             fmtp_p->annex_d = TRUE;
    1120           0 :             codec_info_found = TRUE;
    1121             : 
    1122           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[34].name,
    1123           0 :                                sdp_fmtp_codec_param[34].strlen) == 0) {
    1124           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1125           0 :             fmtp_p->annex_f = TRUE;
    1126           0 :             codec_info_found = TRUE;
    1127             : 
    1128           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[35].name,
    1129           0 :                                sdp_fmtp_codec_param[35].strlen) == 0) {
    1130           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1131           0 :             fmtp_p->annex_i = TRUE;
    1132           0 :             codec_info_found = TRUE;
    1133             : 
    1134           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[36].name,
    1135           0 :                                sdp_fmtp_codec_param[36].strlen) == 0) {
    1136           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1137           0 :             fmtp_p->annex_j = TRUE;
    1138           0 :             codec_info_found = TRUE;
    1139             : 
    1140           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[37].name,
    1141           0 :                                sdp_fmtp_codec_param[36].strlen) == 0) {
    1142           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1143           0 :             fmtp_p->annex_t = TRUE;
    1144           0 :             codec_info_found = TRUE;
    1145             : 
    1146           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[38].name,
    1147           0 :                              sdp_fmtp_codec_param[38].strlen) == 0) {
    1148           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_k", tmp, sizeof(tmp),
    1149             :                                            &tok, &strtoul_result, 0, -1, USHRT_MAX);
    1150           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1151             : 
    1152           0 :                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1153           0 :                 fmtp_p->annex_k_val = (uint16_t) strtoul_result;
    1154           0 :                 codec_info_found = TRUE;
    1155             : 
    1156           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[39].name,
    1157           0 :                                sdp_fmtp_codec_param[39].strlen) == 0) {
    1158           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_n", tmp, sizeof(tmp),
    1159             :                                            &tok, &strtoul_result, 0, -1, USHRT_MAX);
    1160           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1161             : 
    1162           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1163           0 :             fmtp_p->annex_n_val = (uint16_t) strtoul_result;
    1164           0 :             codec_info_found = TRUE;
    1165             : 
    1166           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[40].name,
    1167           0 :                                sdp_fmtp_codec_param[40].strlen) == 0) {
    1168           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annex_p", tmp, sizeof(tmp), &tok);
    1169           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1170             : 
    1171           0 :             fmtp_p->annex_p_val_picture_resize = 0;
    1172           0 :             fmtp_p->annex_p_val_warp = 0;
    1173           0 :             temp = PL_strtok_r(tok, ",", &strtok_state);
    1174           0 :             if (temp) {
    1175           0 :                 iter=1;
    1176           0 :                 while (temp != NULL) {
    1177           0 :                     errno = 0;
    1178           0 :                     strtoul_result = strtoul(temp, &strtoul_end, 10);
    1179             : 
    1180           0 :                     if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
    1181             :                         break;
    1182             :                     }
    1183             : 
    1184           0 :                     if (iter == 1)
    1185           0 :                         fmtp_p->annex_p_val_picture_resize = (uint16_t) strtoul_result;
    1186           0 :                     else if (iter == 2)
    1187           0 :                         fmtp_p->annex_p_val_warp = (uint16_t) strtoul_result;
    1188             : 
    1189           0 :                     temp = PL_strtok_r(NULL, ",", &strtok_state);
    1190           0 :                     iter++;
    1191             :                 }
    1192             :             }
    1193             : 
    1194           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1195           0 :             codec_info_found = TRUE;
    1196             : 
    1197           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[42].name,
    1198           0 :                                sdp_fmtp_codec_param[42].strlen) == 0) {
    1199           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level_asymmetry_allowed", tmp, sizeof(tmp),
    1200             :                                            &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE);
    1201           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1202             : 
    1203           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1204           0 :             fmtp_p->level_asymmetry_allowed = (int) strtoul_result;
    1205           0 :             codec_info_found = TRUE;
    1206             : 
    1207           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[43].name,
    1208           0 :                                    sdp_fmtp_codec_param[43].strlen) == 0) {
    1209           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxaveragebitrate", tmp, sizeof(tmp),
    1210             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1211           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1212             : 
    1213           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1214           0 :             fmtp_p->maxaveragebitrate = (uint32_t) strtoul_result;
    1215           0 :             codec_info_found = TRUE;
    1216             : 
    1217           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[44].name,
    1218           0 :                                    sdp_fmtp_codec_param[44].strlen) == 0) {
    1219           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "usedtx", tmp, sizeof(tmp),
    1220             :                                            &tok, &strtoul_result, -1, -1, 1);
    1221           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1222             : 
    1223           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1224           0 :             fmtp_p->usedtx = (uint16_t) strtoul_result;
    1225           0 :             codec_info_found = TRUE;
    1226             : 
    1227           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[45].name,
    1228           0 :                                    sdp_fmtp_codec_param[45].strlen) == 0) {
    1229           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "stereo", tmp, sizeof(tmp),
    1230             :                                            &tok, &strtoul_result, -1, -1, 1);
    1231           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1232             : 
    1233           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1234           0 :             fmtp_p->stereo = (uint16_t) strtoul_result;
    1235           0 :             codec_info_found = TRUE;
    1236             : 
    1237           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[46].name,
    1238           0 :                                    sdp_fmtp_codec_param[46].strlen) == 0) {
    1239           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "useinbandfec", tmp, sizeof(tmp),
    1240             :                                            &tok, &strtoul_result, -1, -1, 1);
    1241           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1242             : 
    1243           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1244           0 :             fmtp_p->useinbandfec = (uint16_t) strtoul_result;
    1245           0 :             codec_info_found = TRUE;
    1246             : 
    1247           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[47].name,
    1248           0 :                                        sdp_fmtp_codec_param[47].strlen) == 0) {
    1249           0 :             result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "maxcodedaudiobandwidth", tmp, sizeof(tmp), &tok);
    1250             :             // this one is different for some reason. Most others don't increment
    1251             :             // the num_invalid_param field. (mjf)
    1252           0 :             if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
    1253           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1254             : 
    1255           0 :                     fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1256           0 :                     sstrncpy(fmtp_p->maxcodedaudiobandwidth , tok, sizeof(fmtp_p->maxcodedaudiobandwidth));
    1257           0 :                     codec_info_found = TRUE;
    1258             : 
    1259           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[48].name,
    1260           0 :                                    sdp_fmtp_codec_param[48].strlen) == 0) {
    1261           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cbr", tmp, sizeof(tmp),
    1262             :                                            &tok, &strtoul_result, -1, -1, 1);
    1263           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1264             : 
    1265           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1266           0 :             fmtp_p->cbr = (uint16_t) strtoul_result;
    1267           0 :             codec_info_found = TRUE;
    1268             : 
    1269           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[49].name,
    1270           0 :                                    sdp_fmtp_codec_param[49].strlen) == 0) {
    1271           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fr", tmp, sizeof(tmp),
    1272             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1273           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1274             : 
    1275           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1276           0 :             fmtp_p->max_fr = (uint32_t) strtoul_result;
    1277           0 :             codec_info_found = TRUE;
    1278             : 
    1279           0 :         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name,
    1280           0 :                                    sdp_fmtp_codec_param[50].strlen) == 0) {
    1281           0 :             result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxplaybackrate", tmp, sizeof(tmp),
    1282             :                                            &tok, &strtoul_result, 0, -1, UINT_MAX);
    1283           0 :             if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
    1284             : 
    1285           0 :             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
    1286           0 :             fmtp_p->maxplaybackrate = (uint32_t) strtoul_result;
    1287           0 :             codec_info_found = TRUE;
    1288             : 
    1289           0 :         } else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') {
    1290           0 :             temp=PL_strtok_r(tmp, ";", &strtok_state);
    1291           0 :             if (temp) {
    1292           0 :                 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1293           0 :                     SDP_PRINT("%s Annexes are possibly there for this fmtp %s  tmp: %s line\n",
    1294             :                               sdp_p->debug_str, fmtp_ptr, tmp);
    1295             :                 }
    1296           0 :                 while (temp != NULL) {
    1297           0 :                     if (strchr(temp, 'D') !=NULL) {
    1298           0 :                         attr_p->attr.fmtp.annex_d = TRUE;
    1299             :                     }
    1300           0 :                     if (strchr(temp, 'F') !=NULL) {
    1301           0 :                         attr_p->attr.fmtp.annex_f = TRUE;
    1302             :                     }
    1303           0 :                     if (strchr(temp, 'I') !=NULL) {
    1304           0 :                         attr_p->attr.fmtp.annex_i = TRUE;
    1305             :                     }
    1306           0 :                     if (strchr(temp, 'J') !=NULL) {
    1307           0 :                         attr_p->attr.fmtp.annex_j = TRUE;
    1308             :                     }
    1309           0 :                     if (strchr(temp, 'T') !=NULL) {
    1310           0 :                         attr_p->attr.fmtp.annex_t = TRUE;
    1311             :                     }
    1312           0 :                     temp=PL_strtok_r(NULL, ";", &strtok_state);
    1313             :                 }
    1314             :             } /* if (temp) */
    1315           0 :             done = TRUE;
    1316           0 :         } else if (strchr(tmp, '/')) {
    1317             :             // XXX Note that because RFC 5109 so conveniently specified
    1318             :             // this fmtp with no param names, we hope that nothing else
    1319             :             // has a slash in the string because otherwise we won't know
    1320             :             // how to differentiate.
    1321           0 :             temp=PL_strtok_r(tmp, "/", &strtok_state);
    1322           0 :             if (temp) {
    1323           0 :                 iter = 0;
    1324           0 :                 while (temp != NULL) {
    1325           0 :                     errno = 0;
    1326           0 :                     strtoul_result = strtoul(temp, &strtoul_end, 10);
    1327             : 
    1328           0 :                     if (errno ||
    1329           0 :                        temp == strtoul_end || strtoul_result > USHRT_MAX) {
    1330           0 :                       temp = NULL;
    1331           0 :                       continue;
    1332             :                     }
    1333           0 :                     fmtp_p->redundant_encodings[iter++] =
    1334           0 :                         (uint8_t)strtoul_result;
    1335           0 :                     temp=PL_strtok_r(NULL, "/", &strtok_state);
    1336             :                 }
    1337             :             } /* if (temp) */
    1338           0 :         } else if (SDP_SUCCESS == sdp_verify_attr_fmtp_telephone_event(tmp)) {
    1339             :           // XXX Note that DTMF fmtp will fall into here:
    1340             :           // a=fmtp:101 0-15 (or 0-15,NN,NN etc)
    1341           0 :           sstrncpy(fmtp_p->dtmf_tones , tmp, sizeof(fmtp_p->dtmf_tones));
    1342           0 :           codec_info_found = TRUE;
    1343             :         } else {
    1344             :           // unknown parameter - eat chars until ';'
    1345           0 :           CSFLogDebug(logTag, "%s Unknown fmtp type (%s) - ignoring", __FUNCTION__,
    1346             :                       tmp);
    1347           0 :           fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t",
    1348             :                                        &result1);
    1349           0 :           if (result1 != SDP_SUCCESS) {
    1350           0 :             fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
    1351           0 :             if (result1 != SDP_SUCCESS) {
    1352             :               // hmmm, no ; or spaces or tabs; continue on
    1353             :             }
    1354             :           }
    1355             :         }
    1356           0 :         fmtp_ptr++;
    1357             :       } else {
    1358           0 :           done = TRUE;
    1359             :       }
    1360             :     } /* while  - done loop*/
    1361             : 
    1362           0 :     if (codec_info_found) {
    1363             : 
    1364           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1365           0 :             SDP_PRINT("%s Parsed a=%s, payload type %u, bitrate %u, mode %u QCIF = %u, CIF = %u, MAXBR= %u, SQCIF=%u, CIF4= %u, CIF16=%u, CUSTOM=%u,%u,%u , PAR=%u:%u,CPCF=%u, BPP=%u, HRD=%u \n",
    1366             :                       sdp_p->debug_str,
    1367             :                       sdp_get_attr_name(attr_p->type),
    1368             :                       attr_p->attr.fmtp.payload_num,
    1369             :                       attr_p->attr.fmtp.bitrate,
    1370             :                       attr_p->attr.fmtp.mode,
    1371             :                       attr_p->attr.fmtp.qcif,
    1372             :                       attr_p->attr.fmtp.cif,
    1373             :                       attr_p->attr.fmtp.maxbr,
    1374             :                       attr_p->attr.fmtp.sqcif,
    1375             :                       attr_p->attr.fmtp.cif4,
    1376             :                       attr_p->attr.fmtp.cif16,
    1377             :                       attr_p->attr.fmtp.custom_x,attr_p->attr.fmtp.custom_y,
    1378             :                       attr_p->attr.fmtp.custom_mpi,
    1379             :                       attr_p->attr.fmtp.par_width,
    1380             :                       attr_p->attr.fmtp.par_height,
    1381             :                       attr_p->attr.fmtp.cpcf,
    1382             :                       attr_p->attr.fmtp.bpp,
    1383             :                       attr_p->attr.fmtp.hrd
    1384             :                       );
    1385             :         }
    1386             : 
    1387           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1388           0 :             SDP_PRINT("%s Parsed a=%s, payload type %u,PROFILE=%u,LEVEL=%u, INTERLACE - %s",
    1389             :                       sdp_p->debug_str,
    1390             :                       sdp_get_attr_name(attr_p->type),
    1391             :                       attr_p->attr.fmtp.payload_num,
    1392             :                       attr_p->attr.fmtp.profile,
    1393             :                       attr_p->attr.fmtp.level,
    1394             :                       attr_p->attr.fmtp.is_interlace ? "YES":"NO");
    1395             :         }
    1396             : 
    1397           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1398           0 :             SDP_PRINT("%s Parsed H.264 attributes: profile-level-id=%s, parameter-sets=%s, packetization-mode=%d level-asymmetry-allowed=%d interleaving-depth=%d deint-buf-req=%u max-don-diff=%u, init_buf-time=%u\n",
    1399             :                       sdp_p->debug_str,
    1400             :                       attr_p->attr.fmtp.profile_level_id,
    1401             :                       attr_p->attr.fmtp.parameter_sets,
    1402             :                       attr_p->attr.fmtp.packetization_mode,
    1403             :                       attr_p->attr.fmtp.level_asymmetry_allowed,
    1404             :                       attr_p->attr.fmtp.interleaving_depth,
    1405             :                       attr_p->attr.fmtp.deint_buf_req,
    1406             :                       attr_p->attr.fmtp.max_don_diff,
    1407             :                       attr_p->attr.fmtp.init_buf_time
    1408             :                       );
    1409             :         }
    1410             : 
    1411           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1412           0 :             SDP_PRINT("\n%s Parsed H.264 opt attributes: max-mbps=%u, max-fs=%u, max-cpb=%u max-dpb=%u max-br=%u redundant-pic-cap=%d, deint-buf-cap=%u, max-rcmd-nalu-size=%u , parameter-add=%d\n",
    1413             :                       sdp_p->debug_str,
    1414             :                       attr_p->attr.fmtp.max_mbps,
    1415             :                       attr_p->attr.fmtp.max_fs,
    1416             :                       attr_p->attr.fmtp.max_cpb,
    1417             :                       attr_p->attr.fmtp.max_dpb,
    1418             :                       attr_p->attr.fmtp.max_br,
    1419             :                       attr_p->attr.fmtp.redundant_pic_cap,
    1420             :                       attr_p->attr.fmtp.deint_buf_cap,
    1421             :                       attr_p->attr.fmtp.max_rcmd_nalu_size,
    1422             :                       attr_p->attr.fmtp.parameter_add);
    1423             : 
    1424             :         }
    1425           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1426           0 :             SDP_PRINT("%s Parsed annexes are : D=%d F=%d I=%d J=%d T=%d, K=%d N=%d P=%d,%d\n",
    1427             :                       sdp_p->debug_str,
    1428             :                       attr_p->attr.fmtp.annex_d,
    1429             :                       attr_p->attr.fmtp.annex_f,  attr_p->attr.fmtp.annex_i,
    1430             :                       attr_p->attr.fmtp.annex_j,  attr_p->attr.fmtp.annex_t,
    1431             :                       attr_p->attr.fmtp.annex_k_val,
    1432             :                       attr_p->attr.fmtp.annex_n_val,
    1433             :                       attr_p->attr.fmtp.annex_p_val_picture_resize,
    1434             :                       attr_p->attr.fmtp.annex_p_val_warp);
    1435             : 
    1436             :         }
    1437           0 :         SDP_FREE(temp_ptr);
    1438           0 :         return (SDP_SUCCESS);
    1439             :     } else {
    1440           0 :         done = FALSE;
    1441           0 :         fmtp_ptr = src_ptr;
    1442           0 :         tmp[0] = '\0';
    1443             :     }
    1444             : 
    1445           0 :     for (i=0; !done; i++) {
    1446           0 :         fmtp_p->fmtp_format = SDP_FMTP_NTE;
    1447             :         /* Look for comma separated events */
    1448           0 :         fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), ", \t", &result1);
    1449           0 :         if (result1 != SDP_SUCCESS) {
    1450           0 :             done = TRUE;
    1451           0 :             continue;
    1452             :         }
    1453             :         /* Now look for '-' separated range */
    1454           0 :         ptr2 = tmp;
    1455           0 :         low_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
    1456             :                                     "- \t", &result1);
    1457           0 :         if (*ptr2 == '-') {
    1458           0 :             high_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
    1459             :                                          "- \t", &result2);
    1460             :         } else {
    1461           0 :             high_val = low_val;
    1462             :         }
    1463             : 
    1464           0 :         if ((result1 != SDP_SUCCESS) || (result2 != SDP_SUCCESS)) {
    1465           0 :             sdp_parse_error(sdp_p,
    1466             :                 "%s Warning: Invalid named events specified for fmtp attribute.",
    1467           0 :                 sdp_p->debug_str);
    1468           0 :             sdp_p->conf_p->num_invalid_param++;
    1469           0 :             SDP_FREE(temp_ptr);
    1470           0 :             return (SDP_INVALID_PARAMETER);
    1471             :         }
    1472             : 
    1473           0 :         for (i = low_val; i <= high_val; i++) {
    1474           0 :             mapword = i/SDP_NE_BITS_PER_WORD;
    1475           0 :             bmap = SDP_NE_BIT_0 << (i%32);
    1476           0 :             fmtp_p->bmap[mapword] |= bmap;
    1477             :         }
    1478           0 :         if (high_val > fmtp_p->maxval) {
    1479           0 :             fmtp_p->maxval = high_val;
    1480             :         }
    1481             :     }
    1482             : 
    1483           0 :     if (fmtp_p->maxval == 0) {
    1484           0 :         sdp_parse_error(sdp_p,
    1485             :             "%s Warning: No named events specified for fmtp attribute.",
    1486           0 :             sdp_p->debug_str);
    1487           0 :         sdp_p->conf_p->num_invalid_param++;
    1488           0 :         SDP_FREE(temp_ptr);
    1489           0 :         return (SDP_INVALID_PARAMETER);
    1490             :     }
    1491             : 
    1492           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1493           0 :         SDP_PRINT("%s Parsed a=%s, payload type %u, ", sdp_p->debug_str,
    1494             :                   sdp_get_attr_name(attr_p->type),
    1495             :                   attr_p->attr.fmtp.payload_num);
    1496             :     }
    1497           0 :     SDP_FREE(temp_ptr);
    1498           0 :     return (SDP_SUCCESS);
    1499             : }
    1500             : 
    1501             : sdp_result_e
    1502           0 : sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *fmtp_p, flex_string *fs)
    1503             : {
    1504             :   uint16_t         event_id;
    1505             :   uint32_t         mask;
    1506             :   uint32_t         mapword;
    1507           0 :   uint8_t          min = 0;
    1508           0 :   uint8_t          max = 0;
    1509           0 :   tinybool    range_start = FALSE;
    1510           0 :   tinybool    range_end = FALSE;
    1511           0 :   tinybool    semicolon = FALSE;
    1512             : 
    1513           0 :   switch (fmtp_p->fmtp_format) {
    1514             :     case SDP_FMTP_MODE:
    1515           0 :       sdp_append_name_and_unsigned(fs, "mode", fmtp_p->mode, FALSE);
    1516           0 :       break;
    1517             : 
    1518             :     case SDP_FMTP_CODEC_INFO:
    1519           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->bitrate > 0, "bitrate", fmtp_p->bitrate)
    1520             : 
    1521           0 :       FMTP_BUILD_STRING(fmtp_p->annexa_required,
    1522             :         "annexa", (fmtp_p->annexa ? "yes" : "no"))
    1523             : 
    1524           0 :       FMTP_BUILD_STRING(fmtp_p->annexb_required,
    1525             :         "annexb", (fmtp_p->annexa ? "yes" : "no"))
    1526             : 
    1527           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->qcif > 0, "QCIF", fmtp_p->qcif)
    1528             : 
    1529           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->cif > 0, "CIF", fmtp_p->cif)
    1530             : 
    1531           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->maxbr > 0, "MAXBR", fmtp_p->maxbr)
    1532             : 
    1533           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->sqcif > 0, "SQCIF", fmtp_p->sqcif)
    1534             : 
    1535           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->cif4 > 0, "CIF4", fmtp_p->cif4)
    1536             : 
    1537           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->cif16 > 0, "CIF16", fmtp_p->cif16)
    1538             : 
    1539           0 :       if ((fmtp_p->custom_x > 0) && (fmtp_p->custom_y > 0) &&
    1540           0 :         (fmtp_p->custom_mpi > 0)) {
    1541           0 :         flex_string_sprintf(fs, "%sCUSTOM=%u,%u,%u",
    1542             :           semicolon ? ";" : "",
    1543           0 :           fmtp_p->custom_x,
    1544           0 :           fmtp_p->custom_y,
    1545           0 :           fmtp_p->custom_mpi);
    1546             : 
    1547           0 :         semicolon = TRUE;
    1548             :       }
    1549             : 
    1550           0 :       if ((fmtp_p->par_height > 0) && (fmtp_p->par_width > 0)) {
    1551           0 :         flex_string_sprintf(fs, "%sPAR=%u:%u",
    1552             :           semicolon ? ";" : "",
    1553           0 :           fmtp_p->par_width,
    1554           0 :           fmtp_p->par_width);
    1555             : 
    1556           0 :         semicolon = TRUE;
    1557             :       }
    1558             : 
    1559           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->cpcf > 0, "CPCF", fmtp_p->cpcf)
    1560             : 
    1561           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->bpp > 0, "BPP", fmtp_p->bpp)
    1562             : 
    1563           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->hrd > 0, "HRD", fmtp_p->hrd)
    1564             : 
    1565           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->profile >= 0, "PROFILE", fmtp_p->profile)
    1566             : 
    1567           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->level >= 0, "LEVEL", fmtp_p->level)
    1568             : 
    1569           0 :       FMTP_BUILD_FLAG(fmtp_p->is_interlace, "INTERLACE")
    1570             : 
    1571           0 :       FMTP_BUILD_FLAG(fmtp_p->annex_d, "D")
    1572             : 
    1573           0 :       FMTP_BUILD_FLAG(fmtp_p->annex_f, "F")
    1574             : 
    1575           0 :       FMTP_BUILD_FLAG(fmtp_p->annex_i, "I")
    1576             : 
    1577           0 :       FMTP_BUILD_FLAG(fmtp_p->annex_j, "J")
    1578             : 
    1579           0 :       FMTP_BUILD_FLAG(fmtp_p->annex_t, "T")
    1580             : 
    1581           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->annex_k_val > 0,
    1582             :         "K", fmtp_p->annex_k_val)
    1583             : 
    1584           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->annex_n_val > 0,
    1585             :         "N", fmtp_p->annex_n_val)
    1586             : 
    1587           0 :       if ((fmtp_p->annex_p_val_picture_resize > 0) &&
    1588           0 :         (fmtp_p->annex_p_val_warp > 0)) {
    1589           0 :         flex_string_sprintf(fs, "%sP=%d:%d",
    1590             :           semicolon ? ";" : "",
    1591           0 :           fmtp_p->annex_p_val_picture_resize,
    1592           0 :           fmtp_p->annex_p_val_warp);
    1593             : 
    1594           0 :         semicolon = TRUE;
    1595             :       }
    1596             : 
    1597           0 :       FMTP_BUILD_STRING(strlen(fmtp_p->profile_level_id) > 0,
    1598             :         "profile-level-id", fmtp_p->profile_level_id)
    1599             : 
    1600           0 :       FMTP_BUILD_STRING(strlen(fmtp_p->parameter_sets) > 0,
    1601             :         "sprop-parameter-sets", fmtp_p->parameter_sets)
    1602             : 
    1603           0 :       FMTP_BUILD_UNSIGNED(
    1604             :         fmtp_p->packetization_mode < SDP_MAX_PACKETIZATION_MODE_VALUE,
    1605             :         "packetization-mode", fmtp_p->packetization_mode)
    1606             : 
    1607           0 :       FMTP_BUILD_UNSIGNED(
    1608             :         fmtp_p->level_asymmetry_allowed <=
    1609             :         SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE,
    1610             :         "level-asymmetry-allowed", fmtp_p->level_asymmetry_allowed)
    1611             : 
    1612           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->interleaving_depth > 0,
    1613             :         "sprop-interleaving-depth", fmtp_p->interleaving_depth)
    1614             : 
    1615           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_REQ_FLAG,
    1616             :         "sprop-deint-buf-req", fmtp_p->deint_buf_req)
    1617             : 
    1618           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->max_don_diff > 0,
    1619             :         "sprop-max-don-diff", fmtp_p->max_don_diff)
    1620             : 
    1621           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_INIT_BUF_TIME_FLAG,
    1622             :         "sprop-init-buf-time", fmtp_p->init_buf_time)
    1623             : 
    1624           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->max_mbps > 0,
    1625             :         "max-mbps", fmtp_p->max_mbps)
    1626             : 
    1627           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->max_fs > 0, "max-fs", fmtp_p->max_fs)
    1628             : 
    1629           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->max_fr > 0, "max-fr", fmtp_p->max_fr)
    1630             : 
    1631           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->max_cpb > 0, "max-cpb", fmtp_p->max_cpb)
    1632             : 
    1633           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->max_dpb > 0, "max-dpb", fmtp_p->max_dpb)
    1634             : 
    1635           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->max_br > 0, "max-br", fmtp_p->max_br)
    1636             : 
    1637           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->redundant_pic_cap > 0,
    1638             :         "redundant-pic-cap", fmtp_p->redundant_pic_cap)
    1639             : 
    1640           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_CAP_FLAG,
    1641             :         "deint-buf-cap", fmtp_p->deint_buf_cap)
    1642             : 
    1643           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_MAX_RCMD_NALU_SIZE_FLAG,
    1644             :         "max-rcmd-naFMTP_BUILD_FLlu-size", fmtp_p->max_rcmd_nalu_size)
    1645             : 
    1646           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->parameter_add <= 1, "parameter-add",
    1647             :                           fmtp_p->parameter_add)
    1648             : 
    1649           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->maxaveragebitrate > 0,
    1650             :         "maxaveragebitrate", fmtp_p->maxaveragebitrate)
    1651             : 
    1652           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->usedtx <= 1, "usedtx", fmtp_p->usedtx)
    1653             : 
    1654           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->stereo <= 1, "stereo", fmtp_p->stereo)
    1655             : 
    1656           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->useinbandfec <= 1,
    1657             :         "useinbandfec", fmtp_p->useinbandfec)
    1658             : 
    1659           0 :       FMTP_BUILD_STRING(strlen(fmtp_p->maxcodedaudiobandwidth) > 0,
    1660             :         "maxcodedaudiobandwidth", fmtp_p->maxcodedaudiobandwidth)
    1661             : 
    1662           0 :       FMTP_BUILD_UNSIGNED(fmtp_p->cbr <= 1, "cbr", fmtp_p->cbr)
    1663             : 
    1664           0 :       break;
    1665             : 
    1666             :     case SDP_FMTP_NTE:
    1667             :     default:
    1668           0 :       break;
    1669             :   }
    1670             : 
    1671           0 :      for(event_id = 0, mapword = 0, mask = SDP_NE_BIT_0;
    1672           0 :          event_id <= fmtp_p->maxval;
    1673           0 :          event_id++, mapword = event_id/SDP_NE_BITS_PER_WORD ) {
    1674             : 
    1675           0 :          if (event_id % SDP_NE_BITS_PER_WORD) {
    1676           0 :              mask <<= 1;
    1677             :          } else {
    1678             :          /* crossed a bitmap word boundary */
    1679           0 :          mask = SDP_NE_BIT_0;
    1680           0 :              if (!range_start && !range_end && !fmtp_p->bmap[mapword]) {
    1681             :             /* no events in this word, skip to the last event id
    1682             :              * in this bitmap word. */
    1683           0 :                 event_id += SDP_NE_BITS_PER_WORD - 1;
    1684           0 :                 continue;
    1685             :             }
    1686             :          }
    1687             : 
    1688           0 :         if (fmtp_p->bmap[mapword] & mask) {
    1689           0 :             if (!range_start) {
    1690           0 :                 range_start = TRUE;
    1691           0 :                 min = max = (uint8_t)event_id;
    1692             :             } else {
    1693           0 :                 max = (uint8_t)event_id;
    1694             :             }
    1695           0 :         range_end = (max == fmtp_p->maxval);
    1696             :         } else {
    1697             :         /* If we were in the middle of a range, then we've hit the
    1698             :          * end.  If we weren't, there is no end to hit. */
    1699           0 :             range_end = range_start;
    1700             :         }
    1701             : 
    1702             :         /* If this is the end of the range, print it to the string. */
    1703           0 :         if (range_end) {
    1704           0 :             range_start = range_end = FALSE;
    1705             : 
    1706           0 :             flex_string_sprintf(fs, "%u", min);
    1707             : 
    1708           0 :             if (min != max) {
    1709           0 :               flex_string_sprintf(fs, "-%u", max);
    1710             :             }
    1711             : 
    1712           0 :             if (max != fmtp_p->maxval) {
    1713           0 :               flex_string_append(fs, ",");
    1714             :             }
    1715             :         }
    1716             :     }
    1717           0 :     return SDP_SUCCESS;
    1718             : }
    1719             : 
    1720           0 : sdp_result_e sdp_build_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
    1721             : {
    1722             :   sdp_fmtp_t *fmtp_p;
    1723             :   sdp_result_e result;
    1724             : 
    1725           0 :   flex_string_sprintf(fs, "a=%s:%u ",
    1726           0 :     sdp_attr[attr_p->type].name,
    1727           0 :     attr_p->attr.fmtp.payload_num);
    1728             : 
    1729           0 :   fmtp_p = &(attr_p->attr.fmtp);
    1730             : 
    1731           0 :   result = sdp_build_attr_fmtp_params(sdp_p, fmtp_p, fs);
    1732             : 
    1733           0 :   if (result != SDP_SUCCESS) {
    1734           0 :     return result;
    1735             :   }
    1736             : 
    1737           0 :   flex_string_append(fs, "\r\n");
    1738             : 
    1739           0 :   return SDP_SUCCESS;
    1740             : }
    1741             : 
    1742           0 : sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
    1743             :                                     const char *ptr)
    1744             : {
    1745           0 :     sdp_result_e result = SDP_SUCCESS;
    1746             :     char tmp[SDP_MAX_STRING_LEN];
    1747             :     uint32_t streams;
    1748             : 
    1749             :     /* Find the payload type number. */
    1750           0 :     attr_p->attr.sctpmap.port = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
    1751             :                                                       " \t", &result);
    1752           0 :     if (result != SDP_SUCCESS) {
    1753           0 :         sdp_parse_error(sdp_p,
    1754             :             "%s Warning: no sctpmap port number",
    1755           0 :             sdp_p->debug_str);
    1756           0 :         return SDP_INVALID_PARAMETER;
    1757             :     }
    1758             : 
    1759           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    1760           0 :     if (result != SDP_SUCCESS) {
    1761           0 :         sdp_parse_error(sdp_p,
    1762             :             "%s Warning: No sctpmap protocol specified.",
    1763           0 :             sdp_p->debug_str);
    1764           0 :         sdp_p->conf_p->num_invalid_param++;
    1765           0 :         return SDP_INVALID_PARAMETER;
    1766             :     }
    1767           0 :     sstrncpy(attr_p->attr.sctpmap.protocol, tmp,
    1768             :         sizeof (attr_p->attr.sctpmap.protocol));
    1769             : 
    1770           0 :     streams = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
    1771           0 :     if (result != SDP_SUCCESS) {
    1772           0 :         sdp_parse_error(sdp_p,
    1773             :             "%s Warning: No sctpmap streams specified.",
    1774           0 :             sdp_p->debug_str);
    1775           0 :         sdp_p->conf_p->num_invalid_param++;
    1776           0 :         return SDP_INVALID_PARAMETER;
    1777             :     }
    1778             : 
    1779           0 :     attr_p->attr.sctpmap.streams = streams;
    1780             : 
    1781           0 :     return SDP_SUCCESS;
    1782             : }
    1783             : 
    1784           0 : sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
    1785             :                                     flex_string *fs)
    1786             : {
    1787           0 :     flex_string_sprintf(fs, "a=%s:%u %s %u\r\n",
    1788           0 :         sdp_attr[attr_p->type].name,
    1789           0 :         attr_p->attr.sctpmap.port,
    1790           0 :         attr_p->attr.sctpmap.protocol,
    1791             :         attr_p->attr.sctpmap.streams);
    1792             : 
    1793           0 :     return SDP_SUCCESS;
    1794             : }
    1795             : 
    1796           0 : sdp_result_e sdp_parse_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p,
    1797             :                                        const char *ptr)
    1798             : {
    1799             :     /* No parameters to parse. */
    1800           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1801           0 :         SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
    1802             :                   sdp_get_attr_name(attr_p->type));
    1803             :     }
    1804             : 
    1805           0 :     return (SDP_SUCCESS);
    1806             : }
    1807             : 
    1808           0 : sdp_result_e sdp_build_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
    1809             : {
    1810           0 :   flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
    1811             : 
    1812           0 :   return SDP_SUCCESS;
    1813             : }
    1814             : 
    1815           0 : sdp_result_e sdp_parse_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p,
    1816             :                                  const char *ptr)
    1817             : {
    1818             :     int i;
    1819             :     sdp_result_e result;
    1820             :     char tmp[SDP_MAX_STRING_LEN];
    1821             : 
    1822             :     /* Find the strength tag. */
    1823           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    1824           0 :     if (result != SDP_SUCCESS) {
    1825           0 :         sdp_parse_error(sdp_p,
    1826             :             "%s Warning: No qos strength tag specified.",
    1827           0 :             sdp_p->debug_str);
    1828           0 :         sdp_p->conf_p->num_invalid_param++;
    1829           0 :         return (SDP_INVALID_PARAMETER);
    1830             :     }
    1831           0 :     attr_p->attr.qos.strength = SDP_QOS_STRENGTH_UNKNOWN;
    1832           0 :     for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
    1833           0 :         if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
    1834           0 :                         sdp_qos_strength[i].strlen) == 0) {
    1835           0 :             attr_p->attr.qos.strength = (sdp_qos_strength_e)i;
    1836             :         }
    1837             :     }
    1838           0 :     if (attr_p->attr.qos.strength == SDP_QOS_STRENGTH_UNKNOWN) {
    1839           0 :         sdp_parse_error(sdp_p,
    1840             :             "%s Warning: QOS strength tag unrecognized (%s)",
    1841           0 :             sdp_p->debug_str, tmp);
    1842           0 :         sdp_p->conf_p->num_invalid_param++;
    1843           0 :         return (SDP_INVALID_PARAMETER);
    1844             :     }
    1845             : 
    1846             :     /* Find the qos direction. */
    1847           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    1848           0 :     if (result != SDP_SUCCESS) {
    1849           0 :         sdp_parse_error(sdp_p,
    1850             :             "%s Warning: No qos direction specified.",
    1851           0 :             sdp_p->debug_str);
    1852           0 :         sdp_p->conf_p->num_invalid_param++;
    1853           0 :         return (SDP_INVALID_PARAMETER);
    1854             :     }
    1855           0 :     attr_p->attr.qos.direction = SDP_QOS_DIR_UNKNOWN;
    1856           0 :     for (i=0; i < SDP_MAX_QOS_DIR; i++) {
    1857           0 :         if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
    1858           0 :                         sdp_qos_direction[i].strlen) == 0) {
    1859           0 :             attr_p->attr.qos.direction = (sdp_qos_dir_e)i;
    1860             :         }
    1861             :     }
    1862           0 :     if (attr_p->attr.qos.direction == SDP_QOS_DIR_UNKNOWN) {
    1863           0 :         sdp_parse_error(sdp_p,
    1864             :             "%s Warning: QOS direction unrecognized (%s)",
    1865           0 :             sdp_p->debug_str, tmp);
    1866           0 :         sdp_p->conf_p->num_invalid_param++;
    1867           0 :         return (SDP_INVALID_PARAMETER);
    1868             :     }
    1869             : 
    1870             :     /* See if confirm was specified.  Defaults to FALSE. */
    1871           0 :     attr_p->attr.qos.confirm = FALSE;
    1872           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    1873           0 :     if (result == SDP_SUCCESS) {
    1874           0 :         if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
    1875           0 :             attr_p->attr.qos.confirm = TRUE;
    1876             :         }
    1877           0 :         if (attr_p->attr.qos.confirm == FALSE) {
    1878           0 :             sdp_parse_error(sdp_p,
    1879             :                 "%s Warning: QOS confirm parameter invalid (%s)",
    1880           0 :                 sdp_p->debug_str, tmp);
    1881           0 :             sdp_p->conf_p->num_invalid_param++;
    1882           0 :             return (SDP_INVALID_PARAMETER);
    1883             :         }
    1884             :     }
    1885             : 
    1886           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1887           0 :         SDP_PRINT("%s Parsed a=%s, strength %s, direction %s, confirm %s",
    1888             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    1889             :                   sdp_get_qos_strength_name(attr_p->attr.qos.strength),
    1890             :                   sdp_get_qos_direction_name(attr_p->attr.qos.direction),
    1891             :                   (attr_p->attr.qos.confirm ? "set" : "not set"));
    1892             :     }
    1893             : 
    1894           0 :     return (SDP_SUCCESS);
    1895             : }
    1896             : 
    1897           0 : sdp_result_e sdp_build_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
    1898             : {
    1899           0 :   flex_string_sprintf(fs, "a=%s:%s %s%s\r\n", sdp_attr[attr_p->type].name,
    1900             :     sdp_get_qos_strength_name(attr_p->attr.qos.strength),
    1901             :     sdp_get_qos_direction_name(attr_p->attr.qos.direction),
    1902           0 :     attr_p->attr.qos.confirm ? " confirm" : "");
    1903             : 
    1904           0 :   return SDP_SUCCESS;
    1905             : }
    1906             : 
    1907           0 : sdp_result_e sdp_parse_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p,
    1908             :                                  const char *ptr)
    1909             : {
    1910             :     int i;
    1911             :     sdp_result_e result;
    1912             :     char tmp[SDP_MAX_STRING_LEN];
    1913             : 
    1914             :     /* Find the curr type tag. */
    1915           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    1916           0 :     if (result != SDP_SUCCESS) {
    1917           0 :         sdp_parse_error(sdp_p,
    1918             :             "%s Warning: No curr attr type specified.",
    1919           0 :             sdp_p->debug_str);
    1920           0 :         sdp_p->conf_p->num_invalid_param++;
    1921           0 :         return (SDP_INVALID_PARAMETER);
    1922             :     }
    1923           0 :     attr_p->attr.curr.type = SDP_CURR_UNKNOWN_TYPE;
    1924           0 :     for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
    1925           0 :         if (cpr_strncasecmp(tmp, sdp_curr_type[i].name,
    1926           0 :                         sdp_curr_type[i].strlen) == 0) {
    1927           0 :             attr_p->attr.curr.type = (sdp_curr_type_e)i;
    1928             :         }
    1929             :     }
    1930             : 
    1931           0 :     if (attr_p->attr.curr.type != SDP_CURR_QOS_TYPE) {
    1932           0 :         sdp_parse_error(sdp_p,
    1933             :             "%s Warning: Unknown curr type.",
    1934           0 :             sdp_p->debug_str);
    1935           0 :         sdp_p->conf_p->num_invalid_param++;
    1936           0 :         return (SDP_INVALID_PARAMETER);
    1937             :     }
    1938             : 
    1939             :     /* Check qos status type */
    1940           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    1941           0 :      if (result != SDP_SUCCESS) {
    1942           0 :         sdp_parse_error(sdp_p,
    1943             :             "%s Warning: No curr attr type specified.",
    1944           0 :             sdp_p->debug_str);
    1945           0 :         sdp_p->conf_p->num_invalid_param++;
    1946           0 :         return (SDP_INVALID_PARAMETER);
    1947             :     }
    1948           0 :     attr_p->attr.curr.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
    1949           0 :     for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
    1950           0 :         if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
    1951           0 :                         sdp_qos_status_type[i].strlen) == 0) {
    1952           0 :             attr_p->attr.curr.status_type = (sdp_qos_status_types_e)i;
    1953             :         }
    1954             :     }
    1955             : 
    1956             : 
    1957             :     /* Find the qos direction. */
    1958           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    1959           0 :     if (result != SDP_SUCCESS) {
    1960           0 :         sdp_parse_error(sdp_p,
    1961             :             "%s Warning: No qos direction specified.",
    1962           0 :             sdp_p->debug_str);
    1963           0 :         sdp_p->conf_p->num_invalid_param++;
    1964           0 :         return (SDP_INVALID_PARAMETER);
    1965             :     }
    1966           0 :     attr_p->attr.curr.direction = SDP_QOS_DIR_UNKNOWN;
    1967           0 :     for (i=0; i < SDP_MAX_QOS_DIR; i++) {
    1968           0 :         if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
    1969           0 :                         sdp_qos_direction[i].strlen) == 0) {
    1970           0 :             attr_p->attr.curr.direction = (sdp_qos_dir_e)i;
    1971             :         }
    1972             :     }
    1973           0 :     if (attr_p->attr.curr.direction == SDP_QOS_DIR_UNKNOWN) {
    1974           0 :         sdp_parse_error(sdp_p,
    1975             :             "%s Warning: QOS direction unrecognized (%s)",
    1976           0 :             sdp_p->debug_str, tmp);
    1977           0 :         sdp_p->conf_p->num_invalid_param++;
    1978           0 :         return (SDP_INVALID_PARAMETER);
    1979             :     }
    1980             : 
    1981           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    1982           0 :         SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
    1983             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    1984             :                   sdp_get_curr_type_name(attr_p->attr.curr.type),
    1985             :                   sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
    1986             :                   sdp_get_qos_direction_name(attr_p->attr.curr.direction));
    1987             :     }
    1988             : 
    1989           0 :     return (SDP_SUCCESS);
    1990             : }
    1991             : 
    1992           0 : sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
    1993             : {
    1994           0 :   flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
    1995           0 :     sdp_attr[attr_p->type].name,
    1996             :     sdp_get_curr_type_name(attr_p->attr.curr.type),
    1997             :     sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
    1998             :     sdp_get_qos_direction_name(attr_p->attr.curr.direction));
    1999             : 
    2000           0 :   return SDP_SUCCESS;
    2001             : }
    2002             : 
    2003           0 : sdp_result_e sdp_parse_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2004             :                                  const char *ptr)
    2005             : {
    2006             :     int i;
    2007             :     sdp_result_e result;
    2008             :     char tmp[SDP_MAX_STRING_LEN];
    2009             : 
    2010             :     /* Find the curr type tag. */
    2011           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2012           0 :     if (result != SDP_SUCCESS) {
    2013           0 :         sdp_parse_error(sdp_p,
    2014             :             "%s Warning: No des attr type specified.",
    2015           0 :             sdp_p->debug_str);
    2016           0 :         sdp_p->conf_p->num_invalid_param++;
    2017           0 :         return (SDP_INVALID_PARAMETER);
    2018             :     }
    2019           0 :     attr_p->attr.des.type = SDP_DES_UNKNOWN_TYPE;
    2020           0 :     for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
    2021           0 :         if (cpr_strncasecmp(tmp, sdp_des_type[i].name,
    2022           0 :                         sdp_des_type[i].strlen) == 0) {
    2023           0 :             attr_p->attr.des.type = (sdp_des_type_e)i;
    2024             :         }
    2025             :     }
    2026             : 
    2027           0 :     if (attr_p->attr.des.type != SDP_DES_QOS_TYPE) {
    2028           0 :         sdp_parse_error(sdp_p,
    2029             :             "%s Warning: Unknown conf type.",
    2030           0 :             sdp_p->debug_str);
    2031           0 :         sdp_p->conf_p->num_invalid_param++;
    2032           0 :         return (SDP_INVALID_PARAMETER);
    2033             :     }
    2034             : 
    2035             :     /* Find the strength tag. */
    2036           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2037           0 :     if (result != SDP_SUCCESS) {
    2038           0 :         sdp_parse_error(sdp_p,
    2039             :             "%s Warning: No qos strength tag specified.",
    2040           0 :             sdp_p->debug_str);
    2041           0 :         sdp_p->conf_p->num_invalid_param++;
    2042           0 :         return (SDP_INVALID_PARAMETER);
    2043             :     }
    2044           0 :     attr_p->attr.des.strength = SDP_QOS_STRENGTH_UNKNOWN;
    2045           0 :     for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
    2046           0 :         if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
    2047           0 :                         sdp_qos_strength[i].strlen) == 0) {
    2048           0 :             attr_p->attr.des.strength = (sdp_qos_strength_e)i;
    2049             :         }
    2050             :     }
    2051           0 :     if (attr_p->attr.des.strength == SDP_QOS_STRENGTH_UNKNOWN) {
    2052           0 :         sdp_parse_error(sdp_p,
    2053             :             "%s Warning: QOS strength tag unrecognized (%s)",
    2054           0 :             sdp_p->debug_str, tmp);
    2055           0 :         sdp_p->conf_p->num_invalid_param++;
    2056           0 :         return (SDP_INVALID_PARAMETER);
    2057             :     }
    2058             : 
    2059             :     /* Check qos status type */
    2060           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2061           0 :      if (result != SDP_SUCCESS) {
    2062           0 :         sdp_parse_error(sdp_p,
    2063             :             "%s Warning: No des attr type specified.",
    2064           0 :             sdp_p->debug_str);
    2065           0 :         sdp_p->conf_p->num_invalid_param++;
    2066           0 :         return (SDP_INVALID_PARAMETER);
    2067             :     }
    2068           0 :     attr_p->attr.des.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
    2069           0 :     for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
    2070           0 :         if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
    2071           0 :                         sdp_qos_status_type[i].strlen) == 0) {
    2072           0 :             attr_p->attr.des.status_type = (sdp_qos_status_types_e)i;
    2073             :         }
    2074             :     }
    2075             : 
    2076             : 
    2077             :     /* Find the qos direction. */
    2078           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2079           0 :     if (result != SDP_SUCCESS) {
    2080           0 :         sdp_parse_error(sdp_p,
    2081             :             "%s Warning: No qos direction specified.",
    2082           0 :             sdp_p->debug_str);
    2083           0 :         sdp_p->conf_p->num_invalid_param++;
    2084           0 :         return (SDP_INVALID_PARAMETER);
    2085             :     }
    2086           0 :     attr_p->attr.des.direction = SDP_QOS_DIR_UNKNOWN;
    2087           0 :     for (i=0; i < SDP_MAX_QOS_DIR; i++) {
    2088           0 :         if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
    2089           0 :                         sdp_qos_direction[i].strlen) == 0) {
    2090           0 :             attr_p->attr.des.direction = (sdp_qos_dir_e)i;
    2091             :         }
    2092             :     }
    2093           0 :     if (attr_p->attr.des.direction == SDP_QOS_DIR_UNKNOWN) {
    2094           0 :         sdp_parse_error(sdp_p,
    2095             :             "%s Warning: QOS direction unrecognized (%s)",
    2096           0 :             sdp_p->debug_str, tmp);
    2097           0 :         sdp_p->conf_p->num_invalid_param++;
    2098           0 :         return (SDP_INVALID_PARAMETER);
    2099             :     }
    2100             : 
    2101           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2102           0 :         SDP_PRINT("%s Parsed a=%s, type %s strength %s status type %s, direction %s",
    2103             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    2104             :                   sdp_get_des_type_name(attr_p->attr.des.type),
    2105             :                   sdp_get_qos_strength_name(attr_p->attr.qos.strength),
    2106             :                   sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
    2107             :                   sdp_get_qos_direction_name(attr_p->attr.des.direction));
    2108             :     }
    2109             : 
    2110           0 :     return (SDP_SUCCESS);
    2111             : }
    2112             : 
    2113             : 
    2114           0 : sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
    2115             : {
    2116           0 :   flex_string_sprintf(fs, "a=%s:%s %s %s %s\r\n",
    2117           0 :     sdp_attr[attr_p->type].name,
    2118           0 :     sdp_get_curr_type_name((sdp_curr_type_e)attr_p->attr.des.type),
    2119             :     sdp_get_qos_strength_name(attr_p->attr.des.strength),
    2120             :     sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
    2121             :     sdp_get_qos_direction_name(attr_p->attr.des.direction));
    2122             : 
    2123           0 :   return SDP_SUCCESS;
    2124             : }
    2125             : 
    2126           0 : sdp_result_e sdp_parse_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2127             :                                  const char *ptr)
    2128             : {
    2129             :     int i;
    2130             :     sdp_result_e result;
    2131             :     char tmp[SDP_MAX_STRING_LEN];
    2132             : 
    2133             :     /* Find the curr type tag. */
    2134           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2135           0 :     if (result != SDP_SUCCESS) {
    2136           0 :         sdp_parse_error(sdp_p,
    2137             :             "%s Warning: No conf attr type specified.",
    2138           0 :             sdp_p->debug_str);
    2139           0 :         sdp_p->conf_p->num_invalid_param++;
    2140           0 :         return (SDP_INVALID_PARAMETER);
    2141             :     }
    2142           0 :     attr_p->attr.conf.type = SDP_CONF_UNKNOWN_TYPE;
    2143           0 :     for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
    2144           0 :         if (cpr_strncasecmp(tmp, sdp_conf_type[i].name,
    2145           0 :                         sdp_conf_type[i].strlen) == 0) {
    2146           0 :             attr_p->attr.conf.type = (sdp_conf_type_e)i;
    2147             :         }
    2148             :     }
    2149             : 
    2150           0 :     if (attr_p->attr.conf.type != SDP_CONF_QOS_TYPE) {
    2151           0 :         sdp_parse_error(sdp_p,
    2152             :             "%s Warning: Unknown conf type.",
    2153           0 :             sdp_p->debug_str);
    2154           0 :         sdp_p->conf_p->num_invalid_param++;
    2155           0 :         return (SDP_INVALID_PARAMETER);
    2156             :     }
    2157             : 
    2158             :     /* Check qos status type */
    2159           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2160           0 :      if (result != SDP_SUCCESS) {
    2161           0 :         sdp_parse_error(sdp_p,
    2162             :             "%s Warning: No conf attr type specified.",
    2163           0 :             sdp_p->debug_str);
    2164           0 :         sdp_p->conf_p->num_invalid_param++;
    2165           0 :         return (SDP_INVALID_PARAMETER);
    2166             :     }
    2167           0 :     attr_p->attr.conf.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
    2168           0 :     for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
    2169           0 :         if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
    2170           0 :                         sdp_qos_status_type[i].strlen) == 0) {
    2171           0 :             attr_p->attr.conf.status_type = (sdp_qos_status_types_e)i;
    2172             :         }
    2173             :     }
    2174             : 
    2175             : 
    2176             :     /* Find the qos direction. */
    2177           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2178           0 :     if (result != SDP_SUCCESS) {
    2179           0 :         sdp_parse_error(sdp_p,
    2180             :             "%s Warning: No qos direction specified.",
    2181           0 :             sdp_p->debug_str);
    2182           0 :         sdp_p->conf_p->num_invalid_param++;
    2183           0 :         return (SDP_INVALID_PARAMETER);
    2184             :     }
    2185           0 :     attr_p->attr.conf.direction = SDP_QOS_DIR_UNKNOWN;
    2186           0 :     for (i=0; i < SDP_MAX_QOS_DIR; i++) {
    2187           0 :         if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
    2188           0 :                         sdp_qos_direction[i].strlen) == 0) {
    2189           0 :             attr_p->attr.conf.direction = (sdp_qos_dir_e)i;
    2190             :         }
    2191             :     }
    2192           0 :     if (attr_p->attr.conf.direction == SDP_QOS_DIR_UNKNOWN) {
    2193           0 :         sdp_parse_error(sdp_p,
    2194             :             "%s Warning: QOS direction unrecognized (%s)",
    2195           0 :             sdp_p->debug_str, tmp);
    2196           0 :         sdp_p->conf_p->num_invalid_param++;
    2197           0 :         return (SDP_INVALID_PARAMETER);
    2198             :     }
    2199             : 
    2200           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2201           0 :         SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
    2202             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    2203             :                   sdp_get_conf_type_name(attr_p->attr.conf.type),
    2204             :                   sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
    2205             :                   sdp_get_qos_direction_name(attr_p->attr.conf.direction));
    2206             :     }
    2207             : 
    2208           0 :     return (SDP_SUCCESS);
    2209             : }
    2210             : 
    2211           0 : sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
    2212             : {
    2213           0 :   flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
    2214           0 :     sdp_attr[attr_p->type].name,
    2215             :     sdp_get_conf_type_name(attr_p->attr.conf.type),
    2216             :     sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
    2217             :     sdp_get_qos_direction_name(attr_p->attr.conf.direction));
    2218             : 
    2219           0 :   return SDP_SUCCESS;
    2220             : }
    2221             : 
    2222             : /*
    2223             :  *  Parse a rtpmap or a sprtmap. Both formats use the same structure
    2224             :  *  the only difference being the keyword "rtpmap" vs "sprtmap". The
    2225             :  *  rtpmap field in the sdp_attr_t is used to store both mappings.
    2226             :  */
    2227           0 : sdp_result_e sdp_parse_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2228             :         const char *ptr)
    2229             : {
    2230             :     sdp_result_e  result;
    2231             : 
    2232           0 :     attr_p->attr.transport_map.payload_num = 0;
    2233           0 :     attr_p->attr.transport_map.encname[0]  = '\0';
    2234           0 :     attr_p->attr.transport_map.clockrate   = 0;
    2235           0 :     attr_p->attr.transport_map.num_chan    = 1;
    2236             : 
    2237             :     /* Find the payload type number. */
    2238           0 :     attr_p->attr.transport_map.payload_num =
    2239           0 :     (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
    2240           0 :     if (result != SDP_SUCCESS) {
    2241           0 :         sdp_parse_error(sdp_p,
    2242             :             "%s Warning: Invalid payload type specified for %s attribute.",
    2243           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    2244           0 :         sdp_p->conf_p->num_invalid_param++;
    2245           0 :         return (SDP_INVALID_PARAMETER);
    2246             :     }
    2247             : 
    2248             :     /* Find the encoding name. */
    2249           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.transport_map.encname,
    2250             :                             sizeof(attr_p->attr.transport_map.encname), "/ \t", &result);
    2251           0 :     if (result != SDP_SUCCESS) {
    2252           0 :         sdp_parse_error(sdp_p,
    2253             :             "%s Warning: No encoding name specified in %s attribute.",
    2254           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    2255           0 :         sdp_p->conf_p->num_invalid_param++;
    2256           0 :         return (SDP_INVALID_PARAMETER);
    2257             :     }
    2258             : 
    2259             :     /* Find the clockrate. */
    2260           0 :     attr_p->attr.transport_map.clockrate =
    2261           0 :         sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
    2262           0 :     if (result != SDP_SUCCESS) {
    2263           0 :         sdp_parse_error(sdp_p,
    2264             :             "%s Warning: No clockrate specified for "
    2265             :             "%s attribute, set to default of 8000.",
    2266           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    2267           0 :         attr_p->attr.transport_map.clockrate = 8000;
    2268             :     }
    2269             : 
    2270             :     /* Find the number of channels, if specified. This is optional. */
    2271           0 :     if (*ptr == '/') {
    2272             :         /* If a '/' exists, expect something valid beyond it. */
    2273           0 :         attr_p->attr.transport_map.num_chan =
    2274           0 :             (uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
    2275           0 :         if (result != SDP_SUCCESS) {
    2276           0 :             sdp_parse_error(sdp_p,
    2277             :                 "%s Warning: Invalid number of channels parameter"
    2278           0 :                 " for rtpmap attribute.", sdp_p->debug_str);
    2279           0 :             sdp_p->conf_p->num_invalid_param++;
    2280           0 :             return (SDP_INVALID_PARAMETER);
    2281             :         }
    2282             :     }
    2283             : 
    2284           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2285           0 :         SDP_PRINT("%s Parsed a=%s, payload type %u, encoding name %s, "
    2286             :                   "clockrate %u", sdp_p->debug_str,
    2287             :                   sdp_get_attr_name(attr_p->type),
    2288             :                   attr_p->attr.transport_map.payload_num,
    2289             :                   attr_p->attr.transport_map.encname,
    2290             :                   attr_p->attr.transport_map.clockrate);
    2291           0 :         if (attr_p->attr.transport_map.num_chan != 1) {
    2292           0 :             SDP_PRINT("/%u", attr_p->attr.transport_map.num_chan);
    2293             :         }
    2294             :     }
    2295             : 
    2296           0 :     return (SDP_SUCCESS);
    2297             : }
    2298             : 
    2299             : /*
    2300             :  *  Build a rtpmap or a sprtmap. Both formats use the same structure
    2301             :  *  the only difference being the keyword "rtpmap" vs "sprtmap". The
    2302             :  *  rtpmap field in the sdp_attr_t is used for both mappings.
    2303             :  */
    2304           0 : sdp_result_e sdp_build_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2305             :         flex_string *fs)
    2306             : {
    2307           0 :   if (attr_p->attr.transport_map.num_chan == 1) {
    2308           0 :     flex_string_sprintf(fs, "a=%s:%u %s/%u\r\n",
    2309           0 :       sdp_attr[attr_p->type].name,
    2310           0 :       attr_p->attr.transport_map.payload_num,
    2311           0 :       attr_p->attr.transport_map.encname,
    2312             :       attr_p->attr.transport_map.clockrate);
    2313             :   } else {
    2314           0 :     flex_string_sprintf(fs, "a=%s:%u %s/%u/%u\r\n",
    2315           0 :       sdp_attr[attr_p->type].name,
    2316           0 :       attr_p->attr.transport_map.payload_num,
    2317           0 :       attr_p->attr.transport_map.encname,
    2318             :       attr_p->attr.transport_map.clockrate,
    2319           0 :       attr_p->attr.transport_map.num_chan);
    2320             :   }
    2321             : 
    2322           0 :   return SDP_SUCCESS;
    2323             : }
    2324             : 
    2325           0 : sdp_result_e sdp_parse_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2326             :                                     const char *ptr)
    2327             : {
    2328             :     int i;
    2329             :     char         *slash_ptr;
    2330             :     sdp_result_e  result;
    2331           0 :     tinybool      type_found = FALSE;
    2332             :     char          tmp[SDP_MAX_STRING_LEN];
    2333             : 
    2334             :     /* Find the subnet network type. */
    2335           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2336           0 :     if (result != SDP_SUCCESS) {
    2337           0 :         sdp_parse_error(sdp_p,
    2338             :             "%s Warning: No network type specified in subnet attribute.",
    2339           0 :             sdp_p->debug_str);
    2340           0 :         sdp_p->conf_p->num_invalid_param++;
    2341           0 :         return (SDP_INVALID_PARAMETER);
    2342             :     }
    2343           0 :     attr_p->attr.subnet.nettype = SDP_NT_UNSUPPORTED;
    2344           0 :     for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
    2345           0 :         if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
    2346           0 :                         sdp_nettype[i].strlen) == 0) {
    2347           0 :             type_found = TRUE;
    2348             :         }
    2349           0 :         if (type_found == TRUE) {
    2350           0 :             if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
    2351           0 :                 attr_p->attr.subnet.nettype = (sdp_nettype_e)i;
    2352             :             }
    2353           0 :             type_found = FALSE;
    2354             :         }
    2355             :     }
    2356           0 :     if (attr_p->attr.subnet.nettype == SDP_NT_UNSUPPORTED) {
    2357           0 :         sdp_parse_error(sdp_p,
    2358             :             "%s Warning: Subnet network type unsupported (%s).",
    2359           0 :             sdp_p->debug_str, tmp);
    2360           0 :         sdp_p->conf_p->num_invalid_param++;
    2361           0 :         return (SDP_INVALID_PARAMETER);
    2362             :     }
    2363             : 
    2364             :     /* Find the subnet address type. */
    2365           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2366           0 :     if (result != SDP_SUCCESS) {
    2367           0 :         sdp_parse_error(sdp_p,
    2368             :             "%s Warning: No address type specified in subnet attribute.",
    2369           0 :             sdp_p->debug_str);
    2370           0 :         sdp_p->conf_p->num_invalid_param++;
    2371           0 :         return (SDP_INVALID_PARAMETER);
    2372             :     }
    2373           0 :     attr_p->attr.subnet.addrtype = SDP_AT_UNSUPPORTED;
    2374           0 :     for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
    2375           0 :         if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
    2376           0 :                         sdp_addrtype[i].strlen) == 0) {
    2377           0 :             type_found = TRUE;
    2378             :         }
    2379           0 :         if (type_found == TRUE) {
    2380           0 :             if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
    2381           0 :                 attr_p->attr.subnet.addrtype = (sdp_addrtype_e)i;
    2382             :             }
    2383           0 :             type_found = FALSE;
    2384             :         }
    2385             :     }
    2386           0 :     if (attr_p->attr.subnet.addrtype == SDP_AT_UNSUPPORTED) {
    2387           0 :         sdp_parse_error(sdp_p,
    2388             :             "%s Warning: Subnet address type unsupported (%s).",
    2389           0 :             sdp_p->debug_str, tmp);
    2390           0 :         sdp_p->conf_p->num_invalid_param++;
    2391           0 :         return (SDP_INVALID_PARAMETER);
    2392             :     }
    2393             : 
    2394             :     /* Find the subnet address.  */
    2395           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.subnet.addr,
    2396             :                             sizeof(attr_p->attr.subnet.addr), " \t", &result);
    2397           0 :     if (result != SDP_SUCCESS) {
    2398           0 :         sdp_parse_error(sdp_p,
    2399             :             "%s Warning: No subnet address specified in "
    2400           0 :             "subnet attribute.", sdp_p->debug_str);
    2401           0 :         sdp_p->conf_p->num_invalid_param++;
    2402           0 :         return (SDP_INVALID_PARAMETER);
    2403             :     }
    2404           0 :     slash_ptr = sdp_findchar(attr_p->attr.subnet.addr, "/");
    2405           0 :     if (*slash_ptr == '/') {
    2406           0 :         *slash_ptr++ = '\0';
    2407             :         /* If the '/' exists, expect a valid prefix to follow. */
    2408           0 :         attr_p->attr.subnet.prefix = sdp_getnextnumtok(slash_ptr,
    2409             :                                                   (const char **)&slash_ptr,
    2410             :                                                   " \t", &result);
    2411           0 :         if (result != SDP_SUCCESS) {
    2412           0 :             sdp_parse_error(sdp_p,
    2413             :                 "%s Warning: Invalid subnet prefix specified in "
    2414           0 :                 "subnet attribute.", sdp_p->debug_str);
    2415           0 :             sdp_p->conf_p->num_invalid_param++;
    2416           0 :             return (SDP_INVALID_PARAMETER);
    2417             :         }
    2418             :     } else {
    2419           0 :         attr_p->attr.subnet.prefix = SDP_INVALID_VALUE;
    2420             :     }
    2421             : 
    2422           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2423           0 :         SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s ",
    2424             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    2425             :                   sdp_get_network_name(attr_p->attr.subnet.nettype),
    2426             :                   sdp_get_address_name(attr_p->attr.subnet.addrtype),
    2427             :                   attr_p->attr.subnet.addr);
    2428           0 :         if (attr_p->attr.subnet.prefix != SDP_INVALID_VALUE) {
    2429           0 :             SDP_PRINT("/%u", (ushort)attr_p->attr.subnet.prefix);
    2430             :         }
    2431             :     }
    2432             : 
    2433           0 :     return (SDP_SUCCESS);
    2434             : }
    2435             : 
    2436           0 : sdp_result_e sdp_build_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2437             :                                     flex_string *fs)
    2438             : {
    2439           0 :   if (attr_p->attr.subnet.prefix == SDP_INVALID_VALUE) {
    2440           0 :     flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
    2441           0 :       sdp_attr[attr_p->type].name,
    2442             :       sdp_get_network_name(attr_p->attr.subnet.nettype),
    2443             :       sdp_get_address_name(attr_p->attr.subnet.addrtype),
    2444           0 :       attr_p->attr.subnet.addr);
    2445             :   } else {
    2446           0 :     flex_string_sprintf(fs, "a=%s:%s %s %s/%u\r\n",
    2447           0 :       sdp_attr[attr_p->type].name,
    2448             :       sdp_get_network_name(attr_p->attr.subnet.nettype),
    2449             :       sdp_get_address_name(attr_p->attr.subnet.addrtype),
    2450           0 :       attr_p->attr.subnet.addr,
    2451           0 :       (ushort)attr_p->attr.subnet.prefix);
    2452             :   }
    2453             : 
    2454           0 :   return SDP_SUCCESS;
    2455             : }
    2456             : 
    2457           0 : sdp_result_e sdp_parse_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2458             :                                           const char *ptr)
    2459             : {
    2460             :     int i;
    2461             :     sdp_result_e result;
    2462             :     char tmp[SDP_MAX_STRING_LEN];
    2463             : 
    2464             :     /* Find the rate mgmt. */
    2465           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2466           0 :     if (result != SDP_SUCCESS) {
    2467           0 :         sdp_parse_error(sdp_p,
    2468             :             "%s Warning: No t38 rate management specified.",
    2469           0 :             sdp_p->debug_str);
    2470           0 :         sdp_p->conf_p->num_invalid_param++;
    2471           0 :         return (SDP_INVALID_PARAMETER);
    2472             :     }
    2473           0 :     attr_p->attr.t38ratemgmt = SDP_T38_UNKNOWN_RATE;
    2474           0 :     for (i=0; i < SDP_T38_MAX_RATES; i++) {
    2475           0 :         if (cpr_strncasecmp(tmp, sdp_t38_rate[i].name,
    2476           0 :                         sdp_t38_rate[i].strlen) == 0) {
    2477           0 :             attr_p->attr.t38ratemgmt = (sdp_t38_ratemgmt_e)i;
    2478             :         }
    2479             :     }
    2480             : 
    2481           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2482           0 :         SDP_PRINT("%s Parsed a=%s, rate %s", sdp_p->debug_str,
    2483             :                   sdp_get_attr_name(attr_p->type),
    2484             :                   sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
    2485             :     }
    2486             : 
    2487           0 :     return (SDP_SUCCESS);
    2488             : }
    2489             : 
    2490           0 : sdp_result_e sdp_build_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2491             :                                           flex_string *fs)
    2492             : {
    2493           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    2494           0 :     sdp_attr[attr_p->type].name,
    2495             :     sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
    2496             : 
    2497           0 :   return SDP_SUCCESS;
    2498             : }
    2499             : 
    2500           0 : sdp_result_e sdp_parse_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2501             :                                        const char *ptr)
    2502             : {
    2503             :     int i;
    2504             :     sdp_result_e result;
    2505             :     char tmp[SDP_MAX_STRING_LEN];
    2506             : 
    2507             :     /* Find the udpec. */
    2508           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2509           0 :     if (result != SDP_SUCCESS) {
    2510           0 :         sdp_parse_error(sdp_p,
    2511             :             "%s Warning: No t38 udpEC specified.",
    2512           0 :             sdp_p->debug_str);
    2513           0 :         sdp_p->conf_p->num_invalid_param++;
    2514           0 :         return (SDP_INVALID_PARAMETER);
    2515             :     }
    2516           0 :     attr_p->attr.t38udpec = SDP_T38_UDPEC_UNKNOWN;
    2517           0 :     for (i=0; i < SDP_T38_MAX_UDPEC; i++) {
    2518           0 :         if (cpr_strncasecmp(tmp, sdp_t38_udpec[i].name,
    2519           0 :                         sdp_t38_udpec[i].strlen) == 0) {
    2520           0 :             attr_p->attr.t38udpec = (sdp_t38_udpec_e)i;
    2521             :         }
    2522             :     }
    2523             : 
    2524           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2525           0 :         SDP_PRINT("%s Parsed a=%s, udpec %s", sdp_p->debug_str,
    2526             :                   sdp_get_attr_name(attr_p->type),
    2527             :                   sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
    2528             :     }
    2529             : 
    2530           0 :     return (SDP_SUCCESS);
    2531             : }
    2532             : 
    2533           0 : sdp_result_e sdp_build_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2534             :                                        flex_string *fs)
    2535             : {
    2536           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    2537           0 :     sdp_attr[attr_p->type].name,
    2538             :     sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
    2539             : 
    2540           0 :   return SDP_SUCCESS;
    2541             : }
    2542             : 
    2543           0 : sdp_result_e sdp_parse_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2544             :                                       const char *ptr)
    2545             : {
    2546             :     uint16_t i;
    2547             :     sdp_result_e result;
    2548             : 
    2549           0 :     for (i=0; i < SDP_MAX_PAYLOAD_TYPES; i++) {
    2550           0 :         attr_p->attr.pccodec.payload_type[i] = (ushort)sdp_getnextnumtok(ptr, &ptr,
    2551             :                                                                " \t", &result);
    2552           0 :         if (result != SDP_SUCCESS) {
    2553           0 :             break;
    2554             :         }
    2555           0 :         attr_p->attr.pccodec.num_payloads++;
    2556             :     }
    2557             : 
    2558           0 :     if (attr_p->attr.pccodec.num_payloads == 0) {
    2559           0 :         sdp_parse_error(sdp_p,
    2560             :             "%s Warning: No payloads specified for %s attr.",
    2561           0 :             sdp_p->debug_str, sdp_attr[attr_p->type].name);
    2562           0 :         sdp_p->conf_p->num_invalid_param++;
    2563           0 :         return (SDP_INVALID_PARAMETER);
    2564             :     }
    2565             : 
    2566           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2567           0 :         SDP_PRINT("%s Parsed a=%s, num payloads %u, payloads: ",
    2568             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    2569             :                   attr_p->attr.pccodec.num_payloads);
    2570           0 :         for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
    2571           0 :             SDP_PRINT("%u ", attr_p->attr.pccodec.payload_type[i]);
    2572             :         }
    2573             :     }
    2574             : 
    2575           0 :     return (SDP_SUCCESS);
    2576             : }
    2577             : 
    2578           0 : sdp_result_e sdp_build_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2579             :                                       flex_string *fs)
    2580             : {
    2581             :   int i;
    2582             : 
    2583           0 :   flex_string_sprintf(fs, "a=%s: ", sdp_attr[attr_p->type].name);
    2584             : 
    2585           0 :   for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
    2586           0 :     flex_string_sprintf(fs, "%u ", attr_p->attr.pccodec.payload_type[i]);
    2587             :   }
    2588             : 
    2589           0 :   flex_string_append(fs, "\r\n");
    2590             : 
    2591           0 :   return SDP_SUCCESS;
    2592             : }
    2593             : 
    2594             : 
    2595           0 : sdp_result_e sdp_parse_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2596             :                                  const char *ptr)
    2597             : {
    2598             :     uint16_t           i;
    2599             :     sdp_result_e  result;
    2600             :     sdp_mca_t    *cap_p;
    2601             :     char          tmp[SDP_MAX_STRING_LEN];
    2602             : 
    2603             :     /* Set the capability pointer to NULL for now in case we encounter
    2604             :      * an error in parsing.
    2605             :      */
    2606           0 :     attr_p->attr.cap_p = NULL;
    2607             :     /* Set the capability valid flag to FALSE in case we encounter an
    2608             :      * error.  If we do, we don't want to process any X-cpar/cpar attributes
    2609             :      * from this point until we process the next valid X-cap/cdsc attr. */
    2610           0 :     sdp_p->cap_valid = FALSE;
    2611             : 
    2612             :     /* Allocate resource for new capability. Note that the capability
    2613             :      * uses the same structure used for media lines.
    2614             :      */
    2615           0 :     cap_p = sdp_alloc_mca(sdp_p->parse_line);
    2616           0 :     if (cap_p == NULL) {
    2617           0 :         sdp_p->conf_p->num_no_resource++;
    2618           0 :         return (SDP_NO_RESOURCE);
    2619             :     }
    2620             : 
    2621             :     /* Find the capability number. We don't need to store this since we
    2622             :      * calculate it for ourselves as we need to. But it must be specified. */
    2623           0 :     (void)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
    2624           0 :     if (result != SDP_SUCCESS) {
    2625           0 :         sdp_parse_error(sdp_p,
    2626             :             "%s Warning: Capability not specified for %s, "
    2627           0 :             "unable to parse.", sdp_p->debug_str,
    2628             :             sdp_get_attr_name(attr_p->type));
    2629           0 :         SDP_FREE(cap_p);
    2630           0 :         sdp_p->conf_p->num_invalid_param++;
    2631           0 :         return (SDP_INVALID_PARAMETER);
    2632             :     }
    2633             : 
    2634             :     /* Find the media type. */
    2635           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2636           0 :     if (result != SDP_SUCCESS) {
    2637           0 :         sdp_parse_error(sdp_p,
    2638             :             "%s No media type specified for %s attribute, "
    2639             :             "unable to parse.",
    2640           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    2641           0 :         SDP_FREE(cap_p);
    2642           0 :         sdp_p->conf_p->num_invalid_param++;
    2643           0 :         return (SDP_INVALID_PARAMETER);
    2644             :     }
    2645           0 :     cap_p->media = SDP_MEDIA_UNSUPPORTED;
    2646           0 :     for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
    2647           0 :         if (cpr_strncasecmp(tmp, sdp_media[i].name, sdp_media[i].strlen) == 0) {
    2648           0 :             cap_p->media = (sdp_media_e)i;
    2649           0 :             break;
    2650             :         }
    2651             :     }
    2652           0 :     if (cap_p->media == SDP_MEDIA_UNSUPPORTED) {
    2653           0 :         sdp_parse_error(sdp_p,
    2654             :             "%s Warning: Media type unsupported (%s).",
    2655           0 :             sdp_p->debug_str, tmp);
    2656           0 :         SDP_FREE(cap_p);
    2657           0 :         sdp_p->conf_p->num_invalid_param++;
    2658           0 :         return (SDP_INVALID_PARAMETER);
    2659             :     }
    2660             : 
    2661             :     /* Find the transport protocol type. */
    2662           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    2663           0 :     if (result != SDP_SUCCESS) {
    2664           0 :         sdp_parse_error(sdp_p,
    2665             :             "%s No transport protocol type specified, "
    2666           0 :             "unable to parse.", sdp_p->debug_str);
    2667           0 :         SDP_FREE(cap_p);
    2668           0 :         sdp_p->conf_p->num_invalid_param++;
    2669           0 :         return (SDP_INVALID_PARAMETER);
    2670             :     }
    2671           0 :     cap_p->transport = SDP_TRANSPORT_UNSUPPORTED;
    2672           0 :     for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
    2673           0 :         if (cpr_strncasecmp(tmp, sdp_transport[i].name,
    2674           0 :                         sdp_transport[i].strlen) == 0) {
    2675           0 :             cap_p->transport = (sdp_transport_e)i;
    2676           0 :             break;
    2677             :         }
    2678             :     }
    2679           0 :     if (cap_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
    2680           0 :         sdp_parse_error(sdp_p,
    2681             :             "%s Warning: Transport protocol type unsupported (%s).",
    2682           0 :             sdp_p->debug_str, tmp);
    2683           0 :         SDP_FREE(cap_p);
    2684           0 :         sdp_p->conf_p->num_invalid_param++;
    2685           0 :         return (SDP_INVALID_PARAMETER);
    2686             :     }
    2687             : 
    2688             :     /* Find payload formats. AAL2 X-cap lines allow multiple
    2689             :      * transport/profile types per line, so these are handled differently.
    2690             :      */
    2691           0 :     if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
    2692           0 :         (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
    2693           0 :         (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
    2694             :         /* Capability processing is not currently defined for AAL2 types
    2695             :          * with multiple profiles. We don't process. */
    2696           0 :         sdp_parse_error(sdp_p,
    2697             :             "%s Warning: AAL2 profiles unsupported with "
    2698           0 :             "%s attributes.", sdp_p->debug_str,
    2699             :             sdp_get_attr_name(attr_p->type));
    2700           0 :         SDP_FREE(cap_p);
    2701           0 :         sdp_p->conf_p->num_invalid_param++;
    2702           0 :         return (SDP_INVALID_PARAMETER);
    2703             :     } else {
    2704             :         /* Transport is a non-AAL2 type.  Parse payloads normally. */
    2705           0 :         sdp_parse_payload_types(sdp_p, cap_p, ptr);
    2706           0 :         if (cap_p->num_payloads == 0) {
    2707           0 :             SDP_FREE(cap_p);
    2708           0 :             sdp_p->conf_p->num_invalid_param++;
    2709           0 :             return (SDP_INVALID_PARAMETER);
    2710             :         }
    2711             :     }
    2712             : 
    2713           0 :     attr_p->attr.cap_p = cap_p;
    2714             :     /*
    2715             :      * This capability attr is valid.  We can now handle X-cpar or
    2716             :      * cpar attrs.
    2717             :      */
    2718           0 :     sdp_p->cap_valid = TRUE;
    2719           0 :     sdp_p->last_cap_inst++;
    2720             : 
    2721           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2722           0 :         SDP_PRINT("%s Parsed %s media type %s, Transport %s, "
    2723             :                   "Num payloads %u", sdp_p->debug_str,
    2724             :                   sdp_get_attr_name(attr_p->type),
    2725             :                   sdp_get_media_name(cap_p->media),
    2726             :                   sdp_get_transport_name(cap_p->transport),
    2727             :                   cap_p->num_payloads);
    2728             :     }
    2729           0 :     return (SDP_SUCCESS);
    2730             : }
    2731             : 
    2732           0 : sdp_result_e sdp_build_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2733             :                                  flex_string *fs)
    2734             : {
    2735             :     uint16_t                   i, j;
    2736             :     sdp_mca_t            *cap_p;
    2737             :     sdp_media_profiles_t *profile_p;
    2738             : 
    2739             :     /* Get a pointer to the capability structure. */
    2740           0 :     cap_p = attr_p->attr.cap_p;
    2741             : 
    2742           0 :     if (cap_p == NULL) {
    2743           0 :         CSFLogError(logTag, "%s Invalid %s attribute, unable to build.",
    2744             :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    2745           0 :         sdp_p->conf_p->num_invalid_param++;
    2746             :         /* Return success so build won't fail. */
    2747           0 :         return (SDP_SUCCESS);
    2748             :     }
    2749             : 
    2750             :     /* Validate params for this capability line */
    2751           0 :     if ((cap_p->media >= SDP_MAX_MEDIA_TYPES) ||
    2752           0 :         (cap_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
    2753           0 :         CSFLogDebug(logTag, logTag, "%s Media or transport type invalid for %s "
    2754             :             "attribute, unable to build.", sdp_p->debug_str,
    2755             :                         sdp_get_attr_name(attr_p->type));
    2756           0 :         sdp_p->conf_p->num_invalid_param++;
    2757             :         /* Return success so build won't fail. */
    2758           0 :         return (SDP_SUCCESS);
    2759             :     }
    2760             : 
    2761           0 :     flex_string_sprintf(fs, "a=%s: %u %s ", sdp_attr[attr_p->type].name,
    2762           0 :                      sdp_p->cur_cap_num, sdp_get_media_name(cap_p->media));
    2763             : 
    2764             :     /* If the X-cap line has AAL2 profiles, build them differently. */
    2765           0 :     if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
    2766           0 :         (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
    2767           0 :         (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
    2768           0 :         profile_p = cap_p->media_profiles_p;
    2769           0 :         for (i=0; i < profile_p->num_profiles; i++) {
    2770           0 :             flex_string_sprintf(fs, "%s",
    2771             :                              sdp_get_transport_name(profile_p->profile[i]));
    2772             : 
    2773           0 :             for (j=0; j < profile_p->num_payloads[i]; j++) {
    2774           0 :                 flex_string_sprintf(fs, " %u",
    2775           0 :                                  profile_p->payload_type[i][j]);
    2776             :             }
    2777           0 :             flex_string_append(fs, " ");
    2778             :         }
    2779             : 
    2780           0 :         flex_string_append(fs, "\r\n");
    2781           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2782           0 :             SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
    2783             :         }
    2784           0 :         return SDP_SUCCESS;
    2785             :     }
    2786             : 
    2787             :     /* Build the transport name */
    2788           0 :     flex_string_sprintf(fs, "%s", sdp_get_transport_name(cap_p->transport));
    2789             : 
    2790             :     /* Build the format lists */
    2791           0 :     for (i=0; i < cap_p->num_payloads; i++) {
    2792           0 :         if (cap_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
    2793           0 :             flex_string_sprintf(fs, " %s",
    2794           0 :                              sdp_get_payload_name((sdp_payload_e)cap_p->payload_type[i]));
    2795             :         } else {
    2796           0 :             flex_string_sprintf(fs, " %u", cap_p->payload_type[i]);
    2797             :         }
    2798             :     }
    2799             : 
    2800           0 :     flex_string_append(fs, "\r\n");
    2801             : 
    2802             :     /* Increment the current capability number for the next X-cap/cdsc attr. */
    2803           0 :     sdp_p->cur_cap_num += cap_p->num_payloads;
    2804           0 :     sdp_p->last_cap_type = attr_p->type;
    2805             : 
    2806             :     /* Build any X-cpar/cpar attributes associated with this X-cap/cdsc line. */
    2807           0 :     return sdp_build_attr_cpar(sdp_p, cap_p->media_attrs_p, fs);
    2808             : }
    2809             : 
    2810             : 
    2811           0 : sdp_result_e sdp_parse_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2812             :                                   const char *ptr)
    2813             : {
    2814             :     uint16_t           i;
    2815             :     sdp_result_e  result;
    2816             :     sdp_mca_t    *cap_p;
    2817           0 :     sdp_attr_t   *cap_attr_p = NULL;
    2818             :     sdp_attr_t   *prev_attr_p;
    2819             :     char          tmp[SDP_MAX_STRING_LEN];
    2820             : 
    2821             :     /* Make sure we've processed a valid X-cap/cdsc attr prior to this and
    2822             :      * if so, get the cap pointer. */
    2823           0 :     if (sdp_p->cap_valid == TRUE) {
    2824             :         sdp_attr_e cap_type;
    2825             : 
    2826           0 :         if (attr_p->type == SDP_ATTR_CPAR) {
    2827           0 :             cap_type = SDP_ATTR_CDSC;
    2828             :         } else {
    2829             :             /* Default to X-CAP for everything else */
    2830           0 :             cap_type = SDP_ATTR_X_CAP;
    2831             :         }
    2832             : 
    2833           0 :         if (sdp_p->mca_count == 0) {
    2834           0 :             cap_attr_p = sdp_find_attr(sdp_p, SDP_SESSION_LEVEL, 0,
    2835           0 :                                        cap_type, sdp_p->last_cap_inst);
    2836             :         } else {
    2837           0 :             cap_attr_p = sdp_find_attr(sdp_p, sdp_p->mca_count, 0,
    2838           0 :                                        cap_type, sdp_p->last_cap_inst);
    2839             :         }
    2840             :     }
    2841           0 :     if ((cap_attr_p == NULL) || (cap_attr_p->attr.cap_p == NULL)) {
    2842           0 :         sdp_parse_error(sdp_p,
    2843             :             "%s Warning: %s attribute specified with no "
    2844           0 :             "prior %s attribute", sdp_p->debug_str,
    2845             :                          sdp_get_attr_name(attr_p->type),
    2846           0 :                          (attr_p->type == SDP_ATTR_CPAR)?
    2847             :                                (sdp_get_attr_name(SDP_ATTR_CDSC)) :
    2848             :                                (sdp_get_attr_name(SDP_ATTR_X_CAP)) );
    2849           0 :         sdp_p->conf_p->num_invalid_param++;
    2850           0 :         return (SDP_INVALID_PARAMETER);
    2851             :     }
    2852             : 
    2853             :     /*
    2854             :      * Ensure there is no mixed syntax like CDSC followed by X-CPAR
    2855             :      * or X-CAP followed by CPAR.
    2856             :      */
    2857           0 :     if (((cap_attr_p->type == SDP_ATTR_CDSC) &&
    2858           0 :         (attr_p->type == SDP_ATTR_X_CPAR)) ||
    2859           0 :         ( (cap_attr_p->type == SDP_ATTR_X_CAP) &&
    2860           0 :           (attr_p->type == SDP_ATTR_CPAR)) ) {
    2861           0 :         sdp_parse_error(sdp_p,
    2862             :             "%s Warning: %s attribute inconsistent with "
    2863           0 :             "prior %s attribute", sdp_p->debug_str,
    2864             :             sdp_get_attr_name(attr_p->type),
    2865             :             sdp_get_attr_name(cap_attr_p->type));
    2866           0 :         sdp_p->conf_p->num_invalid_param++;
    2867           0 :         return (SDP_INVALID_PARAMETER);
    2868             :     }
    2869           0 :     cap_p = cap_attr_p->attr.cap_p;
    2870             : 
    2871             :     /* a= is the only token we handle in an X-cpar/cpar attribute. */
    2872           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "= \t", &result);
    2873             : 
    2874           0 :     if ((result != SDP_SUCCESS) || (tmp[0] != 'a') || (tmp[1] != '\0')) {
    2875           0 :         sdp_parse_error(sdp_p,
    2876             :             "%s Warning: Invalid token type (%s) in %s "
    2877           0 :             "attribute, unable to parse", sdp_p->debug_str, tmp,
    2878             :             sdp_get_attr_name(attr_p->type));
    2879           0 :         sdp_p->conf_p->num_invalid_param++;
    2880           0 :         return (SDP_INVALID_PARAMETER);
    2881             :     }
    2882             :     /*sa_ignore NO_NULL_CHK
    2883             :      *{ptr is valid since the pointer was checked earlier and the
    2884             :      * function would have exited if NULL.}
    2885             :      */
    2886           0 :     if (*ptr == '=') {
    2887           0 :         ptr++;
    2888             :     }
    2889             : 
    2890             :     /* Find the attribute type. */
    2891           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
    2892             :     /*sa_ignore NO_NULL_CHK
    2893             :      *{ptr is valid since the pointer was checked earlier and the
    2894             :      * function would have exited if NULL.}
    2895             :      */
    2896           0 :     if (ptr[0] == ':') {
    2897             :         /* Skip the ':' char for parsing attribute parameters. */
    2898           0 :         ptr++;
    2899             :     }
    2900           0 :     if (result != SDP_SUCCESS) {
    2901           0 :         sdp_parse_error(sdp_p,
    2902             :             "%s No attribute type specified for %s attribute, unable to parse.",
    2903           0 :             sdp_p->debug_str,
    2904             :             sdp_get_attr_name(attr_p->type));
    2905           0 :         sdp_p->conf_p->num_invalid_param++;
    2906           0 :         return (SDP_INVALID_PARAMETER);
    2907             :     }
    2908             : 
    2909             :     /* Reset the type of the attribute from X-cpar/cpar to whatever the
    2910             :      * specified type is. */
    2911           0 :     attr_p->type = SDP_ATTR_INVALID;
    2912           0 :     attr_p->next_p = NULL;
    2913           0 :     for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
    2914           0 :         if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
    2915           0 :             attr_p->type = (sdp_attr_e)i;
    2916             :         }
    2917             :     }
    2918           0 :     if (attr_p->type == SDP_ATTR_INVALID) {
    2919           0 :         sdp_parse_error(sdp_p,
    2920             :             "%s Warning: Unrecognized attribute (%s) for %s attribute, unable to parse.",
    2921           0 :             sdp_p->debug_str, tmp,
    2922             :             sdp_get_attr_name(attr_p->type));
    2923           0 :         sdp_p->conf_p->num_invalid_param++;
    2924           0 :         return (SDP_INVALID_PARAMETER);
    2925             :     }
    2926             : 
    2927             :     /* We don't allow recursion with the capability attributes. */
    2928           0 :     if ((attr_p->type == SDP_ATTR_X_SQN) ||
    2929           0 :         (attr_p->type == SDP_ATTR_X_CAP) ||
    2930           0 :         (attr_p->type == SDP_ATTR_X_CPAR) ||
    2931           0 :         (attr_p->type == SDP_ATTR_SQN) ||
    2932           0 :         (attr_p->type == SDP_ATTR_CDSC) ||
    2933           0 :         (attr_p->type == SDP_ATTR_CPAR)) {
    2934           0 :         sdp_parse_error(sdp_p,
    2935             :             "%s Warning: Invalid attribute (%s) for %s"
    2936           0 :             " attribute, unable to parse.", sdp_p->debug_str, tmp,
    2937             :             sdp_get_attr_name(attr_p->type));
    2938           0 :         sdp_p->conf_p->num_invalid_param++;
    2939           0 :         return (SDP_INVALID_PARAMETER);
    2940             :     }
    2941             : 
    2942             :     /* Parse the attribute. */
    2943           0 :     result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
    2944           0 :     if (result != SDP_SUCCESS) {
    2945           0 :         return (result);
    2946             :     }
    2947             : 
    2948             :     /* Hook the attribute into the capability structure. */
    2949           0 :     if (cap_p->media_attrs_p == NULL) {
    2950           0 :         cap_p->media_attrs_p = attr_p;
    2951             :     } else {
    2952           0 :         for (prev_attr_p = cap_p->media_attrs_p;
    2953           0 :              prev_attr_p->next_p != NULL;
    2954           0 :              prev_attr_p = prev_attr_p->next_p) {
    2955             :             ; /* Empty for */
    2956             :         }
    2957           0 :         prev_attr_p->next_p = attr_p;
    2958             :     }
    2959             : 
    2960           0 :     return (SDP_SUCCESS);
    2961             : }
    2962             : 
    2963           0 : sdp_result_e sdp_build_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
    2964             :                                   flex_string *fs)
    2965             : {
    2966             :     sdp_result_e  result;
    2967             :     const char   *cpar_name;
    2968             : 
    2969             :     /* Determine whether to use cpar or X-cpar */
    2970           0 :     if (sdp_p->last_cap_type == SDP_ATTR_CDSC) {
    2971           0 :         cpar_name = sdp_get_attr_name(SDP_ATTR_CPAR);
    2972             :     } else {
    2973             :         /*
    2974             :          * Default to X-CPAR if anything else. This is the backward
    2975             :          * compatible value.
    2976             :          */
    2977           0 :         cpar_name = sdp_get_attr_name(SDP_ATTR_X_CPAR);
    2978             :     }
    2979             : 
    2980           0 :     while (attr_p != NULL) {
    2981           0 :         if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
    2982           0 :             CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
    2983             :                 sdp_p->debug_str, (unsigned)attr_p->type);
    2984             :         } else {
    2985           0 :             flex_string_sprintf(fs, "a=%s: ", cpar_name);
    2986             : 
    2987           0 :             result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
    2988             : 
    2989           0 :             if (result == SDP_SUCCESS) {
    2990           0 :                 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    2991           0 :                     SDP_PRINT("%s Built %s a=%s attribute line",
    2992             :                               sdp_p->debug_str, cpar_name,
    2993             :                               sdp_get_attr_name(attr_p->type));
    2994             :                 }
    2995             :             }
    2996             :         }
    2997           0 :         attr_p = attr_p->next_p;
    2998             :     }
    2999             : 
    3000           0 :     return (SDP_SUCCESS);
    3001             : }
    3002             : 
    3003           0 : sdp_result_e sdp_parse_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3004             :                                            const char *ptr)
    3005             : {
    3006             :   sdp_result_e result;
    3007             :   char nettype[SDP_MAX_STRING_LEN];
    3008           0 :   sdp_rtcp_t *rtcp_p = &(attr_p->attr.rtcp);
    3009             :   int enum_raw;
    3010             : 
    3011           0 :   memset(rtcp_p, 0, sizeof(sdp_rtcp_t));
    3012             : 
    3013           0 :   rtcp_p->port = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
    3014           0 :   if (result != SDP_SUCCESS) {
    3015           0 :     sdp_parse_error(sdp_p,
    3016             :                     "%s Warning: could not parse port for rtcp attribute",
    3017           0 :                     sdp_p->debug_str);
    3018           0 :     sdp_p->conf_p->num_invalid_param++;
    3019             : 
    3020           0 :     return SDP_INVALID_PARAMETER;
    3021             :   }
    3022             : 
    3023             :   /* The rest is optional, although it is all-or-nothing */
    3024           0 :   (void)sdp_getnextstrtok(ptr, nettype, sizeof(nettype), " \t", &result);
    3025           0 :   if (result == SDP_EMPTY_TOKEN) {
    3026             :     /* Nothing after the port */
    3027           0 :     return SDP_SUCCESS;
    3028             :   }
    3029             : 
    3030           0 :   enum_raw = find_token_enum("Nettype", sdp_p, &ptr, sdp_nettype,
    3031             :                              SDP_MAX_NETWORK_TYPES, SDP_NT_UNSUPPORTED);
    3032           0 :   if (enum_raw == -1) {
    3033           0 :     return SDP_INVALID_PARAMETER;
    3034             :   }
    3035           0 :   rtcp_p->nettype = (sdp_nettype_e)enum_raw;
    3036             : 
    3037           0 :   enum_raw = find_token_enum("Addrtype", sdp_p, &ptr, sdp_addrtype,
    3038             :                              SDP_MAX_ADDR_TYPES, SDP_AT_UNSUPPORTED);
    3039           0 :   if (enum_raw == -1) {
    3040           0 :     return SDP_INVALID_PARAMETER;
    3041             :   }
    3042           0 :   rtcp_p->addrtype = (sdp_addrtype_e)enum_raw;
    3043             : 
    3044           0 :   ptr = sdp_getnextstrtok(ptr, rtcp_p->addr, sizeof(rtcp_p->addr), " \t",
    3045             :                           &result);
    3046           0 :   if (result != SDP_SUCCESS) {
    3047           0 :     sdp_parse_error(sdp_p,
    3048             :                     "%s Warning: could not parse addr for rtcp attribute",
    3049           0 :                     sdp_p->debug_str);
    3050           0 :     sdp_p->conf_p->num_invalid_param++;
    3051             : 
    3052           0 :     return SDP_INVALID_PARAMETER;
    3053             :   }
    3054             : 
    3055           0 :   return SDP_SUCCESS;
    3056             : }
    3057             : 
    3058           0 : sdp_result_e sdp_build_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3059             :                                            flex_string *fs)
    3060             : {
    3061             :   /* We should not be serializing SDP anyway, but we need this function until
    3062             :    * Bug 1112737 is resolved. */
    3063           0 :   return SDP_FAILURE;
    3064             : }
    3065             : 
    3066           0 : sdp_result_e sdp_parse_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3067             :                                            const char *ptr)
    3068             : {
    3069             :     sdp_result_e  result;
    3070             :     char tmp[SDP_MAX_STRING_LEN];
    3071             : 
    3072           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3073           0 :         SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
    3074             :                   sdp_get_attr_name(attr_p->type));
    3075             :     }
    3076             :     /*Default confirm to FALSE. */
    3077           0 :     attr_p->attr.rtr.confirm = FALSE;
    3078             : 
    3079           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3080           0 :     if (result != SDP_SUCCESS){ // No confirm tag specified is not an error
    3081           0 :         return (SDP_SUCCESS);
    3082             :     } else {
    3083             :        /* See if confirm was specified.  Defaults to FALSE. */
    3084           0 :        if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
    3085           0 :            attr_p->attr.rtr.confirm = TRUE;
    3086             :        }
    3087           0 :        if (attr_p->attr.rtr.confirm == FALSE) {
    3088           0 :           sdp_parse_error(sdp_p,
    3089             :               "%s Warning: RTR confirm parameter invalid (%s)",
    3090           0 :               sdp_p->debug_str, tmp);
    3091           0 :            sdp_p->conf_p->num_invalid_param++;
    3092           0 :            return (SDP_INVALID_PARAMETER);
    3093             :        }
    3094           0 :        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3095           0 :            SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
    3096             :                      sdp_get_attr_name(attr_p->type),
    3097             :                      tmp);
    3098             :        }
    3099           0 :        return (SDP_SUCCESS);
    3100             :     }
    3101             : }
    3102             : 
    3103           0 : sdp_result_e sdp_build_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3104             :                                            flex_string *fs)
    3105             : {
    3106           0 :   flex_string_sprintf(fs, "a=%s%s\r\n",
    3107           0 :     sdp_attr[attr_p->type].name,
    3108           0 :     attr_p->attr.rtr.confirm ? ":confirm" : "");
    3109             : 
    3110           0 :   return SDP_SUCCESS;
    3111             : }
    3112             : 
    3113           0 : sdp_result_e sdp_parse_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3114             :                                         const char *ptr)
    3115             : {
    3116             :     int i;
    3117             :     sdp_result_e  result;
    3118           0 :     tinybool      type_found = FALSE;
    3119             :     char          tmp[SDP_MAX_STRING_LEN];
    3120             : 
    3121           0 :     attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_PASSIVE;
    3122           0 :     attr_p->attr.comediadir.conn_info_present = FALSE;
    3123           0 :     attr_p->attr.comediadir.conn_info.nettype = SDP_NT_INVALID;
    3124           0 :     attr_p->attr.comediadir.src_port = 0;
    3125             : 
    3126             :     /* Find the media direction role. */
    3127           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
    3128             : 
    3129           0 :     if (result != SDP_SUCCESS) {
    3130           0 :         sdp_parse_error(sdp_p,
    3131             :             "%s Warning: No role parameter specified for "
    3132           0 :             "comediadir attribute.", sdp_p->debug_str);
    3133           0 :         sdp_p->conf_p->num_invalid_param++;
    3134           0 :         return (SDP_INVALID_PARAMETER);
    3135             :     }
    3136           0 :     attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_UNSUPPORTED;
    3137           0 :     for (i=0; i < SDP_MAX_MEDIADIR_ROLES; i++) {
    3138           0 :         if (cpr_strncasecmp(tmp, sdp_mediadir_role[i].name,
    3139           0 :                         sdp_mediadir_role[i].strlen) == 0) {
    3140           0 :             type_found = TRUE;
    3141           0 :             attr_p->attr.comediadir.role = (sdp_mediadir_role_e)i;
    3142           0 :             break;
    3143             :         }
    3144             :     }
    3145           0 :     if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_UNSUPPORTED) {
    3146           0 :         sdp_parse_error(sdp_p,
    3147             :             "%s Warning: Invalid role type specified for "
    3148           0 :             "comediadir attribute (%s).", sdp_p->debug_str, tmp);
    3149           0 :         sdp_p->conf_p->num_invalid_param++;
    3150           0 :         return (SDP_INVALID_PARAMETER);
    3151             :     }
    3152             : 
    3153             :     /* If the role is passive, we don't expect any more params. */
    3154           0 :     if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_PASSIVE) {
    3155           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3156           0 :             SDP_PRINT("%s Parsed a=%s, passive",
    3157             :                       sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    3158             :         }
    3159           0 :         return (SDP_SUCCESS);
    3160             :     }
    3161             : 
    3162             :     /* Find the connection information if present */
    3163             :     /* parse to get the nettype */
    3164           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3165           0 :     if (result != SDP_SUCCESS) {
    3166           0 :         sdp_parse_error(sdp_p,
    3167             :             "%s Warning: No network type specified in comediadir "
    3168           0 :             "attribute.", sdp_p->debug_str);
    3169           0 :         sdp_p->conf_p->num_invalid_param++;
    3170           0 :         return (SDP_SUCCESS); /* as the optional parameters are not there */
    3171             :     }
    3172           0 :     attr_p->attr.comediadir.conn_info.nettype = SDP_NT_UNSUPPORTED;
    3173           0 :     for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
    3174           0 :         if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
    3175           0 :                         sdp_nettype[i].strlen) == 0) {
    3176           0 :             type_found = TRUE;
    3177             :         }
    3178           0 :         if (type_found == TRUE) {
    3179           0 :             if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
    3180           0 :                 attr_p->attr.comediadir.conn_info.nettype = (sdp_nettype_e)i;
    3181             :             }
    3182           0 :             type_found = FALSE;
    3183             :         }
    3184             :     }
    3185           0 :     if (attr_p->attr.comediadir.conn_info.nettype == SDP_NT_UNSUPPORTED) {
    3186           0 :         sdp_parse_error(sdp_p,
    3187             :             "%s Warning: ConnInfo in Comediadir: network type "
    3188           0 :             "unsupported (%s).", sdp_p->debug_str, tmp);
    3189           0 :         sdp_p->conf_p->num_invalid_param++;
    3190             :     }
    3191             : 
    3192             :     /* Find the comedia address type. */
    3193           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3194           0 :     if (result != SDP_SUCCESS) {
    3195           0 :         sdp_parse_error(sdp_p,
    3196             :             "%s Warning: No address type specified in comediadir"
    3197           0 :             " attribute.", sdp_p->debug_str);
    3198           0 :         sdp_p->conf_p->num_invalid_param++;
    3199             :     }
    3200           0 :     attr_p->attr.comediadir.conn_info.addrtype = SDP_AT_UNSUPPORTED;
    3201           0 :     for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
    3202           0 :         if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
    3203           0 :                         sdp_addrtype[i].strlen) == 0) {
    3204           0 :             type_found = TRUE;
    3205             :         }
    3206           0 :         if (type_found == TRUE) {
    3207           0 :             if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
    3208           0 :                 attr_p->attr.comediadir.conn_info.addrtype = (sdp_addrtype_e)i;
    3209             :             }
    3210           0 :             type_found = FALSE;
    3211             :         }
    3212             :     }
    3213           0 :     if (attr_p->attr.comediadir.conn_info.addrtype == SDP_AT_UNSUPPORTED) {
    3214           0 :         sdp_parse_error(sdp_p,
    3215             :             "%s Warning: Conninfo address type unsupported "
    3216           0 :             "(%s).", sdp_p->debug_str, tmp);
    3217           0 :         sdp_p->conf_p->num_invalid_param++;
    3218             :     }
    3219             : 
    3220             :     /* Find the conninfo address.  */
    3221           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.comediadir.conn_info.conn_addr,
    3222             :                             sizeof(attr_p->attr.comediadir.conn_info.conn_addr), " \t", &result);
    3223           0 :     if (result != SDP_SUCCESS) {
    3224           0 :         sdp_parse_error(sdp_p,
    3225             :             "%s Warning: No conninfo address specified in "
    3226           0 :             "comediadir attribute.", sdp_p->debug_str);
    3227           0 :         sdp_p->conf_p->num_invalid_param++;
    3228             :     }
    3229             : 
    3230             :     /* Find the src port info , if any */
    3231           0 :     attr_p->attr.comediadir.src_port  = sdp_getnextnumtok(ptr, &ptr, " \t",
    3232             :                                                           &result);
    3233           0 :     if (result != SDP_SUCCESS) {
    3234           0 :         sdp_parse_error(sdp_p,
    3235             :             "%s Warning: No src port specified in "
    3236           0 :             "comediadir attribute.", sdp_p->debug_str);
    3237           0 :         sdp_p->conf_p->num_invalid_param++;
    3238             :     }
    3239             : 
    3240           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3241           0 :         SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s "
    3242             :                   "srcport %u ",
    3243             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    3244             :                   sdp_get_network_name(attr_p->attr.comediadir.conn_info.nettype),
    3245             :                   sdp_get_address_name(attr_p->attr.comediadir.conn_info.addrtype),
    3246             :                   attr_p->attr.comediadir.conn_info.conn_addr,
    3247             :                   (unsigned int)attr_p->attr.comediadir.src_port);
    3248             :     }
    3249             : 
    3250           0 :     if (sdp_p->conf_p->num_invalid_param > 0) {
    3251           0 :         return (SDP_INVALID_PARAMETER);
    3252             :     }
    3253           0 :     return (SDP_SUCCESS);
    3254             : }
    3255             : 
    3256             : sdp_result_e
    3257           0 : sdp_build_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3258             :                                     flex_string *fs)
    3259             : {
    3260           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    3261           0 :     sdp_attr[attr_p->type].name,
    3262             :     sdp_get_mediadir_role_name(attr_p->attr.comediadir.role));
    3263             : 
    3264           0 :   return SDP_SUCCESS;
    3265             : }
    3266             : 
    3267           0 : sdp_result_e sdp_parse_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3268             :                                          const char *ptr)
    3269             : {
    3270             :     int i;
    3271             :     sdp_result_e result;
    3272             :     char tmp[SDP_MAX_STRING_LEN];
    3273             : 
    3274             :     /* Find silenceSuppEnable */
    3275           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3276             : 
    3277           0 :     if (result != SDP_SUCCESS) {
    3278           0 :         sdp_parse_error(sdp_p,
    3279             :             "%s No silenceSupp enable value specified, parse failed.",
    3280           0 :             sdp_p->debug_str);
    3281           0 :         sdp_p->conf_p->num_invalid_param++;
    3282           0 :         return (SDP_INVALID_PARAMETER);
    3283             :     }
    3284             : 
    3285           0 :     if (cpr_strncasecmp(tmp, "on", sizeof("on")) == 0) {
    3286           0 :         attr_p->attr.silencesupp.enabled = TRUE;
    3287           0 :     } else if (cpr_strncasecmp(tmp, "off", sizeof("off")) == 0) {
    3288           0 :         attr_p->attr.silencesupp.enabled = FALSE;
    3289           0 :     } else if (cpr_strncasecmp(tmp, "-", sizeof("-")) == 0) {
    3290           0 :         attr_p->attr.silencesupp.enabled = FALSE;
    3291             :     } else {
    3292           0 :         sdp_parse_error(sdp_p,
    3293             :             "%s Warning: silenceSuppEnable parameter invalid (%s)",
    3294           0 :             sdp_p->debug_str, tmp);
    3295           0 :         sdp_p->conf_p->num_invalid_param++;
    3296           0 :         return (SDP_INVALID_PARAMETER);
    3297             :     }
    3298             : 
    3299             :     /* Find silenceTimer -- uint16_t or "-" */
    3300             : 
    3301           0 :     attr_p->attr.silencesupp.timer =
    3302           0 :         (uint16_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
    3303             :                                        &attr_p->attr.silencesupp.timer_null,
    3304             :                                        &result);
    3305           0 :     if (result != SDP_SUCCESS) {
    3306           0 :         sdp_parse_error(sdp_p,
    3307             :             "%s Warning: Invalid timer value specified for "
    3308           0 :             "silenceSupp attribute.", sdp_p->debug_str);
    3309           0 :         sdp_p->conf_p->num_invalid_param++;
    3310           0 :         return (SDP_INVALID_PARAMETER);
    3311             :     }
    3312             : 
    3313             :     /* Find suppPref */
    3314           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3315           0 :     if (result != SDP_SUCCESS) {
    3316           0 :         sdp_parse_error(sdp_p,
    3317             :             "%s Warning: No silenceSupp pref specified.",
    3318           0 :             sdp_p->debug_str);
    3319           0 :         sdp_p->conf_p->num_invalid_param++;
    3320           0 :         return (SDP_INVALID_PARAMETER);
    3321             :     }
    3322           0 :     attr_p->attr.silencesupp.pref = SDP_SILENCESUPP_PREF_UNKNOWN;
    3323           0 :     for (i=0; i < SDP_MAX_SILENCESUPP_PREF; i++) {
    3324           0 :         if (cpr_strncasecmp(tmp, sdp_silencesupp_pref[i].name,
    3325           0 :                         sdp_silencesupp_pref[i].strlen) == 0) {
    3326           0 :             attr_p->attr.silencesupp.pref = (sdp_silencesupp_pref_e)i;
    3327             :         }
    3328             :     }
    3329           0 :     if (attr_p->attr.silencesupp.pref == SDP_SILENCESUPP_PREF_UNKNOWN) {
    3330           0 :         sdp_parse_error(sdp_p,
    3331             :             "%s Warning: silenceSupp pref unrecognized (%s)",
    3332           0 :             sdp_p->debug_str, tmp);
    3333           0 :         sdp_p->conf_p->num_invalid_param++;
    3334           0 :         return (SDP_INVALID_PARAMETER);
    3335             :     }
    3336             : 
    3337             :     /* Find sidUse */
    3338           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3339           0 :     if (result != SDP_SUCCESS) {
    3340           0 :         sdp_parse_error(sdp_p,
    3341             :             "%s Warning: No silenceSupp sidUse specified.",
    3342           0 :             sdp_p->debug_str);
    3343           0 :         sdp_p->conf_p->num_invalid_param++;
    3344           0 :         return (SDP_INVALID_PARAMETER);
    3345             :     }
    3346           0 :     attr_p->attr.silencesupp.siduse = SDP_SILENCESUPP_SIDUSE_UNKNOWN;
    3347           0 :     for (i=0; i < SDP_MAX_SILENCESUPP_SIDUSE; i++) {
    3348           0 :         if (cpr_strncasecmp(tmp, sdp_silencesupp_siduse[i].name,
    3349           0 :                         sdp_silencesupp_siduse[i].strlen) == 0) {
    3350           0 :             attr_p->attr.silencesupp.siduse = (sdp_silencesupp_siduse_e)i;
    3351             :         }
    3352             :     }
    3353           0 :     if (attr_p->attr.silencesupp.siduse == SDP_SILENCESUPP_SIDUSE_UNKNOWN) {
    3354           0 :         sdp_parse_error(sdp_p,
    3355             :             "%s Warning: silenceSupp sidUse unrecognized (%s)",
    3356           0 :             sdp_p->debug_str, tmp);
    3357           0 :         sdp_p->conf_p->num_invalid_param++;
    3358           0 :         return (SDP_INVALID_PARAMETER);
    3359             :     }
    3360             : 
    3361             :     /* Find fxnslevel -- uint8_t or "-" */
    3362           0 :     attr_p->attr.silencesupp.fxnslevel =
    3363           0 :         (uint8_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
    3364             :                                       &attr_p->attr.silencesupp.fxnslevel_null,
    3365             :                                       &result);
    3366             : 
    3367           0 :     if (result != SDP_SUCCESS) {
    3368           0 :         sdp_parse_error(sdp_p,
    3369             :             "%s Warning: Invalid fxnslevel value specified for "
    3370           0 :             "silenceSupp attribute.", sdp_p->debug_str);
    3371           0 :         sdp_p->conf_p->num_invalid_param++;
    3372           0 :         return (SDP_INVALID_PARAMETER);
    3373             :     }
    3374             : 
    3375           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3376           0 :         SDP_PRINT("%s Parsed a=%s, enabled %s",
    3377             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    3378             :                   (attr_p->attr.silencesupp.enabled ? "on" : "off"));
    3379           0 :         if (attr_p->attr.silencesupp.timer_null) {
    3380           0 :             SDP_PRINT(" timer=-");
    3381             :         } else {
    3382           0 :             SDP_PRINT(" timer=%u,", attr_p->attr.silencesupp.timer);
    3383             :         }
    3384           0 :         SDP_PRINT(" pref=%s, siduse=%s,",
    3385             :                   sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
    3386             :                   sdp_get_silencesupp_siduse_name(
    3387             :                                              attr_p->attr.silencesupp.siduse));
    3388           0 :         if (attr_p->attr.silencesupp.fxnslevel_null) {
    3389           0 :             SDP_PRINT(" fxnslevel=-");
    3390             :         } else {
    3391           0 :             SDP_PRINT(" fxnslevel=%u,", attr_p->attr.silencesupp.fxnslevel);
    3392             :         }
    3393             :     }
    3394             : 
    3395           0 :     return (SDP_SUCCESS);
    3396             : }
    3397             : 
    3398           0 : sdp_result_e sdp_build_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3399             :                                          flex_string *fs)
    3400             : {
    3401             :   char temp_timer_string[11];
    3402             :   char temp_fxnslevel_string[11];
    3403             : 
    3404           0 :   if (attr_p->attr.silencesupp.timer_null) {
    3405           0 :     snprintf(temp_timer_string, sizeof(temp_timer_string), "-");
    3406             :   } else {
    3407           0 :     snprintf(temp_timer_string, sizeof(temp_timer_string), "%u", attr_p->attr.silencesupp.timer);
    3408             :   }
    3409             : 
    3410           0 :   if (attr_p->attr.silencesupp.fxnslevel_null) {
    3411           0 :     snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "-");
    3412             :   } else {
    3413           0 :     snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "%u", attr_p->attr.silencesupp.fxnslevel);
    3414             :   }
    3415             : 
    3416           0 :   flex_string_sprintf(fs, "a=%s:%s %s %s %s %s\r\n",
    3417           0 :     sdp_attr[attr_p->type].name,
    3418           0 :     (attr_p->attr.silencesupp.enabled ? "on" : "off"),
    3419             :     temp_timer_string,
    3420             :     sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
    3421             :     sdp_get_silencesupp_siduse_name(attr_p->attr.silencesupp.siduse),
    3422             :     temp_fxnslevel_string);
    3423             : 
    3424           0 :   return SDP_SUCCESS;
    3425             : }
    3426             : 
    3427             : /*
    3428             :  * sdp_parse_context_crypto_suite
    3429             :  *
    3430             :  * This routine parses the crypto suite pointed to by str, stores the crypto suite value into the
    3431             :  * srtp context suite component of the LocalConnectionOptions pointed to by lco_node_ptr and stores
    3432             :  * pointer to the next crypto parameter in tmp_ptr
    3433             :  */
    3434           0 : tinybool sdp_parse_context_crypto_suite(char * str,  sdp_attr_t *attr_p, sdp_t *sdp_p) {
    3435             :       /*
    3436             :        * Three crypto_suites are defined: (Notice no SPACE between "crypto:" and the <crypto-suite>
    3437             :        * AES_CM_128_HMAC_SHA1_80
    3438             :        * AES_CM_128_HMAC_SHA1_32
    3439             :        * F8_128_HMAC_SHA1_80
    3440             :        */
    3441             : 
    3442             :        int i;
    3443             : 
    3444             :        /* Check crypto suites */
    3445           0 :        for(i=0; i<SDP_SRTP_MAX_NUM_CRYPTO_SUITES; i++) {
    3446           0 :          if (!cpr_strcasecmp(sdp_srtp_crypto_suite_array[i].crypto_suite_str, str)) {
    3447           0 :            attr_p->attr.srtp_context.suite = sdp_srtp_crypto_suite_array[i].crypto_suite_val;
    3448           0 :            attr_p->attr.srtp_context.master_key_size_bytes =
    3449           0 :                sdp_srtp_crypto_suite_array[i].key_size_bytes;
    3450           0 :            attr_p->attr.srtp_context.master_salt_size_bytes =
    3451           0 :                sdp_srtp_crypto_suite_array[i].salt_size_bytes;
    3452           0 :            return TRUE; /* There is a succesful match so exit */
    3453             :          }
    3454             :        }
    3455             :        /* couldn't find a matching crypto suite */
    3456           0 :        sdp_parse_error(sdp_p,
    3457             :             "%s No Matching crypto suite for SRTP Context(%s)-'X-crypto:v1' expected",
    3458           0 :             sdp_p->debug_str, str);
    3459             : 
    3460           0 :        return FALSE;
    3461             : }
    3462             : 
    3463             : 
    3464           0 : sdp_result_e sdp_build_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3465             :                                     flex_string *fs)
    3466             : {
    3467             : #define MAX_BASE64_ENCODE_SIZE_BYTES 60
    3468           0 :     int          output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
    3469           0 :     int                  key_size = attr_p->attr.srtp_context.master_key_size_bytes;
    3470           0 :     int                  salt_size = attr_p->attr.srtp_context.master_salt_size_bytes;
    3471             :     unsigned char  base64_encoded_data[MAX_BASE64_ENCODE_SIZE_BYTES];
    3472             :     unsigned char  base64_encoded_input[MAX_BASE64_ENCODE_SIZE_BYTES];
    3473             :     base64_result_t status;
    3474             : 
    3475           0 :     output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
    3476             : 
    3477             :     /* Append master and salt keys */
    3478           0 :     memcpy(base64_encoded_input,
    3479           0 :            attr_p->attr.srtp_context.master_key,
    3480             :            key_size );
    3481           0 :     memcpy(base64_encoded_input + key_size,
    3482           0 :            attr_p->attr.srtp_context.master_salt,
    3483             :            salt_size );
    3484             : 
    3485           0 :     if ((status = base64_encode(base64_encoded_input, key_size + salt_size,
    3486             :                       base64_encoded_data, &output_len)) != BASE64_SUCCESS) {
    3487           0 :         if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
    3488           0 :             CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
    3489             :                      sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
    3490             :         }
    3491           0 :         return (SDP_INVALID_PARAMETER);
    3492             :     }
    3493             : 
    3494           0 :     *(base64_encoded_data + output_len) = '\0';
    3495             : 
    3496           0 :     flex_string_sprintf(fs, "a=%s:%s inline:%s||\r\n",
    3497           0 :       sdp_attr[attr_p->type].name,
    3498           0 :       sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
    3499             :       base64_encoded_data);
    3500             : 
    3501           0 :     return SDP_SUCCESS;
    3502             : }
    3503             : 
    3504             : /*
    3505             :  * sdp_parse_attr_mptime
    3506             :  * This function parses the a=mptime sdp line. This parameter consists of
    3507             :  * one or more numbers or hyphens ("-"). The first parameter must be a
    3508             :  * number. The number of parameters must match the number of formats specified
    3509             :  * on the m= line. This function is liberal in that it does not match against
    3510             :  * the m= line or require a number for the first parameter.
    3511             :  */
    3512           0 : sdp_result_e sdp_parse_attr_mptime (
    3513             :     sdp_t *sdp_p,
    3514             :     sdp_attr_t *attr_p,
    3515             :     const char *ptr)
    3516             : {
    3517             :     uint16_t i;                      /* loop counter for parameters */
    3518             :     sdp_result_e result;        /* value returned by this function */
    3519             :     tinybool null_ind;          /* true if a parameter is "-" */
    3520             : 
    3521             :     /*
    3522             :      * Scan the input line up to the maximum number of parameters supported.
    3523             :      * Look for numbers or hyphens and store the resulting values. Hyphens
    3524             :      * are stored as zeros.
    3525             :      */
    3526           0 :     for (i=0; i<SDP_MAX_PAYLOAD_TYPES; i++) {
    3527           0 :         attr_p->attr.mptime.intervals[i] =
    3528           0 :             (ushort)sdp_getnextnumtok_or_null(ptr,&ptr," \t",&null_ind,&result);
    3529           0 :         if (result != SDP_SUCCESS) {
    3530           0 :             break;
    3531             :         }
    3532           0 :         attr_p->attr.mptime.num_intervals++;
    3533             :     }
    3534             : 
    3535             :     /*
    3536             :      * At least one parameter must be supplied. If not, return an error
    3537             :      * and optionally log the failure.
    3538             :      */
    3539           0 :     if (attr_p->attr.mptime.num_intervals == 0) {
    3540           0 :         sdp_parse_error(sdp_p,
    3541             :             "%s Warning: No intervals specified for %s attr.",
    3542           0 :             sdp_p->debug_str, sdp_attr[attr_p->type].name);
    3543           0 :         sdp_p->conf_p->num_invalid_param++;
    3544           0 :         return (SDP_INVALID_PARAMETER);
    3545             :     }
    3546             : 
    3547             :     /*
    3548             :      * Here is some debugging code that helps us track what data
    3549             :      * is received and parsed.
    3550             :      */
    3551           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3552           0 :         SDP_PRINT("%s Parsed a=%s, num intervals %u, intervals: ",
    3553             :                   sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
    3554             :                   attr_p->attr.mptime.num_intervals);
    3555           0 :         for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
    3556           0 :             SDP_PRINT("%u ", attr_p->attr.mptime.intervals[i]);
    3557             :         }
    3558             :     }
    3559             : 
    3560           0 :     return SDP_SUCCESS;
    3561             : }
    3562             : 
    3563             : /*
    3564             :  * sdp_build_attr_mptime
    3565             :  * This function builds the a=mptime sdp line. It reads the selected attribute
    3566             :  * from the sdp structure. Parameters with a value of zero are replaced by
    3567             :  * hyphens.
    3568             :  */
    3569           0 : sdp_result_e sdp_build_attr_mptime (
    3570             :     sdp_t *sdp_p,
    3571             :     sdp_attr_t *attr_p,
    3572             :     flex_string *fs)
    3573             : {
    3574             :   int i;
    3575             : 
    3576           0 :   flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
    3577             : 
    3578             :   /*
    3579             :    * Run the list of mptime parameter values and write each one
    3580             :    * to the sdp line. Replace zeros with hyphens.
    3581             :    */
    3582           0 :   for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
    3583           0 :     if (i > 0) {
    3584           0 :       flex_string_append(fs, " ");
    3585             :     }
    3586             : 
    3587           0 :     if (attr_p->attr.mptime.intervals[i] == 0) {
    3588           0 :       flex_string_append(fs, "-");
    3589             :     } else {
    3590           0 :       flex_string_sprintf(fs, "%u", attr_p->attr.mptime.intervals[i]);
    3591             :     }
    3592             :   }
    3593             : 
    3594           0 :   flex_string_append(fs, "\r\n");
    3595             : 
    3596           0 :   return SDP_SUCCESS;
    3597             : }
    3598             : 
    3599             : 
    3600             : 
    3601           0 : sdp_result_e sdp_parse_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3602             :                                      const char *ptr)
    3603             : {
    3604             :     sdp_result_e  result;
    3605           0 :     attr_p->attr.stream_data.x_sidin[0]  = '\0';
    3606             : 
    3607           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3608           0 :         SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
    3609             :                      sdp_get_attr_name(attr_p->type));
    3610             :     }
    3611             : 
    3612             :     /* Find the X-sidin value */
    3613           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidin,
    3614             :                             sizeof(attr_p->attr.stream_data.x_sidin), " \t", &result);
    3615           0 :     if (result != SDP_SUCCESS) {
    3616           0 :         sdp_parse_error(sdp_p,
    3617             :             "%s Warning: No Stream Id incoming specified for X-sidin attribute.",
    3618           0 :             sdp_p->debug_str);
    3619           0 :         sdp_p->conf_p->num_invalid_param++;
    3620           0 :         return (SDP_INVALID_PARAMETER);
    3621             :     }
    3622             : 
    3623           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3624           0 :         SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
    3625             :                   sdp_get_attr_name(attr_p->type),
    3626             :                   attr_p->attr.stream_data.x_sidin);
    3627             :     }
    3628           0 :    return (SDP_SUCCESS);
    3629             : }
    3630             : 
    3631           0 : sdp_result_e sdp_build_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3632             :                                       flex_string *fs)
    3633             : {
    3634           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    3635           0 :     sdp_attr[attr_p->type].name,
    3636           0 :     attr_p->attr.stream_data.x_sidin);
    3637             : 
    3638           0 :   return SDP_SUCCESS;
    3639             : }
    3640             : 
    3641           0 : sdp_result_e sdp_parse_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3642             :                                       const char *ptr)
    3643             : {
    3644             :     sdp_result_e  result;
    3645           0 :     attr_p->attr.stream_data.x_sidout[0]  = '\0';
    3646             : 
    3647           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3648           0 :         SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
    3649             :                      sdp_get_attr_name(attr_p->type));
    3650             :     }
    3651             : 
    3652             :     /* Find the X-sidout value */
    3653           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidout,
    3654             :                             sizeof(attr_p->attr.stream_data.x_sidout), " \t", &result);
    3655           0 :     if (result != SDP_SUCCESS) {
    3656           0 :         sdp_parse_error(sdp_p,
    3657             :             "%s Warning: No Stream Id outgoing specified for X-sidout attribute.",
    3658           0 :             sdp_p->debug_str);
    3659           0 :         sdp_p->conf_p->num_invalid_param++;
    3660           0 :         return (SDP_INVALID_PARAMETER);
    3661             :     }
    3662             : 
    3663           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3664           0 :         SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
    3665             :                   sdp_get_attr_name(attr_p->type),
    3666             :                   attr_p->attr.stream_data.x_sidout);
    3667             :     }
    3668           0 :    return (SDP_SUCCESS);
    3669             : }
    3670             : 
    3671           0 : sdp_result_e sdp_build_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3672             :                                       flex_string *fs)
    3673             : {
    3674           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    3675           0 :     sdp_attr[attr_p->type].name,
    3676           0 :     attr_p->attr.stream_data.x_sidout);
    3677             : 
    3678           0 :   return SDP_SUCCESS;
    3679             : }
    3680             : 
    3681             : 
    3682           0 : sdp_result_e sdp_parse_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3683             :                                       const char *ptr)
    3684             : {
    3685             :     sdp_result_e  result;
    3686           0 :     attr_p->attr.stream_data.x_confid[0]  = '\0';
    3687             : 
    3688           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3689           0 :         SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
    3690             :                   sdp_get_attr_name(attr_p->type));
    3691             :     }
    3692             : 
    3693             :     /* Find the X-confid value */
    3694           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_confid,
    3695             :                             sizeof(attr_p->attr.stream_data.x_confid), " \t", &result);
    3696           0 :     if (result != SDP_SUCCESS) {
    3697           0 :         sdp_parse_error(sdp_p,
    3698             :             "%s Warning: No Conf Id incoming specified for "
    3699           0 :             "X-confid attribute.", sdp_p->debug_str);
    3700           0 :         sdp_p->conf_p->num_invalid_param++;
    3701           0 :         return (SDP_INVALID_PARAMETER);
    3702             :     }
    3703             : 
    3704           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3705           0 :         SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
    3706             :                   sdp_get_attr_name(attr_p->type),
    3707             :                   attr_p->attr.stream_data.x_confid);
    3708             :     }
    3709           0 :     return (SDP_SUCCESS);
    3710             : }
    3711             : 
    3712           0 : sdp_result_e sdp_build_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3713             :                                       flex_string *fs)
    3714             : {
    3715           0 :   if (strlen(attr_p->attr.stream_data.x_confid) <= 0) {
    3716           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3717           0 :       SDP_PRINT("%s X-confid value is not set. Cannot build a=X-confid line\n",
    3718             :         sdp_p->debug_str);
    3719             :     }
    3720             : 
    3721           0 :     return SDP_INVALID_PARAMETER;
    3722             :   }
    3723             : 
    3724           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    3725           0 :     sdp_attr[attr_p->type].name,
    3726           0 :     attr_p->attr.stream_data.x_confid);
    3727             : 
    3728           0 :   return SDP_SUCCESS;
    3729             : }
    3730             : 
    3731           0 : sdp_result_e sdp_parse_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3732             :                                    const char *ptr)
    3733             : {
    3734             :     sdp_result_e  result;
    3735             :     char tmp[64];
    3736           0 :     int i=0;
    3737             : 
    3738           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3739           0 :         SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
    3740             :                   sdp_get_attr_name(attr_p->type));
    3741             :     }
    3742             : 
    3743             :     /* Find the a=group:<attrib> <id1> < id2> ... values */
    3744           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3745           0 :     if (result != SDP_SUCCESS) {
    3746           0 :         sdp_parse_error(sdp_p,
    3747             :             "%s Warning: No group attribute value specified for "
    3748           0 :             "a=group line", sdp_p->debug_str);
    3749           0 :         sdp_p->conf_p->num_invalid_param++;
    3750           0 :         return (SDP_INVALID_PARAMETER);
    3751             :     }
    3752             : 
    3753           0 :     attr_p->attr.stream_data.group_attr = SDP_GROUP_ATTR_UNSUPPORTED;
    3754           0 :     for (i=0; i < SDP_MAX_GROUP_ATTR_VAL; i++) {
    3755           0 :         if (cpr_strncasecmp(tmp, sdp_group_attr_val[i].name,
    3756           0 :                         sdp_group_attr_val[i].strlen) == 0) {
    3757           0 :             attr_p->attr.stream_data.group_attr = (sdp_group_attr_e)i;
    3758           0 :             break;
    3759             :         }
    3760             :     }
    3761             : 
    3762           0 :     if (attr_p->attr.stream_data.group_attr == SDP_GROUP_ATTR_UNSUPPORTED) {
    3763           0 :         sdp_parse_error(sdp_p,
    3764             :             "%s Warning: Group attribute type unsupported (%s).",
    3765           0 :             sdp_p->debug_str, tmp);
    3766             :     }
    3767             : 
    3768             : 
    3769             :     /*
    3770             :      * Scan the input line up after group:<attr>  to the maximum number
    3771             :      * of id available.
    3772             :      */
    3773           0 :     attr_p->attr.stream_data.num_group_id =0;
    3774             : 
    3775           0 :     for (i=0; i<SDP_MAX_MEDIA_STREAMS; i++) {
    3776           0 :         ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3777             : 
    3778           0 :         if (result != SDP_SUCCESS) {
    3779           0 :             break;
    3780             :         }
    3781           0 :         attr_p->attr.stream_data.group_ids[i] = cpr_strdup(tmp);
    3782           0 :         if (!attr_p->attr.stream_data.group_ids[i]) {
    3783           0 :             break;
    3784             :         }
    3785             : 
    3786           0 :         attr_p->attr.stream_data.num_group_id++;
    3787             :     }
    3788             : 
    3789           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    3790           0 :         SDP_PRINT("%s Parsed a=%s:%s\n", sdp_p->debug_str,
    3791             :                   sdp_get_attr_name(attr_p->type),
    3792             :                   sdp_get_group_attr_name (attr_p->attr.stream_data.group_attr));
    3793           0 :         for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
    3794           0 :             SDP_PRINT("%s Parsed group line id : %s\n", sdp_p->debug_str,
    3795             :                       attr_p->attr.stream_data.group_ids[i]);
    3796             :         }
    3797             :     }
    3798           0 :     return (SDP_SUCCESS);
    3799             : }
    3800             : 
    3801           0 : sdp_result_e sdp_build_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3802             :                                    flex_string *fs)
    3803             : {
    3804             :   int i;
    3805             : 
    3806           0 :   flex_string_sprintf(fs, "a=%s:%s",
    3807           0 :     sdp_attr[attr_p->type].name,
    3808             :     sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr));
    3809             : 
    3810           0 :   for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
    3811           0 :     if (attr_p->attr.stream_data.group_ids[i]) {
    3812           0 :       flex_string_sprintf(fs, " %s",
    3813             :         attr_p->attr.stream_data.group_ids[i]);
    3814             :     }
    3815             :   }
    3816             : 
    3817           0 :   flex_string_append(fs, "\r\n");
    3818             : 
    3819           0 :   return SDP_SUCCESS;
    3820             : }
    3821             : 
    3822             : /* Parse the source-filter attribute
    3823             :  * "a=source-filter:<filter-mode><filter-spec>"
    3824             :  *  <filter-spec> = <nettype><addrtype><dest-addr><src_addr><src_addr>...
    3825             :  */
    3826           0 : sdp_result_e sdp_parse_attr_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3827             :                                            const char *ptr)
    3828             : {
    3829             :     int i;
    3830             :     sdp_result_e result;
    3831             :     char tmp[SDP_MAX_STRING_LEN];
    3832             : 
    3833           0 :     attr_p->attr.source_filter.mode = SDP_FILTER_MODE_NOT_PRESENT;
    3834           0 :     attr_p->attr.source_filter.nettype = SDP_NT_UNSUPPORTED;
    3835           0 :     attr_p->attr.source_filter.addrtype = SDP_AT_UNSUPPORTED;
    3836           0 :     attr_p->attr.source_filter.dest_addr[0] = '\0';
    3837           0 :     attr_p->attr.source_filter.num_src_addr = 0;
    3838             : 
    3839             :     /* Find the filter mode */
    3840           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3841           0 :     if (result != SDP_SUCCESS) {
    3842           0 :         sdp_parse_error(sdp_p,
    3843             :             "%s Warning: No src filter attribute value specified for "
    3844           0 :                      "a=source-filter line", sdp_p->debug_str);
    3845           0 :         sdp_p->conf_p->num_invalid_param++;
    3846           0 :         return (SDP_INVALID_PARAMETER);
    3847             :     }
    3848           0 :     for (i = 0; i < SDP_MAX_FILTER_MODE; i++) {
    3849           0 :         if (cpr_strncasecmp(tmp, sdp_src_filter_mode_val[i].name,
    3850           0 :                         sdp_src_filter_mode_val[i].strlen) == 0) {
    3851           0 :             attr_p->attr.source_filter.mode = (sdp_src_filter_mode_e)i;
    3852           0 :             break;
    3853             :         }
    3854             :     }
    3855           0 :     if (attr_p->attr.source_filter.mode == SDP_FILTER_MODE_NOT_PRESENT) {
    3856             :         /* No point continuing */
    3857           0 :         sdp_parse_error(sdp_p,
    3858             :             "%s Warning: Invalid src filter mode for a=source-filter "
    3859           0 :             "line", sdp_p->debug_str);
    3860           0 :         sdp_p->conf_p->num_invalid_param++;
    3861           0 :         return (SDP_INVALID_PARAMETER);
    3862             :     }
    3863             : 
    3864             :     /* Find the network type */
    3865           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3866           0 :     if (result != SDP_SUCCESS) {
    3867           0 :         sdp_p->conf_p->num_invalid_param++;
    3868           0 :         return (SDP_INVALID_PARAMETER);
    3869             :     }
    3870           0 :     for (i = 0; i < SDP_MAX_NETWORK_TYPES; i++) {
    3871           0 :         if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
    3872           0 :                         sdp_nettype[i].strlen) == 0) {
    3873           0 :             if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
    3874           0 :                 attr_p->attr.source_filter.nettype = (sdp_nettype_e)i;
    3875             :             }
    3876             :         }
    3877             :     }
    3878           0 :     if (attr_p->attr.source_filter.nettype == SDP_NT_UNSUPPORTED) {
    3879           0 :         sdp_parse_error(sdp_p,
    3880             :             "%s Warning: Network type unsupported "
    3881           0 :             "(%s) for a=source-filter", sdp_p->debug_str, tmp);
    3882           0 :         sdp_p->conf_p->num_invalid_param++;
    3883           0 :         return (SDP_INVALID_PARAMETER);
    3884             :     }
    3885             : 
    3886             :     /* Find the address type */
    3887           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3888           0 :     if (result != SDP_SUCCESS) {
    3889           0 :         sdp_p->conf_p->num_invalid_param++;
    3890           0 :         return (SDP_INVALID_PARAMETER);
    3891             :     }
    3892           0 :     for (i = 0; i < SDP_MAX_ADDR_TYPES; i++) {
    3893           0 :         if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
    3894           0 :                         sdp_addrtype[i].strlen) == 0) {
    3895           0 :             if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
    3896           0 :                 attr_p->attr.source_filter.addrtype = (sdp_addrtype_e)i;
    3897             :             }
    3898             :         }
    3899             :     }
    3900           0 :     if (attr_p->attr.source_filter.addrtype == SDP_AT_UNSUPPORTED) {
    3901           0 :         if (strncmp(tmp, "*", 1) == 0) {
    3902           0 :             attr_p->attr.source_filter.addrtype = SDP_AT_FQDN;
    3903             :         } else {
    3904           0 :             sdp_parse_error(sdp_p,
    3905             :                 "%s Warning: Address type unsupported "
    3906           0 :                 "(%s) for a=source-filter", sdp_p->debug_str, tmp);
    3907           0 :             sdp_p->conf_p->num_invalid_param++;
    3908           0 :             return (SDP_INVALID_PARAMETER);
    3909             :         }
    3910             :     }
    3911             : 
    3912             :     /* Find the destination addr */
    3913           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.dest_addr,
    3914             :                             sizeof(attr_p->attr.source_filter.dest_addr), " \t", &result);
    3915           0 :     if (result != SDP_SUCCESS) {
    3916           0 :         sdp_parse_error(sdp_p,
    3917             :             "%s No filter destination address specified for "
    3918           0 :             "a=source-filter", sdp_p->debug_str);
    3919           0 :         sdp_p->conf_p->num_invalid_param++;
    3920           0 :         return (SDP_INVALID_PARAMETER);
    3921             :     }
    3922             : 
    3923             :     /* Find the list of source address to apply the filter */
    3924           0 :     for (i = 0; i < SDP_MAX_SRC_ADDR_LIST; i++) {
    3925           0 :         ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.src_list[i],
    3926             :                                 sizeof(attr_p->attr.source_filter.src_list[i]), " \t", &result);
    3927           0 :         if (result != SDP_SUCCESS) {
    3928           0 :             break;
    3929             :         }
    3930           0 :         attr_p->attr.source_filter.num_src_addr++;
    3931             :     }
    3932           0 :     if (attr_p->attr.source_filter.num_src_addr == 0) {
    3933           0 :         sdp_parse_error(sdp_p,
    3934             :             "%s Warning: No source list provided "
    3935           0 :             "for a=source-filter", sdp_p->debug_str);
    3936           0 :         sdp_p->conf_p->num_invalid_param++;
    3937           0 :         return (SDP_INVALID_PARAMETER);
    3938             :     }
    3939             : 
    3940           0 :     return (SDP_SUCCESS);
    3941             : }
    3942             : 
    3943           0 : sdp_result_e sdp_build_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3944             :                                       flex_string *fs)
    3945             : {
    3946             :   int i;
    3947             : 
    3948           0 :   flex_string_sprintf(fs, "a=%s:%s %s %s %s",
    3949             :     sdp_get_attr_name(attr_p->type),
    3950             :     sdp_get_src_filter_mode_name(attr_p->attr.source_filter.mode),
    3951             :     sdp_get_network_name(attr_p->attr.source_filter.nettype),
    3952             :     sdp_get_address_name(attr_p->attr.source_filter.addrtype),
    3953           0 :     attr_p->attr.source_filter.dest_addr);
    3954             : 
    3955           0 :   for (i = 0; i < attr_p->attr.source_filter.num_src_addr; i++) {
    3956           0 :     flex_string_append(fs, " ");
    3957           0 :     flex_string_append(fs, attr_p->attr.source_filter.src_list[i]);
    3958             :   }
    3959             : 
    3960           0 :   flex_string_append(fs, "\r\n");
    3961             : 
    3962           0 :   return SDP_SUCCESS;
    3963             : }
    3964             : 
    3965             : /* Parse the rtcp-unicast attribute
    3966             :  * "a=rtcp-unicast:<reflection|rsi>"
    3967             :  */
    3968           0 : sdp_result_e sdp_parse_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
    3969             :                                           const char *ptr)
    3970             : {
    3971             :     sdp_result_e result;
    3972             :     uint32_t i;
    3973             :     char tmp[SDP_MAX_STRING_LEN];
    3974             : 
    3975           0 :     attr_p->attr.u32_val = SDP_RTCP_UNICAST_MODE_NOT_PRESENT;
    3976             : 
    3977           0 :     memset(tmp, 0, sizeof(tmp));
    3978             : 
    3979           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    3980           0 :     if (result != SDP_SUCCESS) {
    3981           0 :         sdp_parse_error(sdp_p,
    3982             :             "%s Warning: No rtcp unicast mode specified for "
    3983           0 :             "a=rtcp-unicast line", sdp_p->debug_str);
    3984           0 :         sdp_p->conf_p->num_invalid_param++;
    3985           0 :         return (SDP_INVALID_PARAMETER);
    3986             :     }
    3987           0 :     for (i = 0; i < SDP_RTCP_MAX_UNICAST_MODE;  i++) {
    3988           0 :         if (cpr_strncasecmp(tmp, sdp_rtcp_unicast_mode_val[i].name,
    3989           0 :                         sdp_rtcp_unicast_mode_val[i].strlen) == 0) {
    3990           0 :             attr_p->attr.u32_val = i;
    3991           0 :             break;
    3992             :         }
    3993             :     }
    3994           0 :     if (attr_p->attr.u32_val == SDP_RTCP_UNICAST_MODE_NOT_PRESENT) {
    3995           0 :         sdp_parse_error(sdp_p,
    3996             :             "%s Warning: Invalid rtcp unicast mode for "
    3997           0 :             "a=rtcp-unicast line", sdp_p->debug_str);
    3998           0 :         sdp_p->conf_p->num_invalid_param++;
    3999           0 :         return (SDP_INVALID_PARAMETER);
    4000             :     }
    4001           0 :     return (SDP_SUCCESS);
    4002             : }
    4003             : 
    4004           0 : sdp_result_e sdp_build_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4005             :                                           flex_string *fs)
    4006             : {
    4007           0 :   if (attr_p->attr.u32_val >= SDP_RTCP_MAX_UNICAST_MODE) {
    4008           0 :     return SDP_INVALID_PARAMETER;
    4009             :   }
    4010             : 
    4011           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    4012             :     sdp_get_attr_name(attr_p->type),
    4013           0 :     sdp_get_rtcp_unicast_mode_name((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val));
    4014             : 
    4015           0 :   return SDP_SUCCESS;
    4016             : }
    4017             : 
    4018             : 
    4019             : /*
    4020             :  * store_sdescriptions_mki_or_lifetime
    4021             :  *
    4022             :  * Verifies the syntax of the MKI or lifetime parameter and stores
    4023             :  * it in the sdescriptions attribute struct.
    4024             :  *
    4025             :  * Inputs:
    4026             :  *   buf    - pointer to MKI or lifetime string assumes string is null
    4027             :  *            terminated.
    4028             :  *   attr_p - pointer to attribute struct
    4029             :  *
    4030             :  * Outputs:
    4031             :  *   Return TRUE all is good otherwise FALSE for error.
    4032             :  */
    4033             : 
    4034             : tinybool
    4035           0 : store_sdescriptions_mki_or_lifetime (char *buf, sdp_attr_t *attr_p)
    4036             : {
    4037             : 
    4038             :     tinybool  result;
    4039             :     uint16_t       mkiLen;
    4040             :     char      mkiValue[SDP_SRTP_MAX_MKI_SIZE_BYTES];
    4041             : 
    4042             :     /* MKI has a colon */
    4043           0 :     if (strstr(buf, ":")) {
    4044           0 :         result = verify_sdescriptions_mki(buf, mkiValue, &mkiLen);
    4045           0 :         if (result) {
    4046           0 :             attr_p->attr.srtp_context.mki_size_bytes = mkiLen;
    4047           0 :             sstrncpy((char*)attr_p->attr.srtp_context.mki, mkiValue,
    4048             :                      SDP_SRTP_MAX_MKI_SIZE_BYTES);
    4049             :         }
    4050             : 
    4051             :     } else {
    4052           0 :         result =  verify_sdescriptions_lifetime(buf);
    4053           0 :         if (result) {
    4054           0 :             sstrncpy((char*)attr_p->attr.srtp_context.master_key_lifetime, buf,
    4055             :                      SDP_SRTP_MAX_LIFETIME_BYTES);
    4056             :         }
    4057             :     }
    4058             : 
    4059           0 :     return result;
    4060             : 
    4061             : }
    4062             : 
    4063             : /*
    4064             :  * sdp_parse_sdescriptions_key_param
    4065             :  *
    4066             :  * This routine parses the srtp key-params pointed to by str.
    4067             :  *
    4068             :  * key-params    = <key-method> ":" <key-info>
    4069             :  * key-method    = "inline" / key-method-ext [note V9 only supports 'inline']
    4070             :  * key-info      = srtp-key-info
    4071             :  * srtp-key-info = key-salt ["|" lifetime] ["|" mki]
    4072             :  * key-salt      = 1*(base64)   ; binary key and salt values
    4073             :  *                              ; concatenated together, and then
    4074             :  *                              ; base64 encoded [section 6.8 of
    4075             :  *                              ; RFC2046]
    4076             :  *
    4077             :  * lifetime      = ["2^"] 1*(DIGIT)
    4078             :  * mki           = mki-value ":" mki-length
    4079             :  * mki-value     = 1*DIGIT
    4080             :  * mki-length    = 1*3DIGIT   ; range 1..128.
    4081             :  *
    4082             :  * Inputs: str - pointer to beginning of key-params and assumes
    4083             :  *               null terminated string.
    4084             :  */
    4085             : 
    4086             : 
    4087             : tinybool
    4088           0 : sdp_parse_sdescriptions_key_param (const char *str, sdp_attr_t *attr_p,
    4089             :                                    sdp_t *sdp_p)
    4090             : {
    4091             :     char            buf[SDP_MAX_STRING_LEN],
    4092             :                     base64decodeData[SDP_MAX_STRING_LEN];
    4093             :     const char      *ptr;
    4094           0 :     sdp_result_e    result = SDP_SUCCESS;
    4095           0 :     tinybool        keyFound = FALSE;
    4096             :     int             len,
    4097             :                     keySize,
    4098             :                     saltSize;
    4099             :     base64_result_t status;
    4100             : 
    4101           0 :     ptr = str;
    4102           0 :     if (cpr_strncasecmp(ptr, "inline:", 7) != 0) {
    4103           0 :         sdp_parse_error(sdp_p,
    4104           0 :             "%s Could not find keyword inline", sdp_p->debug_str);
    4105           0 :         sdp_p->conf_p->num_invalid_param++;
    4106           0 :         return FALSE;
    4107             :     }
    4108             : 
    4109             :     /* advance pass the inline key word */
    4110           0 :     ptr = ptr + 7;
    4111           0 :     ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
    4112           0 :     while (result == SDP_SUCCESS) {
    4113             :         /* the fist time this loop executes, the key is gotten */
    4114           0 :         if (keyFound == FALSE) {
    4115           0 :             keyFound = TRUE;
    4116           0 :             len = SDP_MAX_STRING_LEN;
    4117             :             /* The key is base64 encoded composed of the master key concatenated with the
    4118             :              * master salt.
    4119             :              */
    4120           0 :             status = base64_decode((unsigned char *)buf, strlen(buf),
    4121             :                                    (unsigned char *)base64decodeData, &len);
    4122             : 
    4123           0 :         if (status != BASE64_SUCCESS) {
    4124           0 :             sdp_parse_error(sdp_p,
    4125             :                 "%s key-salt error decoding buffer: %s",
    4126           0 :                 sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
    4127           0 :             return FALSE;
    4128             :         }
    4129             : 
    4130           0 :         keySize = attr_p->attr.srtp_context.master_key_size_bytes;
    4131           0 :         saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
    4132             : 
    4133           0 :         if (len != keySize + saltSize) {
    4134           0 :             sdp_parse_error(sdp_p,
    4135             :                 "%s key-salt size doesn't match: (%d, %d, %d)",
    4136           0 :                 sdp_p->debug_str, len, keySize, saltSize);
    4137           0 :             return(FALSE);
    4138             :         }
    4139             : 
    4140           0 :             memcpy(attr_p->attr.srtp_context.master_key,
    4141             :                    base64decodeData,
    4142             :                    keySize);
    4143             : 
    4144           0 :             memcpy(attr_p->attr.srtp_context.master_salt,
    4145             :                    base64decodeData + keySize,
    4146             :                    saltSize);
    4147             : 
    4148             :             /* Used only for MGCP */
    4149           0 :             SDP_SRTP_CONTEXT_SET_MASTER_KEY
    4150             :                      (attr_p->attr.srtp_context.selection_flags);
    4151           0 :             SDP_SRTP_CONTEXT_SET_MASTER_SALT
    4152             :                      (attr_p->attr.srtp_context.selection_flags);
    4153             : 
    4154           0 :        } else if (store_sdescriptions_mki_or_lifetime(buf, attr_p) == FALSE) {
    4155           0 :            return FALSE;
    4156             :        }
    4157             : 
    4158             :        /* if we haven't reached the end of line, get the next token */
    4159           0 :        ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
    4160             :     }
    4161             : 
    4162             :     /* if we didn't find the key, error out */
    4163           0 :     if (keyFound == FALSE) {
    4164           0 :         sdp_parse_error(sdp_p,
    4165           0 :             "%s Could not find sdescriptions key", sdp_p->debug_str);
    4166           0 :         sdp_p->conf_p->num_invalid_param++;
    4167           0 :         return FALSE;
    4168             :     }
    4169             : 
    4170           0 :     return TRUE;
    4171             : 
    4172             : }
    4173             : 
    4174             : /*
    4175             :  * sdp_build_attr_sdescriptions
    4176             :  *
    4177             :  * Builds a=crypto line for attribute type SDP_ATTR_SDESCRIPTIONS.
    4178             :  *
    4179             :  * a=crypto:tag 1*WSP crypto-suite 1*WSP key-params
    4180             :  *
    4181             :  * Where key-params = inline: <key|salt> ["|"lifetime] ["|" MKI:length]
    4182             :  * The key and salt is base64 encoded and lifetime and MKI/length are optional.
    4183             :  */
    4184             : 
    4185             : sdp_result_e
    4186           0 : sdp_build_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4187             :                               flex_string *fs)
    4188             : {
    4189             : 
    4190             :     unsigned char  base64_encoded_data[MAX_BASE64_STRING_LEN];
    4191             :     unsigned char  base64_encoded_input[MAX_BASE64_STRING_LEN];
    4192             :     int            keySize,
    4193             :                    saltSize,
    4194             :                    outputLen;
    4195             :     base64_result_t status;
    4196             : 
    4197           0 :     keySize = attr_p->attr.srtp_context.master_key_size_bytes;
    4198           0 :     saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
    4199             : 
    4200             :     /* concatenate the master key + salt then base64 encode it */
    4201           0 :     memcpy(base64_encoded_input,
    4202           0 :            attr_p->attr.srtp_context.master_key,
    4203             :            keySize);
    4204             : 
    4205           0 :     memcpy(base64_encoded_input + keySize,
    4206           0 :            attr_p->attr.srtp_context.master_salt,
    4207             :            saltSize);
    4208             : 
    4209           0 :     outputLen = MAX_BASE64_STRING_LEN;
    4210           0 :     status = base64_encode(base64_encoded_input, keySize + saltSize,
    4211             :                            base64_encoded_data, &outputLen);
    4212             : 
    4213           0 :     if (status != BASE64_SUCCESS) {
    4214           0 :         if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
    4215           0 :             CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
    4216             :                        sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
    4217             :         }
    4218           0 :         return (SDP_INVALID_PARAMETER);
    4219             : 
    4220             :     }
    4221             : 
    4222           0 :     base64_encoded_data[outputLen] = 0;
    4223             : 
    4224             :     /* lifetime and MKI parameters are optional. Only inlcude them if
    4225             :      * they were set.
    4226             :      */
    4227             : 
    4228             : 
    4229           0 :     if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0 &&
    4230           0 :         attr_p->attr.srtp_context.mki[0] != 0) {
    4231           0 :       flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s|%s:%d\r\n",
    4232           0 :         sdp_attr[attr_p->type].name,
    4233             :         attr_p->attr.srtp_context.tag,
    4234           0 :         sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
    4235             :         base64_encoded_data,
    4236           0 :         attr_p->attr.srtp_context.master_key_lifetime,
    4237           0 :         attr_p->attr.srtp_context.mki,
    4238           0 :         attr_p->attr.srtp_context.mki_size_bytes);
    4239             : 
    4240           0 :       return SDP_SUCCESS;
    4241             :     }
    4242             : 
    4243             :     /* if we get here, either lifetime is populated and mki and is not or mki is populated
    4244             :      * and lifetime is not or neither is populated
    4245             :      */
    4246             : 
    4247           0 :     if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0) {
    4248           0 :       flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s\r\n",
    4249           0 :         sdp_attr[attr_p->type].name,
    4250             :         attr_p->attr.srtp_context.tag,
    4251           0 :         sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
    4252             :         base64_encoded_data,
    4253           0 :         attr_p->attr.srtp_context.master_key_lifetime);
    4254             : 
    4255           0 :     } else if (attr_p->attr.srtp_context.mki[0] != 0) {
    4256           0 :       flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s:%d\r\n",
    4257           0 :         sdp_attr[attr_p->type].name,
    4258             :         attr_p->attr.srtp_context.tag,
    4259           0 :         sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
    4260             :         base64_encoded_data,
    4261           0 :         attr_p->attr.srtp_context.mki,
    4262           0 :         attr_p->attr.srtp_context.mki_size_bytes);
    4263             : 
    4264             :     } else {
    4265           0 :       flex_string_sprintf(fs, "a=%s:%d %s inline:%s\r\n",
    4266           0 :         sdp_attr[attr_p->type].name,
    4267             :         attr_p->attr.srtp_context.tag,
    4268           0 :         sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
    4269             :         base64_encoded_data);
    4270             : 
    4271             :     }
    4272             : 
    4273           0 :     return SDP_SUCCESS;
    4274             : 
    4275             : }
    4276             : 
    4277             : 
    4278             : /*
    4279             :  * sdp_parse_attr_srtp
    4280             :  *
    4281             :  * Parses Session Description for Protocol Security Descriptions
    4282             :  * version 2 or version 9. Grammar is of the form:
    4283             :  *
    4284             :  * a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
    4285             :  *
    4286             :  * Note session-params is not supported and will not be parsed.
    4287             :  * Version 2 does not contain a tag.
    4288             :  *
    4289             :  * Inputs:
    4290             :  *   sdp_p  - pointer to sdp handle
    4291             :  *   attr_p - pointer to attribute structure
    4292             :  *   ptr    - pointer to string to be parsed
    4293             :  *   vtype  - version type
    4294             :  */
    4295             : 
    4296             : sdp_result_e
    4297           0 : sdp_parse_attr_srtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4298             :                      const char *ptr, sdp_attr_e vtype)
    4299             : {
    4300             : 
    4301             :     char         tmp[SDP_MAX_STRING_LEN];
    4302           0 :     sdp_result_e result = SDP_FAILURE;
    4303           0 :     int          k = 0;
    4304             : 
    4305             :     /* initialize only the optional parameters */
    4306           0 :     attr_p->attr.srtp_context.master_key_lifetime[0] = 0;
    4307           0 :     attr_p->attr.srtp_context.mki[0] = 0;
    4308             : 
    4309             :      /* used only for MGCP */
    4310           0 :     SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE
    4311             :              (attr_p->attr.srtp_context.selection_flags);
    4312             : 
    4313             :     /* get the tag only if we are version 9 */
    4314           0 :     if (vtype == SDP_ATTR_SDESCRIPTIONS) {
    4315           0 :         attr_p->attr.srtp_context.tag =
    4316           0 :                 sdp_getnextnumtok(ptr, &ptr, " \t", &result);
    4317             : 
    4318           0 :         if (result != SDP_SUCCESS) {
    4319           0 :             sdp_parse_error(sdp_p,
    4320             :                 "%s Could not find sdescriptions tag",
    4321           0 :                 sdp_p->debug_str);
    4322           0 :             sdp_p->conf_p->num_invalid_param++;
    4323           0 :             return (SDP_INVALID_PARAMETER);
    4324             : 
    4325             :         }
    4326             :     }
    4327             : 
    4328             :     /* get the crypto suite */
    4329           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    4330           0 :     if (result != SDP_SUCCESS) {
    4331           0 :         sdp_parse_error(sdp_p,
    4332           0 :             "%s Could not find sdescriptions crypto suite", sdp_p->debug_str);
    4333           0 :         sdp_p->conf_p->num_invalid_param++;
    4334           0 :         return (SDP_INVALID_PARAMETER);
    4335             :     }
    4336             : 
    4337           0 :     if (!sdp_parse_context_crypto_suite(tmp, attr_p, sdp_p)) {
    4338           0 :         sdp_parse_error(sdp_p,
    4339           0 :             "%s Unsupported crypto suite", sdp_p->debug_str);
    4340           0 :             return (SDP_INVALID_PARAMETER);
    4341             :     }
    4342             : 
    4343           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
    4344           0 :     if (result != SDP_SUCCESS) {
    4345           0 :         sdp_parse_error(sdp_p,
    4346           0 :             "%s Could not find sdescriptions key params", sdp_p->debug_str);
    4347           0 :         sdp_p->conf_p->num_invalid_param++;
    4348           0 :         return (SDP_INVALID_PARAMETER);
    4349             :     }
    4350             : 
    4351           0 :     if (!sdp_parse_sdescriptions_key_param(tmp, attr_p, sdp_p)) {
    4352           0 :         sdp_parse_error(sdp_p,
    4353           0 :             "%s Failed to parse key-params", sdp_p->debug_str);
    4354           0 :         return (SDP_INVALID_PARAMETER);
    4355             :     }
    4356             : 
    4357             :     /* if there are session parameters, scan the session parameters
    4358             :      * into tmp until we reach end of line. Currently the sdp parser
    4359             :      * does not parse session parameters but if they are present,
    4360             :      * we store them for the application.
    4361             :      */
    4362             :     /*sa_ignore NO_NULL_CHK
    4363             :      *{ptr is valid since the pointer was checked earlier and the
    4364             :      * function would have exited if NULL.}
    4365             :      */
    4366           0 :     while (*ptr && *ptr != '\n' && *ptr != '\r' && k < SDP_MAX_STRING_LEN) {
    4367           0 :          tmp[k++] = *ptr++;
    4368             :     }
    4369             : 
    4370           0 :     if ((k) && (k < SDP_MAX_STRING_LEN)) {
    4371           0 :         tmp[k] = 0;
    4372           0 :         attr_p->attr.srtp_context.session_parameters = cpr_strdup(tmp);
    4373             :     }
    4374             : 
    4375           0 :     return SDP_SUCCESS;
    4376             : 
    4377             : }
    4378             : 
    4379             : /* Parses crypto attribute based on the sdescriptions version
    4380             :  * 9 grammar.
    4381             :  *
    4382             :  */
    4383             : 
    4384             : sdp_result_e
    4385           0 : sdp_parse_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4386             :                               const char *ptr)
    4387             : {
    4388             : 
    4389           0 :    return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
    4390             :                               SDP_ATTR_SDESCRIPTIONS);
    4391             : 
    4392             : }
    4393             : 
    4394             : /* Parses X-crypto attribute based on the sdescriptions version
    4395             :  * 2 grammar.
    4396             :  *
    4397             :  */
    4398             : 
    4399           0 : sdp_result_e sdp_parse_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4400             :                                          const char *ptr)
    4401             : {
    4402             : 
    4403           0 :     return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
    4404             :                                SDP_ATTR_SRTP_CONTEXT);
    4405             : }
    4406             : 
    4407             : 
    4408           0 : sdp_result_e sdp_build_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4409             :                                           flex_string *fs) {
    4410           0 :   flex_string_sprintf(fs, "a=%s:%s\r\n",
    4411             :                       sdp_get_attr_name(attr_p->type),
    4412           0 :                       attr_p->attr.ice_attr);
    4413             : 
    4414           0 :   return SDP_SUCCESS;
    4415             : }
    4416             : 
    4417             : 
    4418           0 : sdp_result_e sdp_parse_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr) {
    4419             :     sdp_result_e  result;
    4420             :     char tmp[SDP_MAX_STRING_LEN];
    4421             : 
    4422           0 :     ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "\r\n", &result);
    4423           0 :     if (result != SDP_SUCCESS){
    4424           0 :         sdp_parse_error(sdp_p,
    4425           0 :             "%s Warning: problem parsing ice attribute ", sdp_p->debug_str);
    4426           0 :         sdp_p->conf_p->num_invalid_param++;
    4427           0 :         return (SDP_INVALID_PARAMETER);
    4428             :     }
    4429             : 
    4430           0 :     snprintf(attr_p->attr.ice_attr, sizeof(attr_p->attr.ice_attr), "%s", tmp);
    4431             : 
    4432           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    4433           0 :       SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, sdp_get_attr_name(attr_p->type), tmp);
    4434             :     }
    4435           0 :     return (SDP_SUCCESS);
    4436             : }
    4437             : 
    4438             : 
    4439           0 : sdp_result_e sdp_build_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4440             :                                          flex_string *fs) {
    4441           0 :     flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
    4442             : 
    4443           0 :     return SDP_SUCCESS;
    4444             : }
    4445             : 
    4446             : 
    4447           0 : sdp_result_e sdp_parse_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4448             :                                       const char *ptr) {
    4449             :     /* No parameters to parse. */
    4450             : 
    4451           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    4452           0 :         SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
    4453             :                   sdp_get_attr_name(attr_p->type));
    4454             :     }
    4455             : 
    4456           0 :     return (SDP_SUCCESS);
    4457             : }
    4458             : 
    4459           0 : static sdp_result_e sdp_parse_attr_line(sdp_t *sdp_p, sdp_attr_t *attr_p,
    4460             :                                         const char *ptr, char *buf, size_t buf_len) {
    4461             :     sdp_result_e result;
    4462             : 
    4463           0 :     (void)sdp_getnextstrtok(ptr, buf, buf_len, "\r\n", &result);
    4464             : 
    4465           0 :     if (result != SDP_SUCCESS) {
    4466           0 :         sdp_parse_error(sdp_p,
    4467             :             "%s Warning: No string token found for %s attribute",
    4468           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    4469           0 :         sdp_p->conf_p->num_invalid_param++;
    4470           0 :         return (SDP_INVALID_PARAMETER);
    4471             :     } else {
    4472           0 :         if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    4473           0 :             SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
    4474             :                       sdp_get_attr_name(attr_p->type),
    4475             :                       buf);
    4476             :         }
    4477           0 :         return (SDP_SUCCESS);
    4478             :     }
    4479             : }
    4480             : 
    4481           0 : sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4482             :                                            const char *ptr)
    4483             : {
    4484           0 :     return sdp_parse_attr_line(sdp_p, attr_p, ptr,
    4485           0 :                                attr_p->attr.string_val,
    4486             :                                sizeof(attr_p->attr.string_val));
    4487             : }
    4488             : 
    4489           0 : sdp_result_e sdp_parse_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4490             :                                        const char *ptr)
    4491             : {
    4492             :     sdp_result_e result;
    4493             :     char buffer[SDP_MAX_LONG_STRING_LEN];
    4494             : 
    4495           0 :     result = sdp_parse_attr_line(sdp_p, attr_p, ptr,
    4496             :                                  buffer, sizeof(buffer));
    4497           0 :     if (result == SDP_SUCCESS) {
    4498           0 :         attr_p->attr.stringp = cpr_strdup(buffer);
    4499             :     }
    4500           0 :     return result;
    4501             : }
    4502             : 
    4503           0 : sdp_result_e sdp_build_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
    4504             :                                        flex_string *fs)
    4505             : {
    4506           0 :     flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
    4507             :                         attr_p->attr.stringp);
    4508           0 :     return SDP_SUCCESS;
    4509             : }
    4510             : 
    4511           0 : sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p,
    4512             :                                     sdp_attr_t *attr_p,
    4513             :                                     flex_string *fs)
    4514             : {
    4515           0 :     flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
    4516             : 
    4517             :     /* Payload Type */
    4518           0 :     if (attr_p->attr.rtcp_fb.payload_num == SDP_ALL_PAYLOADS) {
    4519           0 :       flex_string_sprintf(fs, "* ");
    4520             :     } else {
    4521           0 :       flex_string_sprintf(fs, "%d ",attr_p->attr.rtcp_fb.payload_num);
    4522             :     }
    4523             : 
    4524             :     /* Feedback Type */
    4525           0 :     if (attr_p->attr.rtcp_fb.feedback_type < SDP_RTCP_FB_UNKNOWN) {
    4526           0 :         flex_string_sprintf(fs, "%s",
    4527           0 :             sdp_rtcp_fb_type_val[attr_p->attr.rtcp_fb.feedback_type].name);
    4528             :     }
    4529             : 
    4530             :     /* Feedback Type Parameters */
    4531           0 :     switch (attr_p->attr.rtcp_fb.feedback_type) {
    4532             :         case SDP_RTCP_FB_ACK:
    4533           0 :             if (attr_p->attr.rtcp_fb.param.ack < SDP_MAX_RTCP_FB_ACK) {
    4534           0 :                 flex_string_sprintf(fs, " %s",
    4535           0 :                     sdp_rtcp_fb_ack_type_val[attr_p->attr.rtcp_fb.param.ack]
    4536             :                         .name);
    4537             :             }
    4538           0 :             break;
    4539             :         case SDP_RTCP_FB_CCM: /* RFC 5104 */
    4540           0 :             if (attr_p->attr.rtcp_fb.param.ccm < SDP_MAX_RTCP_FB_CCM) {
    4541           0 :                 flex_string_sprintf(fs, " %s",
    4542           0 :                     sdp_rtcp_fb_ccm_type_val[attr_p->attr.rtcp_fb.param.ccm]
    4543             :                         .name);
    4544             :             }
    4545           0 :             break;
    4546             :         case SDP_RTCP_FB_NACK:
    4547           0 :             if (attr_p->attr.rtcp_fb.param.nack > SDP_RTCP_FB_NACK_BASIC
    4548           0 :                 && attr_p->attr.rtcp_fb.param.nack < SDP_MAX_RTCP_FB_NACK) {
    4549           0 :                 flex_string_sprintf(fs, " %s",
    4550           0 :                     sdp_rtcp_fb_nack_type_val[attr_p->attr.rtcp_fb.param.nack]
    4551             :                         .name);
    4552             :             }
    4553           0 :             break;
    4554             :         case SDP_RTCP_FB_TRR_INT:
    4555           0 :             flex_string_sprintf(fs, " %u", attr_p->attr.rtcp_fb.param.trr_int);
    4556           0 :             break;
    4557             :         case SDP_RTCP_FB_REMB:
    4558             :             /* No additional params after REMB */
    4559           0 :             break;
    4560             : 
    4561             :         case SDP_RTCP_FB_UNKNOWN:
    4562             :             /* Contents are in the "extra" field */
    4563           0 :             break;
    4564             : 
    4565             :         default:
    4566           0 :             CSFLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
    4567             :                         sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type);
    4568           0 :             return SDP_FAILURE;
    4569             :     }
    4570             : 
    4571             :     /* Tack on any information that cannot otherwise be represented by
    4572             :      * the sdp_fmtp_fb_t structure. */
    4573           0 :     if (attr_p->attr.rtcp_fb.extra[0]) {
    4574           0 :         flex_string_sprintf(fs, " %s", attr_p->attr.rtcp_fb.extra);
    4575             :     }
    4576             : 
    4577             :     /* Line ending */
    4578           0 :     flex_string_sprintf(fs, "\r\n");
    4579             : 
    4580           0 :     return SDP_SUCCESS;
    4581             : }
    4582             : 
    4583           0 : sdp_result_e sdp_parse_attr_rtcp_fb (sdp_t *sdp_p,
    4584             :                                      sdp_attr_t *attr_p,
    4585             :                                      const char *ptr)
    4586             : {
    4587           0 :     sdp_result_e     result = SDP_SUCCESS;
    4588           0 :     sdp_fmtp_fb_t   *rtcp_fb_p = &(attr_p->attr.rtcp_fb);
    4589             :     int              i;
    4590             : 
    4591             :     /* Set up attribute fields */
    4592           0 :     rtcp_fb_p->payload_num = 0;
    4593           0 :     rtcp_fb_p->feedback_type = SDP_RTCP_FB_UNKNOWN;
    4594           0 :     rtcp_fb_p->extra[0] = '\0';
    4595             : 
    4596             :     /* Skip WS (just in case) */
    4597           0 :     while (*ptr == ' ' || *ptr == '\t') {
    4598           0 :         ptr++;
    4599             :     }
    4600             : 
    4601             :     /* Look for the special "*" payload type */
    4602           0 :     if (*ptr == '*') {
    4603           0 :         rtcp_fb_p->payload_num = SDP_ALL_PAYLOADS;
    4604           0 :         ptr++;
    4605             :     } else {
    4606             :         /* If the pt is not '*', parse it out as an integer */
    4607           0 :         rtcp_fb_p->payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
    4608             :                                                         " \t", &result);
    4609           0 :         if (result != SDP_SUCCESS) {
    4610           0 :             sdp_parse_error(sdp_p,
    4611             :               "%s Warning: could not parse payload type for rtcp-fb attribute",
    4612           0 :               sdp_p->debug_str);
    4613           0 :             sdp_p->conf_p->num_invalid_param++;
    4614             : 
    4615           0 :             return SDP_INVALID_PARAMETER;
    4616             :         }
    4617             :     }
    4618             : 
    4619             :     /* Read feedback type */
    4620           0 :     i = find_token_enum("rtcp-fb attribute", sdp_p, &ptr, sdp_rtcp_fb_type_val,
    4621             :                         SDP_MAX_RTCP_FB, SDP_RTCP_FB_UNKNOWN);
    4622           0 :     if (i < 0) {
    4623           0 :         sdp_parse_error(sdp_p,
    4624             :           "%s Warning: could not parse feedback type for rtcp-fb attribute",
    4625           0 :           sdp_p->debug_str);
    4626           0 :         sdp_p->conf_p->num_invalid_param++;
    4627           0 :         return SDP_INVALID_PARAMETER;
    4628             :     }
    4629           0 :     rtcp_fb_p->feedback_type = (sdp_rtcp_fb_type_e) i;
    4630             : 
    4631           0 :     switch(rtcp_fb_p->feedback_type) {
    4632             :         case SDP_RTCP_FB_ACK:
    4633           0 :             i = find_token_enum("rtcp-fb ack type", sdp_p, &ptr,
    4634             :                                 sdp_rtcp_fb_ack_type_val,
    4635             :                                 SDP_MAX_RTCP_FB_ACK, SDP_RTCP_FB_ACK_UNKNOWN);
    4636           0 :             if (i < 0) {
    4637           0 :                 sdp_parse_error(sdp_p,
    4638             :                   "%s Warning: could not parse ack type for rtcp-fb attribute",
    4639           0 :                   sdp_p->debug_str);
    4640           0 :                 sdp_p->conf_p->num_invalid_param++;
    4641           0 :                 return SDP_INVALID_PARAMETER;
    4642             :             }
    4643           0 :             rtcp_fb_p->param.ack = (sdp_rtcp_fb_ack_type_e) i;
    4644           0 :             break;
    4645             : 
    4646             :         case SDP_RTCP_FB_CCM:
    4647           0 :             i = find_token_enum("rtcp-fb ccm type", sdp_p, &ptr,
    4648             :                                 sdp_rtcp_fb_ccm_type_val,
    4649             :                                 SDP_MAX_RTCP_FB_CCM, SDP_RTCP_FB_CCM_UNKNOWN);
    4650           0 :             if (i < 0) {
    4651           0 :                 sdp_parse_error(sdp_p,
    4652             :                   "%s Warning: could not parse ccm type for rtcp-fb attribute",
    4653           0 :                   sdp_p->debug_str);
    4654           0 :                 sdp_p->conf_p->num_invalid_param++;
    4655           0 :                 return SDP_INVALID_PARAMETER;
    4656             :             }
    4657           0 :             rtcp_fb_p->param.ccm = (sdp_rtcp_fb_ccm_type_e) i;
    4658             : 
    4659             :             /* TODO -- We don't currently parse tmmbr parameters or vbcm
    4660             :                submessage types. If we decide to support these modes of
    4661             :                operation, we probably want to add parsing code for them.
    4662             :                For the time being, they'll just end up parsed into "extra"
    4663             :                Bug 1097169.
    4664             :             */
    4665           0 :             break;
    4666             : 
    4667             :         case SDP_RTCP_FB_NACK:
    4668             :             /* Skip any remaining WS -- see
    4669             :                http://code.google.com/p/webrtc/issues/detail?id=1922 */
    4670           0 :             while (*ptr == ' ' || *ptr == '\t') {
    4671           0 :                 ptr++;
    4672             :             }
    4673             :             /* Check for empty string */
    4674           0 :             if (*ptr == '\r') {
    4675           0 :                 rtcp_fb_p->param.nack = SDP_RTCP_FB_NACK_BASIC;
    4676           0 :                 break;
    4677             :             }
    4678           0 :             i = find_token_enum("rtcp-fb nack type", sdp_p, &ptr,
    4679             :                                 sdp_rtcp_fb_nack_type_val,
    4680             :                                 SDP_MAX_RTCP_FB_NACK, SDP_RTCP_FB_NACK_UNKNOWN);
    4681           0 :             if (i < 0) {
    4682           0 :                 sdp_parse_error(sdp_p,
    4683             :                   "%s Warning: could not parse nack type for rtcp-fb attribute",
    4684           0 :                   sdp_p->debug_str);
    4685           0 :                 sdp_p->conf_p->num_invalid_param++;
    4686           0 :                 return SDP_INVALID_PARAMETER;
    4687             :             }
    4688           0 :             rtcp_fb_p->param.nack = (sdp_rtcp_fb_nack_type_e) i;
    4689           0 :             break;
    4690             : 
    4691             :         case SDP_RTCP_FB_TRR_INT:
    4692           0 :             rtcp_fb_p->param.trr_int = sdp_getnextnumtok(ptr, &ptr,
    4693             :                                                          " \t", &result);
    4694           0 :             if (result != SDP_SUCCESS) {
    4695           0 :                 sdp_parse_error(sdp_p,
    4696             :                   "%s Warning: could not parse trr-int value for rtcp-fb "
    4697           0 :                   "attribute", sdp_p->debug_str);
    4698           0 :                 sdp_p->conf_p->num_invalid_param++;
    4699           0 :                 return SDP_INVALID_PARAMETER;
    4700             :             }
    4701           0 :             break;
    4702             : 
    4703             :         case SDP_RTCP_FB_REMB:
    4704             :             /* No additional tokens to parse after goog-remb */
    4705           0 :             break;
    4706             : 
    4707             :         case SDP_RTCP_FB_UNKNOWN:
    4708             :             /* Handled by "extra", below */
    4709           0 :             break;
    4710             : 
    4711             :         default:
    4712             :             /* This is an internal error, not a parsing error */
    4713           0 :             CSFLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
    4714             :                         sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type);
    4715           0 :             return SDP_FAILURE;
    4716             :     }
    4717             : 
    4718             :     /* Skip any remaining WS  */
    4719           0 :     while (*ptr == ' ' || *ptr == '\t') {
    4720           0 :         ptr++;
    4721             :     }
    4722             : 
    4723             :     /* Just store the rest of the line in "extra" -- this will return
    4724             :        a failure result if there is no more text, but that's fine. */
    4725           0 :     ptr = sdp_getnextstrtok(ptr, rtcp_fb_p->extra,
    4726             :                             sizeof(rtcp_fb_p->extra), "\r\n", &result);
    4727             : 
    4728           0 :     return SDP_SUCCESS;
    4729             : }
    4730             : 
    4731           0 : sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
    4732             :                                   sdp_attr_t *attr_p,
    4733             :                                   flex_string *fs)
    4734             : {
    4735           0 :     switch (attr_p->attr.setup) {
    4736             :     case SDP_SETUP_ACTIVE:
    4737             :     case SDP_SETUP_PASSIVE:
    4738             :     case SDP_SETUP_ACTPASS:
    4739             :     case SDP_SETUP_HOLDCONN:
    4740           0 :         flex_string_sprintf(fs, "a=%s:%s\r\n",
    4741           0 :             sdp_attr[attr_p->type].name,
    4742           0 :             sdp_setup_type_val[attr_p->attr.setup].name);
    4743           0 :         break;
    4744             :     default:
    4745           0 :         CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
    4746             :                     sdp_p->debug_str, attr_p->attr.setup);
    4747           0 :         return SDP_FAILURE;
    4748             :     }
    4749             : 
    4750           0 :     return SDP_SUCCESS;
    4751             : }
    4752             : 
    4753           0 : sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
    4754             :                                    sdp_attr_t *attr_p,
    4755             :                                    const char *ptr)
    4756             : {
    4757           0 :     int i = find_token_enum("setup attribute", sdp_p, &ptr,
    4758             :         sdp_setup_type_val,
    4759             :         SDP_MAX_SETUP, SDP_SETUP_UNKNOWN);
    4760             : 
    4761           0 :     if (i < 0) {
    4762           0 :         sdp_parse_error(sdp_p,
    4763             :           "%s Warning: could not parse setup attribute",
    4764           0 :           sdp_p->debug_str);
    4765           0 :         sdp_p->conf_p->num_invalid_param++;
    4766           0 :         return SDP_INVALID_PARAMETER;
    4767             :     }
    4768             : 
    4769           0 :     attr_p->attr.setup = (sdp_setup_type_e) i;
    4770             : 
    4771           0 :     switch (attr_p->attr.setup) {
    4772             :     case SDP_SETUP_ACTIVE:
    4773             :     case SDP_SETUP_PASSIVE:
    4774             :     case SDP_SETUP_ACTPASS:
    4775             :     case SDP_SETUP_HOLDCONN:
    4776             :         /* All these values are OK */
    4777           0 :         break;
    4778             :     case SDP_SETUP_UNKNOWN:
    4779           0 :         sdp_parse_error(sdp_p,
    4780             :             "%s Warning: Unknown setup attribute",
    4781           0 :             sdp_p->debug_str);
    4782           0 :         return SDP_INVALID_PARAMETER;
    4783             :     default:
    4784             :         /* This is an internal error, not a parsing error */
    4785           0 :         CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
    4786             :                     sdp_p->debug_str, attr_p->attr.setup);
    4787           0 :         return SDP_FAILURE;
    4788             :     }
    4789             : 
    4790           0 :     return SDP_SUCCESS;
    4791             : }
    4792             : 
    4793           0 : sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
    4794             :                                        sdp_attr_t *attr_p,
    4795             :                                        flex_string *fs)
    4796             : {
    4797           0 :     switch (attr_p->attr.connection) {
    4798             :     case SDP_CONNECTION_NEW:
    4799             :     case SDP_CONNECTION_EXISTING:
    4800           0 :         flex_string_sprintf(fs, "a=%s:%s\r\n",
    4801           0 :             sdp_attr[attr_p->type].name,
    4802           0 :             sdp_connection_type_val[attr_p->attr.connection].name);
    4803           0 :         break;
    4804             :     default:
    4805           0 :         CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
    4806             :                     sdp_p->debug_str, attr_p->attr.connection);
    4807           0 :         return SDP_FAILURE;
    4808             :     }
    4809             : 
    4810           0 :     return SDP_SUCCESS;
    4811             : }
    4812             : 
    4813           0 : sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
    4814             :                                        sdp_attr_t *attr_p,
    4815             :                                        const char *ptr)
    4816             : {
    4817           0 :     int i = find_token_enum("connection attribute", sdp_p, &ptr,
    4818             :         sdp_connection_type_val,
    4819             :         SDP_MAX_CONNECTION, SDP_CONNECTION_UNKNOWN);
    4820             : 
    4821           0 :     if (i < 0) {
    4822           0 :         sdp_parse_error(sdp_p,
    4823             :           "%s Warning: could not parse connection attribute",
    4824           0 :           sdp_p->debug_str);
    4825           0 :         sdp_p->conf_p->num_invalid_param++;
    4826           0 :         return SDP_INVALID_PARAMETER;
    4827             :     }
    4828             : 
    4829           0 :     attr_p->attr.connection = (sdp_connection_type_e) i;
    4830             : 
    4831           0 :     switch (attr_p->attr.connection) {
    4832             :     case SDP_CONNECTION_NEW:
    4833             :     case SDP_CONNECTION_EXISTING:
    4834             :         /* All these values are OK */
    4835           0 :         break;
    4836             :     case SDP_CONNECTION_UNKNOWN:
    4837           0 :         sdp_parse_error(sdp_p,
    4838             :             "%s Warning: Unknown connection attribute",
    4839           0 :             sdp_p->debug_str);
    4840           0 :         return SDP_INVALID_PARAMETER;
    4841             :     default:
    4842             :         /* This is an internal error, not a parsing error */
    4843           0 :         CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
    4844             :                     sdp_p->debug_str, attr_p->attr.connection);
    4845           0 :         return SDP_FAILURE;
    4846             :     }
    4847           0 :     return SDP_SUCCESS;
    4848             : }
    4849             : 
    4850           0 : sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
    4851             :                                        sdp_attr_t *attr_p,
    4852             :                                        flex_string *fs)
    4853             : {
    4854           0 :     flex_string_sprintf(fs, "a=extmap:%d %s\r\n",
    4855           0 :         attr_p->attr.extmap.id,
    4856           0 :         attr_p->attr.extmap.uri);
    4857             : 
    4858           0 :     return SDP_SUCCESS;
    4859             : }
    4860             : 
    4861           0 : sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
    4862             :                                    sdp_attr_t *attr_p,
    4863             :                                    const char *ptr)
    4864             : {
    4865             :     sdp_result_e  result;
    4866             : 
    4867           0 :     attr_p->attr.extmap.id = 0;
    4868           0 :     attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
    4869           0 :     attr_p->attr.extmap.media_direction_specified = FALSE;
    4870           0 :     attr_p->attr.extmap.uri[0] = '\0';
    4871           0 :     attr_p->attr.extmap.extension_attributes[0] = '\0';
    4872             : 
    4873             :     /* Find the payload type number. */
    4874           0 :     attr_p->attr.extmap.id =
    4875           0 :     (uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
    4876           0 :     if (result != SDP_SUCCESS) {
    4877           0 :         sdp_parse_error(sdp_p,
    4878             :             "%s Warning: Invalid extmap id specified for %s attribute.",
    4879           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    4880           0 :         sdp_p->conf_p->num_invalid_param++;
    4881           0 :         return (SDP_INVALID_PARAMETER);
    4882             :     }
    4883             : 
    4884           0 :     if (*ptr == '/') {
    4885             :         char direction[SDP_MAX_STRING_LEN+1];
    4886           0 :         ++ptr; /* Skip over '/' */
    4887           0 :         ptr = sdp_getnextstrtok(ptr, direction,
    4888             :                                 sizeof(direction), " \t", &result);
    4889           0 :         if (result != SDP_SUCCESS) {
    4890           0 :             sdp_parse_error(sdp_p,
    4891             :                 "%s Warning: Invalid direction specified in %s attribute.",
    4892           0 :                 sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    4893           0 :             sdp_p->conf_p->num_invalid_param++;
    4894           0 :             return (SDP_INVALID_PARAMETER);
    4895             :         }
    4896             : 
    4897           0 :         if (!cpr_strcasecmp(direction, "sendrecv")) {
    4898           0 :           attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
    4899           0 :         } else if (!cpr_strcasecmp(direction, "sendonly")) {
    4900           0 :           attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDONLY;
    4901           0 :         } else if (!cpr_strcasecmp(direction, "recvonly")) {
    4902           0 :           attr_p->attr.extmap.media_direction = SDP_DIRECTION_RECVONLY;
    4903           0 :         } else if (!cpr_strcasecmp(direction, "inactive")) {
    4904           0 :           attr_p->attr.extmap.media_direction = SDP_DIRECTION_INACTIVE;
    4905             :         } else {
    4906           0 :             sdp_parse_error(sdp_p,
    4907             :                 "%s Warning: Invalid direction specified in %s attribute.",
    4908           0 :                 sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    4909           0 :             sdp_p->conf_p->num_invalid_param++;
    4910           0 :             return (SDP_INVALID_PARAMETER);
    4911             :         }
    4912           0 :         attr_p->attr.extmap.media_direction_specified = TRUE;
    4913             :     }
    4914             : 
    4915           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.uri,
    4916             :                             sizeof(attr_p->attr.extmap.uri), " \t", &result);
    4917           0 :     if (result != SDP_SUCCESS) {
    4918           0 :         sdp_parse_error(sdp_p,
    4919             :             "%s Warning: No uri specified in %s attribute.",
    4920           0 :             sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
    4921           0 :         sdp_p->conf_p->num_invalid_param++;
    4922           0 :         return (SDP_INVALID_PARAMETER);
    4923             :     }
    4924             : 
    4925           0 :     while (*ptr == ' ' || *ptr == '\t') {
    4926           0 :       ++ptr;
    4927             :     }
    4928             : 
    4929             :     /* Grab everything that follows, even if it contains whitespace */
    4930           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.extension_attributes,
    4931             :                             sizeof(attr_p->attr.extmap.extension_attributes), "\r\n", &result);
    4932             : 
    4933           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    4934           0 :         SDP_PRINT("%s Parsed a=%s, id %u, direction %s, "
    4935             :                   "uri %s, extension %s", sdp_p->debug_str,
    4936             :                   sdp_get_attr_name(attr_p->type),
    4937             :                   attr_p->attr.extmap.id,
    4938             :                   SDP_DIRECTION_PRINT(attr_p->attr.extmap.media_direction),
    4939             :                   attr_p->attr.extmap.uri,
    4940             :                   attr_p->attr.extmap.extension_attributes);
    4941             :     }
    4942             : 
    4943           0 :     return (SDP_SUCCESS);
    4944             : }
    4945             : 
    4946           0 : sdp_result_e sdp_parse_attr_msid(sdp_t *sdp_p,
    4947             :                                  sdp_attr_t *attr_p,
    4948             :                                  const char *ptr)
    4949             : {
    4950             :     sdp_result_e result;
    4951             : 
    4952           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.identifier,
    4953             :                             sizeof(attr_p->attr.msid.identifier), " \t", &result);
    4954           0 :     if (result != SDP_SUCCESS) {
    4955           0 :         sdp_parse_error(sdp_p, "%s Warning: Bad msid identity value",
    4956           0 :                         sdp_p->debug_str);
    4957           0 :         sdp_p->conf_p->num_invalid_param++;
    4958           0 :         return SDP_INVALID_PARAMETER;
    4959             :     }
    4960             : 
    4961           0 :     ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.appdata,
    4962             :                             sizeof(attr_p->attr.msid.appdata), " \t", &result);
    4963           0 :     if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
    4964           0 :         sdp_parse_error(sdp_p, "%s Warning: Bad msid appdata value",
    4965           0 :                         sdp_p->debug_str);
    4966           0 :         sdp_p->conf_p->num_invalid_param++;
    4967           0 :         return SDP_INVALID_PARAMETER;
    4968             :     }
    4969           0 :     if (result == SDP_EMPTY_TOKEN) {
    4970           0 :         attr_p->attr.msid.appdata[0] = '\0';
    4971             :     }
    4972             : 
    4973           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    4974           0 :         SDP_PRINT("%s Parsed a=msid, %s %s", sdp_p->debug_str,
    4975             :                   attr_p->attr.msid.identifier, attr_p->attr.msid.appdata);
    4976             :     }
    4977             : 
    4978           0 :     return SDP_SUCCESS;
    4979             : }
    4980             : 
    4981             : 
    4982           0 : sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p,
    4983             :                                  sdp_attr_t *attr_p,
    4984             :                                  flex_string *fs)
    4985             : {
    4986           0 :     flex_string_sprintf(fs, "a=msid:%s%s%s\r\n",
    4987           0 :                         attr_p->attr.msid.identifier,
    4988           0 :                         attr_p->attr.msid.appdata[0] ? " " : "",
    4989           0 :                         attr_p->attr.msid.appdata);
    4990           0 :     return SDP_SUCCESS;
    4991             : }
    4992             : 
    4993           0 : sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p,
    4994             :                                           sdp_attr_t *attr_p,
    4995             :                                           const char *ptr)
    4996             : {
    4997             :     sdp_result_e result;
    4998             :     int i;
    4999             : 
    5000           0 :     ptr = sdp_getnextstrtok(ptr,
    5001           0 :                             attr_p->attr.msid_semantic.semantic,
    5002             :                             sizeof(attr_p->attr.msid_semantic.semantic),
    5003             :                             " \t",
    5004             :                             &result);
    5005             : 
    5006           0 :     if (result != SDP_SUCCESS) {
    5007           0 :         sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute; "
    5008             :                         "missing semantic",
    5009           0 :                         sdp_p->debug_str);
    5010           0 :         sdp_p->conf_p->num_invalid_param++;
    5011           0 :         return SDP_INVALID_PARAMETER;
    5012             :     }
    5013             : 
    5014           0 :     for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
    5015             :       /* msid-id can be up to 64 characters long, plus null terminator */
    5016             :       char temp[65];
    5017           0 :       ptr = sdp_getnextstrtok(ptr, temp, sizeof(temp), " \t", &result);
    5018             : 
    5019           0 :       if (result != SDP_SUCCESS) {
    5020           0 :         break;
    5021             :       }
    5022             : 
    5023           0 :       attr_p->attr.msid_semantic.msids[i] = cpr_strdup(temp);
    5024             :     }
    5025             : 
    5026           0 :     if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
    5027           0 :         sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute",
    5028           0 :                         sdp_p->debug_str);
    5029           0 :         sdp_p->conf_p->num_invalid_param++;
    5030           0 :         return SDP_INVALID_PARAMETER;
    5031             :     }
    5032             : 
    5033           0 :     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
    5034           0 :         SDP_PRINT("%s Parsed a=msid-semantic, %s", sdp_p->debug_str,
    5035             :                   attr_p->attr.msid_semantic.semantic);
    5036           0 :         for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
    5037           0 :           if (!attr_p->attr.msid_semantic.msids[i]) {
    5038           0 :             break;
    5039             :           }
    5040             : 
    5041           0 :           SDP_PRINT("%s ... msid %s", sdp_p->debug_str,
    5042             :                     attr_p->attr.msid_semantic.msids[i]);
    5043             :         }
    5044             :     }
    5045             : 
    5046           0 :     return SDP_SUCCESS;
    5047             : }
    5048             : 
    5049             : 
    5050           0 : sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p,
    5051             :                                           sdp_attr_t *attr_p,
    5052             :                                           flex_string *fs)
    5053             : {
    5054             :     int i;
    5055           0 :     flex_string_sprintf(fs, "a=msid-semantic:%s",
    5056           0 :                         attr_p->attr.msid_semantic.semantic);
    5057           0 :     for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
    5058           0 :         if (!attr_p->attr.msid_semantic.msids[i]) {
    5059           0 :             break;
    5060             :         }
    5061             : 
    5062           0 :         flex_string_sprintf(fs, " %s",
    5063             :                             attr_p->attr.msid_semantic.msids[i]);
    5064             :     }
    5065           0 :     flex_string_sprintf(fs, "\r\n");
    5066           0 :     return SDP_SUCCESS;
    5067             : }
    5068             : 
    5069           0 : sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p,
    5070             :                                  sdp_attr_t *attr_p,
    5071             :                                  const char *ptr)
    5072             : {
    5073             :     sdp_result_e result;
    5074             : 
    5075           0 :     attr_p->attr.ssrc.ssrc =
    5076           0 :         (uint32_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
    5077             : 
    5078           0 :     if (result != SDP_SUCCESS) {
    5079           0 :         sdp_parse_error(sdp_p, "%s Warning: Bad ssrc attribute, cannot parse ssrc",
    5080           0 :                         sdp_p->debug_str);
    5081           0 :         sdp_p->conf_p->num_invalid_param++;
    5082           0 :         return SDP_INVALID_PARAMETER;
    5083             :     }
    5084             : 
    5085             :     /* Skip any remaining WS  */
    5086           0 :     while (*ptr == ' ' || *ptr == '\t') {
    5087           0 :         ptr++;
    5088             :     }
    5089             : 
    5090             :     /* Just store the rest of the line in "attribute" -- this will return
    5091             :        a failure result if there is no more text, but that's fine. */
    5092           0 :     ptr = sdp_getnextstrtok(ptr,
    5093           0 :                             attr_p->attr.ssrc.attribute,
    5094             :                             sizeof(attr_p->attr.ssrc.attribute),
    5095             :                             "\r\n",
    5096             :                             &result);
    5097             : 
    5098           0 :     return SDP_SUCCESS;
    5099             : }
    5100             : 
    5101             : 
    5102           0 : sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p,
    5103             :                                  sdp_attr_t *attr_p,
    5104             :                                  flex_string *fs)
    5105             : {
    5106           0 :     flex_string_sprintf(fs, "a=ssrc:%s%s%s\r\n",
    5107             :                         attr_p->attr.ssrc.ssrc,
    5108           0 :                         attr_p->attr.ssrc.attribute[0] ? " " : "",
    5109           0 :                         attr_p->attr.ssrc.attribute);
    5110           0 :     return SDP_SUCCESS;
    5111             : }

Generated by: LCOV version 1.13