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