blob: e2be94b5bbf240347d8f0fe4d5ab881041449f86 [file] [log] [blame]
Harald Welteb0d93602018-03-20 18:09:34 +01001module SIP_Templates {
2
3import from SIPmsg_Types all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02004import from TCCConversion_Functions all;
5import from TCCOpenSecurity_Functions all;
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02006import from TCCDateTime_Functions all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02007import from Native_Functions all;
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01008import from Osmocom_Types all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02009import from Misc_Helpers all;
Harald Welteb0d93602018-03-20 18:09:34 +010010
11/* wrapper type to encapsulate the Addr_Union + parameter list used in From, To. ... */
12type record SipAddr {
13 Addr_Union addr,
14 SemicolonParam_List params optional
15}
16
17const charstring c_SIP_VERSION := "SIP/2.0";
18
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020019template (value) GenericParam ts_Param(template (value) charstring id,
20 template (omit) charstring paramValue := omit) := {
21 id := id,
22 paramValue := paramValue
23}
24template (present) GenericParam tr_Param(template (present) charstring id := ?,
25 template charstring paramValue := *) := {
26 id := id,
27 paramValue := paramValue
28}
29function f_ts_Param_omit(template (value) charstring id,
30 template (omit) charstring paramValue := omit)
31 return template (omit) GenericParam
32{
33 if (istemplatekind(paramValue, "omit")) {
34 return omit;
35 }
36 return ts_Param(id, paramValue);
37}
38
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010039template (value) SipUrl ts_SipUrl(template (value) HostPort host_port,
40 template (omit) UserInfo user_info := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +010041 scheme := "sip",
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010042 userInfo := user_info,
43 hostPort := host_port,
Harald Welteb0d93602018-03-20 18:09:34 +010044 urlParameters := omit,
45 headers := omit
46}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010047template (present) SipUrl tr_SipUrl(template (present) HostPort host_port := ?,
48 template UserInfo user_info := *) := {
Harald Welteb0d93602018-03-20 18:09:34 +010049 scheme := "sip",
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010050 userInfo := user_info,
51 hostPort := host_port,
Harald Welteb0d93602018-03-20 18:09:34 +010052 urlParameters := *,
53 headers := *
54}
55
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020056template (value) SipUrl ts_SipUrlHost(template (value) charstring host,
57 template (omit) integer portField := omit)
58 := ts_SipUrl(ts_HostPort(host, portField));
59
60function ts_SipUrl_from_Addr_Union(template (value) Addr_Union au)
61return template (value) SipUrl {
62 if (ischosen(au.nameAddr)) {
63 return au.nameAddr.addrSpec;
64 } else { /* au.addrSpecUnion */
65 return au.addrSpecUnion;
66 }
67}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010068
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +020069// [20.5]
70template (present) Allow tr_Allow(template Method_List methods := *) := {
71 fieldName := ALLOW_E,
72 methods := methods
73}
74template (value) Allow ts_Allow(template (omit) Method_List methods := omit) := {
75 fieldName := ALLOW_E,
76 methods := methods
77}
78
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020079template (value) Credentials ts_Credentials_DigestResponse(template (value) CommaParam_List digestResponse) := {
80 digestResponse := digestResponse
81}
82
83template (value) Credentials ts_Credentials_DigestResponseMD5(
84 template (value) charstring username,
85 template (value) charstring realm,
86 template (value) charstring nonce,
87 template (value) charstring uri,
88 template (value) charstring response,
89 template (value) charstring opaque,
90 template (value) charstring algorithm := "MD5",
91 template (value) charstring qop := "auth",
92 template (omit) charstring cnonce := omit,
93 template (omit) charstring nc := omit
94 ) := {
95 digestResponse := {
96 // Already added by digestResponse automatically:
97 //ts_Param("Digest", omit),
98 ts_Param("username", f_sip_str_quote(username)),
99 ts_Param("realm", f_sip_str_quote(realm)),
100 ts_Param("nonce", f_sip_str_quote(nonce)),
101 ts_Param("uri", f_sip_str_quote(uri)),
102 ts_Param("response", f_sip_str_quote(response)),
103 ts_Param("opaque", f_sip_str_quote(opaque)),
104 ts_Param("algorithm", algorithm),
105 ts_Param("qop", qop),
106 // FIXME: If "omit" is passed, these below end up in;
107 // "Dynamic test case error: Performing a valueof or send operation on a non-specific template of type @SIPmsg_Types.GenericParam"
108 f_ts_Param_omit("cnonce", f_sip_str_quote(cnonce)),
109 f_ts_Param_omit("nc", nc)
110 }
111}
112
113template (value) Credentials ts_Credentials_OtherAuth(template (value) OtherAuth otherResponse) := {
114 otherResponse := otherResponse
115}
116
117template (value) Authorization ts_Authorization(template (value) Credentials body) := {
118 fieldName := AUTHORIZATION_E,
119 body := body
120}
121
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100122// [20.10]
123template (present) NameAddr tr_NameAddr(template (present) SipUrl addrSpec := ?,
124 template charstring displayName := *) := {
125 displayName := displayName,
126 addrSpec := addrSpec
Harald Welteb0d93602018-03-20 18:09:34 +0100127}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100128template (value) NameAddr ts_NameAddr(template (value) SipUrl addrSpec,
129 template (omit) charstring displayName := omit) := {
130 displayName := displayName,
131 addrSpec := addrSpec
132}
133
134template (present) Addr_Union tr_Addr_Union_NameAddr(template (present) NameAddr nameAddr := ?) := {
135 nameAddr := nameAddr
136}
137template (value) Addr_Union ts_Addr_Union_NameAddr(template (value) NameAddr nameAddr) := {
138 nameAddr := nameAddr
139}
140
141template (present) Addr_Union tr_Addr_Union_SipUrl(template (present) SipUrl sipUrl := ?) := {
142 addrSpecUnion := sipUrl
143}
144template (value) Addr_Union ts_Addr_Union_SipUrl(template (value) SipUrl sipUrl) := {
145 addrSpecUnion := sipUrl
146}
147
148
149template (present) ContactAddress tr_ContactAddress(template (present) Addr_Union addressField := ?,
150 template SemicolonParam_List contactParams := *) := {
151 addressField := addressField,
152 contactParams := contactParams
153}
154template (value) ContactAddress ts_ContactAddress(template (value) Addr_Union addressField,
155 template (omit) SemicolonParam_List contactParams := omit) := {
156 addressField := addressField,
157 contactParams := contactParams
158}
159
160template (present) Contact tr_Contact(template (present) ContactAddress_List contactAddresses := ?) := {
161 fieldName := CONTACT_E,
162 contactBody := {
163 contactAddresses := contactAddresses
164 }
165}
166template (value) Contact ts_Contact(template (value) ContactAddress_List contactAddresses) := {
167 fieldName := CONTACT_E,
168 contactBody := {
169 contactAddresses := contactAddresses
170 }
171}
172
173template (value) Contact ts_ContactWildcard := {
174 fieldName := CONTACT_E,
175 contactBody := {
176 wildcard := "*"
177 }
178}
179
180template (present) Contact tr_Contact_SipAddr(template (present) SipAddr contact_addr := ?)
181 := tr_Contact({ tr_ContactAddress(contact_addr.addr, contact_addr.params) });
182
183private function f_tr_Contact_SipAddr(template SipAddr contact_addr) return template Contact
184{
185 if (istemplatekind(contact_addr, "omit")) {
186 return omit;
187 } else if (istemplatekind(contact_addr, "*")) {
188 return *;
189 }
190 return tr_Contact_SipAddr(contact_addr);
191}
192
193template (value) Contact ts_Contact_SipAddr(template (value) SipAddr contact_addr)
194 := ts_Contact({ ts_ContactAddress(contact_addr.addr, contact_addr.params) });
195private function ts_Contact_SipAddr_omit(template (omit) SipAddr contact_addr := omit) return template (omit) Contact
196{
197 if (istemplatekind(contact_addr, "omit")) {
198 return omit;
199 }
200 return ts_Contact_SipAddr(contact_addr);
201}
202
203
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200204// [20.14]
205template (value) ContentLength ts_ContentLength(template (value) integer len := 0) := {
206 fieldName := CONTENT_LENGTH_E,
207 len := len
208}
209template (present) ContentLength tr_ContentLength(template (present) integer len := ?) := {
210 fieldName := CONTENT_LENGTH_E,
211 len := len
212}
213
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100214// [20.19]
215template (value) Expires ts_Expires(template (value) DeltaSec deltaSec := "7200") := {
216 fieldName := EXPIRES_E,
217 deltaSec := deltaSec
218}
219
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200220
221// [20.32]
222template (value) Require ts_Require(template (value) OptionTag_List optionsTags := {}) := {
223 fieldName := REQUIRE_E,
224 optionsTags := optionsTags
225}
226template (present) Require tr_Require(template (present) OptionTag_List optionsTags := ?) := {
227 fieldName := REQUIRE_E,
228 optionsTags := optionsTags
229}
230
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200231// [20.35 RFC2616 14.38]
232template (value) Server ts_Server(template (value) ServerVal_List serverBody := {}) := {
233 fieldName := SERVER_E,
234 serverBody := serverBody
235}
236template (present) Server tr_Server(template (present) ServerVal_List serverBody := ?) := {
237 fieldName := SERVER_E,
238 serverBody := serverBody
239}
240
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200241// [20.37]
242template (value) Supported ts_Supported(template (value) OptionTag_List optionsTags := {}) := {
243 fieldName := SUPPORTED_E,
244 optionsTags := optionsTags
245}
246template (present) Supported tr_Supported(template (present) OptionTag_List optionsTags := ?) := {
247 fieldName := SUPPORTED_E,
248 optionsTags := optionsTags
249}
250
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200251// [20.41 RFC2616 14.43]
252template (value) UserAgent ts_UserAgent(template (value) ServerVal_List userAgentBody := {}) := {
253 fieldName := USER_AGENT_E,
254 userAgentBody := userAgentBody
255}
256template (present) UserAgent tr_UserAgent(template (present) ServerVal_List userAgentBody := ?) := {
257 fieldName := USER_AGENT_E,
258 userAgentBody := userAgentBody
259}
260
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200261
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100262template (value) SipAddr ts_SipAddr(template (value) HostPort host_port,
263 template (omit) UserInfo user_info := omit,
264 template (omit) charstring displayName := omit,
265 template (omit) SemicolonParam_List params := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100266 addr := {
267 nameAddr := {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100268 displayName := displayName,
269 addrSpec := ts_SipUrl(host_port, user_info)
Harald Welteb0d93602018-03-20 18:09:34 +0100270 }
271 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100272 params := params
273}
274template (present) SipAddr tr_SipAddr(template (present) HostPort host_port := ?,
275 template UserInfo user_info := *,
276 template charstring displayName := *,
277 template SemicolonParam_List params := *) := {
278 addr := {
279 nameAddr := {
280 displayName := displayName,
281 addrSpec := tr_SipUrl(host_port, user_info)
282 }
283 },
284 params := params
Harald Welteb0d93602018-03-20 18:09:34 +0100285}
286
287/* build a receive template from a value: substitute '*' for omit */
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200288function tr_SipUrl_from_val(template (value) SipUrl tin) return template (present) SipUrl {
289 var template (present) SipUrl ret := tin;
290
291 /* if the port number is 5060, it may be omitted */
292 if (ispresent(tin.hostPort.portField) and
293 valueof(tin.hostPort.portField) == 5060) {
294 ret.hostPort.portField := 5060 ifpresent;
295 }
296 if (not ispresent(tin.userInfo.password)) {
297 ret.userInfo.password := *;
298 }
299
300 return ret;
301}
302function tr_SipAddr_from_val(template (value) SipAddr tin) return template (present) SipAddr {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100303 var template (present) SipAddr ret := tin;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200304
305 if (not ispresent(tin.addr.nameAddr.displayName)) {
Harald Welteb0d93602018-03-20 18:09:34 +0100306 ret.addr.nameAddr.displayName := *;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200307 } else if (f_str_tolower(f_sip_str_unquote(tin.addr.nameAddr.displayName)) == "anonymous") {
308 /* if the user is Anonymous, it may be omitted */
309 ret.addr.nameAddr.displayName := tin.addr.nameAddr.displayName ifpresent;
Harald Welteb0d93602018-03-20 18:09:34 +0100310 }
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200311
312 ret.addr.nameAddr.addrSpec := tr_SipUrl_from_val(tin.addr.nameAddr.addrSpec);
313
314 if (not ispresent(tin.params)) {
Harald Welteb0d93602018-03-20 18:09:34 +0100315 ret.params := *;
316 }
317 return ret;
318}
319
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200320function ts_SipAddr_from_Addr_Union(template (value) Addr_Union au,
321 template (omit) SemicolonParam_List params := omit)
322return template (value) SipAddr {
323 var template (value) SipUrl addrSpec := ts_SipUrl_from_Addr_Union(au);
324 var template (omit) charstring displayName;
325
326 if (ischosen(au.nameAddr)) {
327 displayName := au.nameAddr.displayName;
328 } else { /* au.addrSpecUnion */
329 displayName := omit
330 }
331
332 return ts_SipAddr(addrSpec.hostPort,
333 addrSpec.userInfo,
334 displayName,
335 params);
336}
337
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100338template (value) HostPort ts_HostPort(template (omit) charstring host := omit,
339 template (omit) integer portField := omit) := {
340 host := host,
341 portField := portField
342}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200343
344template (present) HostPort tr_HostPort(template charstring host := *,
345 template integer portField := *) := {
346 host := host,
347 portField := portField
348}
349function f_tr_HostPort(template charstring host := *,
350 template integer portField := *)
351return template (present) HostPort {
352 return f_tr_HostPort_opt_defport(tr_HostPort(host, portField));
353}
354function f_tr_HostPort_opt_defport(template (present) HostPort hp) return template (present) HostPort {
355 var template (present) HostPort hpout := hp;
Harald Welteb0d93602018-03-20 18:09:34 +0100356 /* if the port number is 5060, it may be omitted */
357 if (isvalue(hp.portField) and valueof(hp.portField) == 5060) {
358 hpout.portField := 5060 ifpresent;
359 }
360 return hpout;
361}
362
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200363function f_tr_SipUrl_opt_defport(template (present) SipUrl url) return template (present) SipUrl {
364 var template (present) SipUrl urlout := url;
365 urlout.hostPort := f_tr_HostPort_opt_defport(url.hostPort);
366 return urlout;
367}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100368
369template (value) UserInfo ts_UserInfo(template (value) charstring userOrTelephoneSubscriber,
370 template (omit) charstring password := omit) := {
371 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
372 password := password
373}
374template (present) UserInfo tr_UserInfo(template (present) charstring userOrTelephoneSubscriber := ?,
375 template charstring password := *) := {
376 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
377 password := password
378}
379
380template (value) RequestLine ts_SIP_ReqLine(Method method,
381 template (value) SipUrl uri,
Harald Welteb0d93602018-03-20 18:09:34 +0100382 charstring ver := c_SIP_VERSION) := {
383 method := method,
384 requestUri := uri,
385 sipVersion := ver
386}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100387template (present) RequestLine tr_SIP_ReqLine(template (present) Method method := ?,
388 template (present) SipUrl uri := ?,
389 template (present) charstring ver := c_SIP_VERSION) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100390 method := method,
391 requestUri := uri,
392 sipVersion := ver
393}
394
395template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := {
396 sipVersion := "SIP/2.0",
397 statusCode := status_code,
398 reasonPhrase := reason
399}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100400template (present) StatusLine tr_SIP_StatusLine(template integer status_code,
401 template charstring reason) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100402 sipVersion := "SIP/2.0",
403 statusCode := status_code,
404 reasonPhrase := reason
405}
406
407
408template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := {
409 requestLine := rl,
410 msgHeader := c_SIP_msgHeader_empty,
411 messageBody := omit,
412 payload := omit
413}
414
415const Method_List c_SIP_defaultMethods := {
416 "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE",
417 "NOTIFY", "REFER", "UPDATE" };
418
419private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body)
420return template (omit) ContentType {
421 /* if user explicitly stated no content type */
422 if (istemplatekind(ct, "omit")) {
423 return omit;
424 }
425 /* if there's no body, then there's no content-type either */
426 if (istemplatekind(body, "omit")) {
427 return omit;
428 }
429 return ct;
430}
431
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200432private function f_ContentLength(template (omit) charstring body)
433return template (value) ContentLength {
434 /* rfc3261 20.14: "If no body is present in a message, then the
435 * Content-Length header field value MUST be set to zero." */
436 if (istemplatekind(body, "omit")) {
437 return ts_ContentLength(0);
438 }
439 return ts_ContentLength(lengthof(body));
440}
441
Harald Welteb0d93602018-03-20 18:09:34 +0100442template (value) ContentType ts_CT_SDP := {
443 fieldName := CONTENT_TYPE_E,
444 mediaType := "application/sdp"
445};
446
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200447template (value) Via ts_Via_from(template (value) HostPort addr,
448 template (value) charstring transport := "UDP") := {
Harald Welteb0d93602018-03-20 18:09:34 +0100449 fieldName := VIA_E,
450 viaBody := {
451 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200452 sentProtocol := { "SIP", "2.0", transport },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100453 sentBy := addr,
Harald Welteb0d93602018-03-20 18:09:34 +0100454 viaParams := omit
455 }
456 }
457}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100458template (present) Via tr_Via_from(template (present) HostPort host_port := ?,
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200459 template (present) charstring transport := ?,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100460 template SemicolonParam_List viaParams := *) := {
461 fieldName := VIA_E,
462 viaBody := {
463 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200464 sentProtocol := { "SIP", "2.0", ? },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100465 sentBy := host_port,
466 viaParams := viaParams
467 }
468 }
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200469}
470
471template (present) OtherAuth
472tr_OtherAuth(template (present) charstring authScheme := ?,
473 template (present) CommaParam_List authParams := ?) := {
474 authScheme := authScheme,
475 authParams := authParams
476}
477
478template (value) OtherAuth
479ts_OtherAuth(template (value) charstring authScheme,
480 template (value) CommaParam_List authParams) := {
481 authScheme := authScheme,
482 authParams := authParams
483}
484
485template (present) Challenge
486tr_Challenge_digestCln(template (present) CommaParam_List digestCln := ?) := {
487 digestCln := digestCln
488}
489
490template (value) Challenge
491ts_Challenge_digestCln(template (value) CommaParam_List digestCln) := {
492 digestCln := digestCln
493}
494
495template (present) Challenge
496tr_Challenge_otherChallenge(template (present) OtherAuth otherChallenge := ?) := {
497 otherChallenge := otherChallenge
498}
499
500template (value) Challenge
501ts_Challenge_otherChallenge(template (value) OtherAuth otherChallenge) := {
502 otherChallenge := otherChallenge
503}
504
505template (present) WwwAuthenticate
506tr_WwwAuthenticate(template (present) Challenge_list challenge := ?) := {
507 fieldName := WWW_AUTHENTICATE_E,
508 challenge := challenge
509}
510
511template (value) WwwAuthenticate
512ts_WwwAuthenticate(template (value) Challenge_list challenge) := {
513 fieldName := WWW_AUTHENTICATE_E,
514 challenge := challenge
515}
Harald Welteb0d93602018-03-20 18:09:34 +0100516
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200517// RFC3329
518template (present) Security_client
519tr_Security_client(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
520 fieldName := SECURITY_CLIENT_E,
521 sec_mechanism_list := sec_mechanism_list
522}
523template (value) Security_client
524ts_Security_client(template (value) Security_mechanism_list sec_mechanism_list) := {
525 fieldName := SECURITY_CLIENT_E,
526 sec_mechanism_list := sec_mechanism_list
527}
528
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200529template (present) Security_server
530tr_Security_server(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
531 fieldName := SECURITY_SERVER_E,
532 sec_mechanism_list := sec_mechanism_list
533}
534template (value) Security_server
535ts_Security_server(template (value) Security_mechanism_list sec_mechanism_list) := {
536 fieldName := SECURITY_SERVER_E,
537 sec_mechanism_list := sec_mechanism_list
538}
539
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200540template (present) Security_mechanism
541tr_Security_mechanism(template (present) charstring name := ?,
542 template SemicolonParam_List params := *) := {
543 mechanism_name := name,
544 mechanism_params := params
545}
546template (value) Security_mechanism
547ts_Security_mechanism(template (value) charstring name,
548 template (omit) SemicolonParam_List params := omit) := {
549 mechanism_name := name,
550 mechanism_params := params
551}
552
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100553template (value) MessageHeader ts_SIP_msgHeader_empty := c_SIP_msgHeader_empty;
554template (value) MessageHeader
555ts_SIP_msgh_std(template (value) CallidString call_id,
556 template (value) SipAddr from_addr,
557 template (value) SipAddr to_addr,
558 template (omit) Contact contact,
559 template (value) charstring method,
560 template (value) integer seq_nr,
561 template (value) Via via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200562 template (omit) ContentLength content_length := ts_ContentLength(0),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100563 template (omit) ContentType content_type := omit,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200564 template (omit)Authorization authorization := omit,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200565 template (omit) Allow allow := ts_Allow(c_SIP_defaultMethods),
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200566 template (omit) Expires expires := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200567 template (omit) Require require := omit,
568 template (omit) Security_client security_client := omit,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200569 template (omit) Security_server security_server := omit,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200570 template (omit) Server server := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200571 template (omit) Supported supported := omit,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200572 template (omit) UserAgent userAgent := ts_UserAgent({ "osmo-ttcn3-hacks/0.23" }),
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200573 template (omit) WwwAuthenticate wwwAuthenticate := omit
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100574 ) modifies ts_SIP_msgHeader_empty := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200575 allow := allow,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200576 authorization := authorization,
Harald Welteb0d93602018-03-20 18:09:34 +0100577 callId := {
578 fieldName := CALL_ID_E,
579 callid := call_id
580 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100581 contact := contact,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200582 contentLength := content_length,
Harald Welteb0d93602018-03-20 18:09:34 +0100583 contentType := content_type,
584 cSeq := {
585 fieldName := CSEQ_E,
586 seqNumber := seq_nr,
587 method := method
588 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100589 expires := expires,
Harald Welteb0d93602018-03-20 18:09:34 +0100590 fromField := {
591 fieldName := FROM_E,
592 addressField := from_addr.addr,
593 fromParams := from_addr.params
594 },
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200595 require := require,
596 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200597 security_server := security_server,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200598 server := server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200599 supported := supported,
Harald Welteb0d93602018-03-20 18:09:34 +0100600 toField := {
601 fieldName := TO_E,
602 addressField := to_addr.addr,
603 toParams := to_addr.params
604 },
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200605 userAgent := userAgent,
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200606 via := via,
607 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100608}
609
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100610template (present) MessageHeader
611tr_SIP_msgh_std(template CallidString call_id,
612 template SipAddr from_addr,
613 template SipAddr to_addr,
614 template Contact contact,
615 template (present) Via via := tr_Via_from(?),
616 template charstring method,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100617 template integer seq_nr := ?,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200618 template ContentLength content_length := *,
619 template ContentType content_type := *,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200620 template Allow allow := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200621 template Expires expires := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200622 template Require require := *,
623 template Security_client security_client := *,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200624 template Security_server security_server := *,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200625 template Server server := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200626 template Supported supported := *,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200627 template UserAgent userAgent := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200628 template WwwAuthenticate wwwAuthenticate := *
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100629 ) modifies t_SIP_msgHeader_any := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200630 allow := allow,
Harald Welteb0d93602018-03-20 18:09:34 +0100631 callId := {
632 fieldName := CALL_ID_E,
633 callid := call_id
634 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100635 contact := contact,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200636 contentLength := content_length,
Harald Welteb0d93602018-03-20 18:09:34 +0100637 contentType := content_type,
638 cSeq := {
639 fieldName := CSEQ_E,
640 seqNumber := seq_nr,
641 method := method
642 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100643 expires := expires,
Harald Welteb0d93602018-03-20 18:09:34 +0100644 fromField := {
645 fieldName := FROM_E,
646 addressField := from_addr.addr,
647 fromParams := from_addr.params
648 },
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200649 require := require,
650 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200651 security_server := security_server,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200652 server := server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200653 supported := supported,
Harald Welteb0d93602018-03-20 18:09:34 +0100654 toField := {
655 fieldName := TO_E,
656 addressField := to_addr.addr,
657 toParams := to_addr.params
658 },
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200659 userAgent := userAgent,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200660 via := via,
661 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100662}
663
664
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100665template (value) PDU_SIP_Request
666ts_SIP_REGISTER(template (value) SipUrl sip_url_host_port,
667 template (value) CallidString call_id,
668 template (value) SipAddr from_addr,
669 template (value) SipAddr to_addr,
670 template (value) Via via,
671 integer seq_nr,
672 template (omit) Contact contact,
673 template (omit) Expires expires,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200674 template (omit) Authorization authorization := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200675 template (omit) Require require := omit,
676 template (omit) Security_client security_client := omit,
677 template (omit) Supported supported := omit,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100678 template (omit) charstring body := omit) := {
679 requestLine := ts_SIP_ReqLine(REGISTER_E, sip_url_host_port),
680 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
681 "REGISTER", seq_nr, via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200682 content_length := f_ContentLength(body),
683 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200684 authorization := authorization,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200685 expires := expires,
686 require := require,
687 security_client := security_client,
688 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100689 messageBody := body,
690 payload := omit
691}
692template (present) PDU_SIP_Request
693tr_SIP_REGISTER(template (present) SipUrl sip_url_host_port := ?,
694 template (present) CallidString call_id := ?,
695 template (present) SipAddr from_addr := ?,
696 template (present) SipAddr to_addr := ?,
Pau Espin Pedrol0dd3f262024-04-25 17:04:43 +0200697 template (present) Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100698 template integer seq_nr := *,
699 template Contact contact := *,
700 template Expires expires := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200701 template Require require := *,
702 template Security_client security_client := *,
703 template Supported supported := *,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100704 template charstring body := *) := {
705 requestLine := tr_SIP_ReqLine(REGISTER_E, sip_url_host_port),
706 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200707 via, "REGISTER", seq_nr,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200708 expires := expires,
709 require := require,
710 security_client := security_client,
711 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100712 messageBody := body,
713 payload := omit
714}
715
716template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200717ts_SIP_INVITE(template (value) CallidString call_id,
718 template (value) SipAddr from_addr,
719 template (value) SipAddr to_addr,
720 template (value) Via via,
721 template (value) Contact contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100722 integer seq_nr,
723 template (omit) charstring body := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100724 requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200725 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100726 "INVITE", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200727 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200728 content_length := f_ContentLength(body),
729 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100730 messageBody := body,
731 payload := omit
732}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100733template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200734tr_SIP_INVITE(template (present) SipUrl uri,
735 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100736 template SipAddr from_addr,
737 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200738 template Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100739 template integer seq_nr,
740 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200741 requestLine := tr_SIP_ReqLine(INVITE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100742 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200743 via, "INVITE", seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100744 messageBody := body,
745 payload := omit
746}
747
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100748template (value) PDU_SIP_Request
749ts_SIP_BYE(CallidString call_id,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200750 template (value) SipAddr from_addr,
751 template (value) SipAddr to_addr,
752 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100753 integer seq_nr,
754 template (omit) charstring body) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100755 requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec),
756 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200757 via,
758 content_length := f_ContentLength(body),
759 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100760 messageBody := body,
761 payload := omit
762}
763
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100764template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200765tr_SIP_BYE(template (present) SipUrl uri,
766 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100767 template SipAddr from_addr,
768 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200769 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100770 template integer seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200771 template charstring body := *) := {
772 requestLine := tr_SIP_ReqLine(BYE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100773 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200774 via, "BYE", seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100775 messageBody := body,
776 payload := omit
777}
778
779
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100780template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200781ts_SIP_ACK(template (value) CallidString call_id,
782 template (value) SipAddr from_addr,
783 template (value) SipAddr to_addr,
784 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100785 integer seq_nr,
786 template (omit) charstring body) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100787 requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100788 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr,
789 ts_Contact_SipAddr(from_addr),
790 "ACK", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200791 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200792 content_length := f_ContentLength(body),
793 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100794 messageBody := body,
795 payload := omit
796}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100797template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200798tr_SIP_ACK(template (present) SipUrl uri,
799 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100800 template SipAddr from_addr,
801 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200802 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100803 template integer seq_nr,
804 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200805 requestLine := tr_SIP_ReqLine(ACK_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100806 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200807 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200808 "ACK", seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100809 messageBody := body,
810 payload := omit
811}
812
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200813template (present) PDU_SIP_Request
814tr_SIP_CANCEL(template (present) SipUrl uri,
815 template (present) CallidString call_id,
816 template (present) SipAddr from_addr,
817 template (present) SipAddr to_addr,
818 template (present) Via via,
819 template (present) integer seq_nr,
820 template charstring body := *) := {
821 requestLine := tr_SIP_ReqLine(CANCEL_E, uri),
822 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
823 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200824 "CANCEL", seq_nr),
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200825 messageBody := body,
826 payload := omit
827}
828
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100829template (value) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200830ts_SIP_Response(template (value) CallidString call_id,
831 template (value) SipAddr from_addr,
832 template (value) SipAddr to_addr,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100833 charstring method,
834 integer status_code,
835 integer seq_nr,
836 charstring reason,
837 Via via,
838 template (omit) charstring body := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100839 statusLine := ts_SIP_StatusLine(status_code, reason),
840 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200841 via,
842 content_length := f_ContentLength(body),
843 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100844 messageBody := body,
845 payload := omit
846}
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +0200847/* 100 Trying */
848template (value) PDU_SIP_Response
849ts_SIP_Response_Trying(
850 template (value) CallidString call_id,
851 template (value) SipAddr from_addr,
852 template (value) SipAddr to_addr,
853 Via via,
854 integer seq_nr,
855 charstring method := "INVITE",
856 template (omit) charstring body := omit) := {
857 statusLine := ts_SIP_StatusLine(100, "Trying"),
858 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200859 via,
860 content_length := f_ContentLength(body),
861 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +0200862 messageBody := body,
863 payload := omit
864}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200865/* 180 Ringing */
866template (value) PDU_SIP_Response
867ts_SIP_Response_Ringing(
868 template (value) CallidString call_id,
869 template (value) SipAddr from_addr,
870 template (value) SipAddr to_addr,
871 Via via,
872 integer seq_nr,
873 charstring method := "INVITE",
874 template (omit) charstring body := omit) := {
875 statusLine := ts_SIP_StatusLine(180, "Ringing"),
876 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200877 via,
878 content_length := f_ContentLength(body),
879 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200880 messageBody := body,
881 payload := omit
882}
883
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100884template (present) PDU_SIP_Response
885tr_SIP_Response(template CallidString call_id,
886 template SipAddr from_addr,
887 template SipAddr to_addr,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200888 template (present) Via via := tr_Via_from(?),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100889 template Contact contact,
890 template charstring method,
891 template integer status_code,
892 template integer seq_nr := ?,
893 template charstring reason := ?,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200894 template charstring body := *) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100895 statusLine := tr_SIP_StatusLine(status_code, reason),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100896 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200897 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200898 method, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100899 messageBody := body,
900 payload := omit
901}
902
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200903/* Expect during first REGISTER/INVITE/... when authorization is required: */
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100904template (present) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200905tr_SIP_Response_Unauthorized(
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100906 template CallidString call_id,
907 template SipAddr from_addr,
908 template SipAddr to_addr,
909 template (present) Via via := tr_Via_from(?),
910 template Contact contact := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200911 template (present) WwwAuthenticate wwwAuthenticate := ?,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100912 template integer seq_nr := ?,
913 template charstring method := "REGISTER",
914 template integer status_code := 401,
915 template charstring reason := "Unauthorized",
916 template charstring body := *) := {
917 statusLine := tr_SIP_StatusLine(status_code, reason),
918 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
919 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200920 method, seq_nr,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200921 wwwAuthenticate := wwwAuthenticate),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100922 messageBody := body,
923 payload := omit
924}
Harald Welteb0d93602018-03-20 18:09:34 +0100925
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200926/* 100 Trying */
927template (present) PDU_SIP_Response
928tr_SIP_Response_Trying(
929 template CallidString call_id,
930 template SipAddr from_addr,
931 template SipAddr to_addr,
932 template (present) Via via := tr_Via_from(?),
933 template integer seq_nr := ?,
934 template charstring method := "INVITE",
935 template integer status_code := 100,
936 template charstring reason := "Trying",
937 template charstring body := *) := {
938 statusLine := tr_SIP_StatusLine(status_code, reason),
939 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
940 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200941 method, seq_nr),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200942 messageBody := body,
943 payload := omit
944}
945
946/* 180 Ringing */
947template (present) PDU_SIP_Response
948tr_SIP_Response_Ringing(
949 template CallidString call_id,
950 template SipAddr from_addr,
951 template SipAddr to_addr,
952 template (present) Via via := tr_Via_from(?),
953 template integer seq_nr := ?,
954 template charstring method := "INVITE",
955 template integer status_code := 180,
956 template charstring reason := "Ringing",
957 template charstring body := *) := {
958 statusLine := tr_SIP_StatusLine(status_code, reason),
959 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
960 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200961 method, seq_nr),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200962 messageBody := body,
963 payload := omit
964}
965
966/****************
967 * FUNCTIONS:
968 ****************/
969
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200970function f_sip_param_find(GenericParam_List li,
971 template (present) charstring id := ?)
972return template (omit) GenericParam {
973 var integer i;
974
975 for (i := 0; i < lengthof(li); i := i + 1) {
976 if (not ispresent(li[i])) {
977 continue;
978 }
979 if (match(li[i].id, id)) {
980 return li[i];
981 }
982 }
983 return omit;
984}
985
986function f_sip_param_find_or_fail(GenericParam_List li,
987 template (present) charstring id := ?)
988return GenericParam {
989 var template (omit) GenericParam parameter;
990 parameter := f_sip_param_find(li, id);
991 if (istemplatekind(parameter, "omit")) {
992 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
993 log2str("Param ", id, " not found in ", li));
994 }
995 return valueof(parameter);
996}
997
998function f_sip_param_get_value(GenericParam_List li,
999 template (present) charstring id := ?)
1000return template (omit) charstring {
1001 var template (omit) GenericParam parameter;
1002 parameter := f_sip_param_find(li, id);
1003 if (istemplatekind(parameter, "omit")) {
1004 return omit;
1005 }
1006 return parameter.paramValue;
1007}
1008
1009function f_sip_param_get_value_or_fail(GenericParam_List li,
1010 template (present) charstring id := ?)
1011return template (omit) charstring {
1012 var GenericParam parameter;
1013 parameter := f_sip_param_find_or_fail(li, id);
1014 return parameter.paramValue;
1015}
1016
1017function f_sip_param_get_value_present_or_fail(GenericParam_List li,
1018 template (present) charstring id := ?)
1019return charstring {
1020 var GenericParam parameter;
1021 parameter := f_sip_param_find_or_fail(li, id);
1022 if (not ispresent(parameter.paramValue)) {
1023 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1024 log2str("Param ", id, " value not present in ", li));
1025 }
1026 return parameter.paramValue;
1027}
1028
1029function f_sip_param_match_value(GenericParam_List li,
1030 template (present) charstring id := ?,
1031 template charstring exp_paramValue := *)
1032return boolean {
1033 var template (omit) charstring val;
1034 val := f_sip_param_get_value_or_fail(li, id);
1035 if (istemplatekind(val, "omit")) {
1036 return istemplatekind(val, "omit") or istemplatekind(val, "*");
1037 }
1038 return match(valueof(val), exp_paramValue);
1039}
1040
1041function f_sip_param_match_value_or_fail(GenericParam_List li,
1042 template (present) charstring id := ?,
1043 template charstring exp_paramValue := *)
1044{
1045 var template (omit) charstring val := f_sip_param_get_value_or_fail(li, id);
1046 if (istemplatekind(val, "omit")) {
1047 if (istemplatekind(val, "omit") or istemplatekind(val, "*")) {
1048 return;
1049 } else {
1050 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1051 log2str("Param ", id, " match failed: val ", val,
1052 " vs exp ", exp_paramValue));
1053 }
1054 }
1055 if (not match(valueof(val), exp_paramValue)) {
1056 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1057 log2str("Param ", id, " match failed: val ", val,
1058 " vs exp ", exp_paramValue));
1059 }
1060}
1061
1062function f_sip_param_remove(template (omit) GenericParam_List li_tpl, charstring id)
1063return GenericParam_List {
1064 var integer i;
1065 var GenericParam_List li;
1066 var GenericParam_List new_li := {};
1067
1068 if (istemplatekind(li_tpl, "omit")) {
1069 return {};
1070 }
1071
1072 li := valueof(li_tpl);
1073 for (i := 0; i < lengthof(li); i := i + 1) {
1074 if (not ispresent(li[i]) or
1075 not match(li[i].id, id)) {
1076 new_li := new_li & {li[i]};
1077 }
1078 }
1079 return new_li;
1080}
1081
1082function f_sip_param_set(template (omit) GenericParam_List li_tpl, charstring id, charstring val)
1083return GenericParam_List {
1084 var integer i;
1085 var GenericParam_List li;
1086 var GenericParam_List new_li := {};
1087 var boolean found := false;
1088
1089 if (istemplatekind(li_tpl, "omit")) {
1090 return { valueof(ts_Param(id, val)) };
1091 }
1092
1093 li := valueof(li_tpl);
1094 for (i := 0; i < lengthof(li); i := i + 1) {
1095 if (not ispresent(li[i]) or
1096 not match(li[i].id, id)) {
1097 new_li := new_li & {li[i]};
1098 continue;
1099 }
1100 new_li := new_li & { valueof(ts_Param(li[i].id, val)) };
1101 found := true;
1102 }
1103
1104 if (not found) {
1105 new_li := new_li & { valueof(ts_Param(id, val)) };
1106 }
1107 return new_li;
1108}
1109
1110/* Make sure string is quoted. */
1111function f_sip_str_quote(template (value) charstring val) return charstring {
1112 var charstring str := valueof(val);
1113 if (lengthof(str) == 0) {
1114 return "";
1115 }
1116
1117 if (str[0] != "\"") {
1118 return "\"" & str & "\"";
1119 }
1120 return str;
1121}
1122
1123/* Make sure string is unquoted.
1124 * Similar to unq() in RFC 2617 */
1125function f_sip_str_unquote(template (value) charstring val) return charstring {
1126 var charstring str := valueof(val);
1127 var integer len := lengthof(str);
1128
1129 if (len <= 1) {
1130 return str;
1131 }
1132
1133 if (str[0] == "\"" and str[len - 1] == "\"") {
1134 return substr(str, 1, len - 2);
1135 }
1136 return str;
1137}
1138
1139/* RFC 2617 3.2.2.2 A1 */
1140function f_sip_digest_A1(charstring user, charstring realm, charstring password) return charstring {
1141
1142 /* RFC 2617 3.2.2.2 A1 */
1143 var charstring A1 := f_sip_str_unquote(user) & ":" &
1144 f_sip_str_unquote(realm) & ":" &
1145 password;
1146 var charstring digestA1 := f_str_tolower(f_calculateMD5(A1));
1147 log("A1: md5('", A1, "') = ", digestA1);
1148 return digestA1;
1149}
1150
1151/* RFC 2617 3.2.2.2 A2 */
1152function f_sip_digest_A2(charstring method, charstring uri) return charstring {
1153
1154 var charstring A2 := method & ":" & uri
1155 var charstring digestA2 := f_str_tolower(f_calculateMD5(A2));
1156 log("A2: md5('", A2, "') = ", digestA2);
1157 return digestA2;
1158}
1159
1160/* RFC 2617 3.2.2.1 Request-Digest */
1161function f_sip_digest_RequestDigest(charstring digestA1, charstring nonce,
1162 charstring nc, charstring cnonce,
1163 charstring qop, charstring digestA2) return charstring {
1164 var charstring digest_data := f_sip_str_unquote(nonce) & ":" &
1165 nc & ":" &
1166 cnonce & ":" &
1167 f_sip_str_unquote(qop) & ":" &
1168 digestA2;
1169 var charstring req_digest := f_sip_digest_KD(digestA1, digest_data);
1170 log("Request-Digest: md5('", digestA1, ":", digest_data ,"') = ", req_digest);
1171 return req_digest;
1172}
1173
1174/* RFC 2617 3.2.1 The WWW-Authenticate Response Header
1175 * KD(secret, data) = H(concat(secret, ":", data))
1176 */
1177function f_sip_digest_KD(charstring secret, charstring data) return charstring {
1178 return f_str_tolower(f_calculateMD5(secret & ":" & data));
1179}
1180
1181/* Digest Auth: RFC 2617 */
1182function f_sip_digest_gen_Authorization(WwwAuthenticate www_authenticate,
1183 charstring user, charstring password,
1184 charstring method, charstring uri,
1185 charstring cnonce := "0a4f113b", integer nc_int := 1) return Authorization {
1186 var CommaParam_List digestCln;
1187 var template (value) Authorization authorization;
1188 var template (value) Credentials cred;
1189 var template (omit) GenericParam rx_param;
1190
1191 digestCln := www_authenticate.challenge[0].digestCln;
1192
1193 var charstring algorithm;
1194 rx_param := f_sip_param_find(digestCln, "algorithm");
1195 if (istemplatekind(rx_param, "omit")) {
1196 /* Assume MD5 if not set */
1197 algorithm := "MD5"
1198 } else {
1199 algorithm := valueof(rx_param.paramValue);
1200 if (f_strstr(algorithm, "MD5") == -1) {
1201 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1202 log2str("Unexpected algorithm: ", algorithm));
1203 }
1204 }
1205
1206 var charstring realm := f_sip_param_get_value_present_or_fail(digestCln, "realm");
1207 var charstring nonce := f_sip_param_get_value_present_or_fail(digestCln, "nonce");
1208 var charstring opaque := f_sip_param_get_value_present_or_fail(digestCln, "opaque");
1209 var charstring qop := f_sip_param_get_value_present_or_fail(digestCln, "qop");
1210
1211 if (f_strstr(qop, "auth") == -1) {
1212 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected qop: ", qop));
1213 }
1214 var charstring selected_qop := "auth";
1215
1216 /* RFC 2617 3.2.2.2 A1 */
1217 var charstring digestA1 := f_sip_digest_A1(user, realm, password);
1218 /* RFC 2617 3.2.2.3 A2 */
1219 var charstring digestA2 := f_sip_digest_A2(method, uri);
1220
1221 /* RFC 2617 3.2.2.1 Request-Digest */
1222 var charstring nc := f_str_tolower(hex2str(int2hex(nc_int, 8)));
1223 var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
1224 nc, cnonce,
1225 selected_qop, digestA2);
1226
1227 cred := ts_Credentials_DigestResponseMD5(user, realm, nonce,
1228 uri, req_digest,
1229 opaque, algorithm, selected_qop, cnonce, nc);
1230
1231 authorization := ts_Authorization(cred);
1232 return valueof(authorization);
1233}
1234
1235/* RFC 2617 3.5 Example */
1236function f_sip_digest_selftest() {
1237/*
1238The following example assumes that an access-protected document is
1239being requested from the server via a GET request. The URI of the
1240document is "http://www.nowhere.org/dir/index.html". Both client and
1241server know that the username for this document is "Mufasa", and the
1242password is "Circle Of Life" (with one space between each of the
1243three words).
1244
1245HTTP/1.1 401 Unauthorized
1246WWW-Authenticate: Digest
1247 realm="testrealm@host.com",
1248 qop="auth,auth-int",
1249 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1250 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1251
1252Authorization: Digest username="Mufasa",
1253 realm="testrealm@host.com",
1254 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1255 uri="/dir/index.html",
1256 qop=auth,
1257 nc=00000001,
1258 cnonce="0a4f113b",
1259 response="6629fae49393a05397450978507c4ef1",
1260 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1261*/
1262 var template (value) CommaParam_List digestCln := {
1263 ts_Param("realm", f_sip_str_quote("testrealm@host.com")),
1264 ts_Param("qop", f_sip_str_quote("auth,auth-int")),
1265 ts_Param("nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093")),
1266 ts_Param("opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"))
1267 };
1268 var template (value) WwwAuthenticate www_authenticate :=
1269 ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
1270
1271 var Authorization authorization :=
1272 f_sip_digest_gen_Authorization(valueof(www_authenticate),
1273 "Mufasa",
1274 "Circle Of Life",
1275 "GET",
1276 "/dir/index.html",
1277 cnonce := "0a4f113b",
1278 nc_int := 1);
1279
1280 var CommaParam_List digestResp := authorization.body.digestResponse;
1281 f_sip_param_match_value_or_fail(digestResp, "realm", f_sip_str_quote("testrealm@host.com"));
1282 f_sip_param_match_value_or_fail(digestResp, "nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093"));
1283 f_sip_param_match_value_or_fail(digestResp, "uri", f_sip_str_quote("/dir/index.html"));
1284 f_sip_param_match_value_or_fail(digestResp, "qop", "auth");
1285 f_sip_param_match_value_or_fail(digestResp, "nc", "00000001");
1286 f_sip_param_match_value_or_fail(digestResp, "cnonce", f_sip_str_quote("0a4f113b"));
1287 f_sip_param_match_value_or_fail(digestResp, "response", f_sip_str_quote("6629fae49393a05397450978507c4ef1"));
1288 f_sip_param_match_value_or_fail(digestResp, "opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"));
1289}
1290
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01001291/* RFC 3261 8.1.1.5:
1292 * "The sequence number value MUST be expressible as a 32-bit unsigned integer
1293 * and MUST be less than 2**31."
1294 */
1295function f_sip_rand_seq_nr() return integer {
1296 /* 2**31 = 2147483648 */
1297 return f_rnd_int(2147483648)
1298}
Harald Welteb0d93602018-03-20 18:09:34 +01001299
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001300function f_sip_next_seq_nr(integer seq_nr) return integer {
1301 return (seq_nr + 1) mod 2147483648;
1302}
1303
1304function f_sip_Request_inc_seq_nr(inout template (value) PDU_SIP_Request req) {
1305 req.msgHeader.cSeq.seqNumber := f_sip_next_seq_nr(valueof(req.msgHeader.cSeq.seqNumber));
1306}
1307
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001308function f_sip_rand_tag() return charstring {
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001309 /* Tags shall have at least 32 bit of randomness */
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001310 var integer rnd_int := f_rnd_int(4294967296);
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001311 /* Make collisions harder by appending time to the final string: */
1312 var integer ts_int := f_time_ms() mod 4294967296;
1313 return hex2str(int2hex(rnd_int, 8)) & "-" & hex2str(int2hex(ts_int, 8));
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001314}
1315
1316/* Generate a "branch" tag value.
1317 * RFC 3261 p.105 section 8:
1318 * "A common way to create this value is to compute a
1319 * cryptographic hash of the To tag, From tag, Call-ID header
1320 * field, the Request-URI of the request received (before
1321 * translation), the topmost Via header, and the sequence number
1322 * from the CSeq header field, in addition to any Proxy-Require
1323 * and Proxy-Authorization header fields that may be present. The
1324 * algorithm used to compute the hash is implementation-dependent,
1325 * but MD5 (RFC 1321 [35]),expressed in hexadecimal, is a reasonable
1326 * choice."
1327 * See also Section 8.1.1.7:
1328 * "The branch ID inserted by an element compliant with this
1329 * specification MUST always begin with the characters "z9hG4bK"."
1330 */
1331const charstring sip_magic_cookie := "z9hG4bK";
1332function f_sip_gen_branch(charstring tag_to,
1333 charstring tag_from,
1334 charstring tag_call_id,
1335 integer cseq) return charstring {
1336 var charstring str := tag_to & tag_from & tag_call_id & int2str(cseq);
1337 var charstring hash := f_calculateMD5(str);
1338 var charstring branch := sip_magic_cookie & hash;
1339 return branch;
1340}
1341
1342function f_sip_HostPort_to_str(HostPort host_port) return charstring {
1343 var charstring str := "";
1344 if (ispresent(host_port.host)) {
1345 str := host_port.host;
1346 }
1347 if (ispresent(host_port.portField)) {
1348 str := str & ":" & int2str(host_port.portField);
1349 }
1350 return str;
1351}
1352
1353function f_sip_SipUrl_to_str(SipUrl uri) return charstring {
1354 var charstring str := uri.scheme & f_sip_HostPort_to_str(uri.hostPort);
1355 return str;
1356}
1357
1358function f_sip_NameAddr_to_str(NameAddr naddr) return charstring {
1359 if (ispresent(naddr.displayName)) {
1360 return naddr.displayName & " <" & f_sip_SipUrl_to_str(naddr.addrSpec) & ">";
1361 } else {
1362 return f_sip_SipUrl_to_str(naddr.addrSpec);
1363 }
1364}
1365
1366function f_sip_SipAddr_to_str(SipAddr sip_addr) return charstring {
1367 if (ischosen(sip_addr.addr.nameAddr)) {
1368 return f_sip_NameAddr_to_str(sip_addr.addr.nameAddr);
1369 } else {
1370 return f_sip_SipUrl_to_str(sip_addr.addr.addrSpecUnion);
1371 }
1372}
1373
Harald Welteb0d93602018-03-20 18:09:34 +01001374}