blob: e1c9ec6524d2d6aca744a0e64bd6f5d7bd1fc37e [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
204// [20.19]
205template (value) Expires ts_Expires(template (value) DeltaSec deltaSec := "7200") := {
206 fieldName := EXPIRES_E,
207 deltaSec := deltaSec
208}
209
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200210
211// [20.32]
212template (value) Require ts_Require(template (value) OptionTag_List optionsTags := {}) := {
213 fieldName := REQUIRE_E,
214 optionsTags := optionsTags
215}
216template (present) Require tr_Require(template (present) OptionTag_List optionsTags := ?) := {
217 fieldName := REQUIRE_E,
218 optionsTags := optionsTags
219}
220
221// [20.37]
222template (value) Supported ts_Supported(template (value) OptionTag_List optionsTags := {}) := {
223 fieldName := SUPPORTED_E,
224 optionsTags := optionsTags
225}
226template (present) Supported tr_Supported(template (present) OptionTag_List optionsTags := ?) := {
227 fieldName := SUPPORTED_E,
228 optionsTags := optionsTags
229}
230
231
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100232template (value) SipAddr ts_SipAddr(template (value) HostPort host_port,
233 template (omit) UserInfo user_info := omit,
234 template (omit) charstring displayName := omit,
235 template (omit) SemicolonParam_List params := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100236 addr := {
237 nameAddr := {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100238 displayName := displayName,
239 addrSpec := ts_SipUrl(host_port, user_info)
Harald Welteb0d93602018-03-20 18:09:34 +0100240 }
241 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100242 params := params
243}
244template (present) SipAddr tr_SipAddr(template (present) HostPort host_port := ?,
245 template UserInfo user_info := *,
246 template charstring displayName := *,
247 template SemicolonParam_List params := *) := {
248 addr := {
249 nameAddr := {
250 displayName := displayName,
251 addrSpec := tr_SipUrl(host_port, user_info)
252 }
253 },
254 params := params
Harald Welteb0d93602018-03-20 18:09:34 +0100255}
256
257/* build a receive template from a value: substitute '*' for omit */
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200258function tr_SipUrl_from_val(template (value) SipUrl tin) return template (present) SipUrl {
259 var template (present) SipUrl ret := tin;
260
261 /* if the port number is 5060, it may be omitted */
262 if (ispresent(tin.hostPort.portField) and
263 valueof(tin.hostPort.portField) == 5060) {
264 ret.hostPort.portField := 5060 ifpresent;
265 }
266 if (not ispresent(tin.userInfo.password)) {
267 ret.userInfo.password := *;
268 }
269
270 return ret;
271}
272function tr_SipAddr_from_val(template (value) SipAddr tin) return template (present) SipAddr {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100273 var template (present) SipAddr ret := tin;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200274
275 if (not ispresent(tin.addr.nameAddr.displayName)) {
Harald Welteb0d93602018-03-20 18:09:34 +0100276 ret.addr.nameAddr.displayName := *;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200277 } else if (f_str_tolower(f_sip_str_unquote(tin.addr.nameAddr.displayName)) == "anonymous") {
278 /* if the user is Anonymous, it may be omitted */
279 ret.addr.nameAddr.displayName := tin.addr.nameAddr.displayName ifpresent;
Harald Welteb0d93602018-03-20 18:09:34 +0100280 }
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200281
282 ret.addr.nameAddr.addrSpec := tr_SipUrl_from_val(tin.addr.nameAddr.addrSpec);
283
284 if (not ispresent(tin.params)) {
Harald Welteb0d93602018-03-20 18:09:34 +0100285 ret.params := *;
286 }
287 return ret;
288}
289
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200290function ts_SipAddr_from_Addr_Union(template (value) Addr_Union au,
291 template (omit) SemicolonParam_List params := omit)
292return template (value) SipAddr {
293 var template (value) SipUrl addrSpec := ts_SipUrl_from_Addr_Union(au);
294 var template (omit) charstring displayName;
295
296 if (ischosen(au.nameAddr)) {
297 displayName := au.nameAddr.displayName;
298 } else { /* au.addrSpecUnion */
299 displayName := omit
300 }
301
302 return ts_SipAddr(addrSpec.hostPort,
303 addrSpec.userInfo,
304 displayName,
305 params);
306}
307
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100308template (value) HostPort ts_HostPort(template (omit) charstring host := omit,
309 template (omit) integer portField := omit) := {
310 host := host,
311 portField := portField
312}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200313
314template (present) HostPort tr_HostPort(template charstring host := *,
315 template integer portField := *) := {
316 host := host,
317 portField := portField
318}
319function f_tr_HostPort(template charstring host := *,
320 template integer portField := *)
321return template (present) HostPort {
322 return f_tr_HostPort_opt_defport(tr_HostPort(host, portField));
323}
324function f_tr_HostPort_opt_defport(template (present) HostPort hp) return template (present) HostPort {
325 var template (present) HostPort hpout := hp;
Harald Welteb0d93602018-03-20 18:09:34 +0100326 /* if the port number is 5060, it may be omitted */
327 if (isvalue(hp.portField) and valueof(hp.portField) == 5060) {
328 hpout.portField := 5060 ifpresent;
329 }
330 return hpout;
331}
332
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200333function f_tr_SipUrl_opt_defport(template (present) SipUrl url) return template (present) SipUrl {
334 var template (present) SipUrl urlout := url;
335 urlout.hostPort := f_tr_HostPort_opt_defport(url.hostPort);
336 return urlout;
337}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100338
339template (value) UserInfo ts_UserInfo(template (value) charstring userOrTelephoneSubscriber,
340 template (omit) charstring password := omit) := {
341 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
342 password := password
343}
344template (present) UserInfo tr_UserInfo(template (present) charstring userOrTelephoneSubscriber := ?,
345 template charstring password := *) := {
346 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
347 password := password
348}
349
350template (value) RequestLine ts_SIP_ReqLine(Method method,
351 template (value) SipUrl uri,
Harald Welteb0d93602018-03-20 18:09:34 +0100352 charstring ver := c_SIP_VERSION) := {
353 method := method,
354 requestUri := uri,
355 sipVersion := ver
356}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100357template (present) RequestLine tr_SIP_ReqLine(template (present) Method method := ?,
358 template (present) SipUrl uri := ?,
359 template (present) charstring ver := c_SIP_VERSION) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100360 method := method,
361 requestUri := uri,
362 sipVersion := ver
363}
364
365template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := {
366 sipVersion := "SIP/2.0",
367 statusCode := status_code,
368 reasonPhrase := reason
369}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100370template (present) StatusLine tr_SIP_StatusLine(template integer status_code,
371 template charstring reason) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100372 sipVersion := "SIP/2.0",
373 statusCode := status_code,
374 reasonPhrase := reason
375}
376
377
378template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := {
379 requestLine := rl,
380 msgHeader := c_SIP_msgHeader_empty,
381 messageBody := omit,
382 payload := omit
383}
384
385const Method_List c_SIP_defaultMethods := {
386 "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE",
387 "NOTIFY", "REFER", "UPDATE" };
388
389private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body)
390return template (omit) ContentType {
391 /* if user explicitly stated no content type */
392 if (istemplatekind(ct, "omit")) {
393 return omit;
394 }
395 /* if there's no body, then there's no content-type either */
396 if (istemplatekind(body, "omit")) {
397 return omit;
398 }
399 return ct;
400}
401
402template (value) ContentType ts_CT_SDP := {
403 fieldName := CONTENT_TYPE_E,
404 mediaType := "application/sdp"
405};
406
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200407template (value) Via ts_Via_from(template (value) HostPort addr,
408 template (value) charstring transport := "UDP") := {
Harald Welteb0d93602018-03-20 18:09:34 +0100409 fieldName := VIA_E,
410 viaBody := {
411 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200412 sentProtocol := { "SIP", "2.0", transport },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100413 sentBy := addr,
Harald Welteb0d93602018-03-20 18:09:34 +0100414 viaParams := omit
415 }
416 }
417}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100418template (present) Via tr_Via_from(template (present) HostPort host_port := ?,
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200419 template (present) charstring transport := ?,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100420 template SemicolonParam_List viaParams := *) := {
421 fieldName := VIA_E,
422 viaBody := {
423 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200424 sentProtocol := { "SIP", "2.0", ? },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100425 sentBy := host_port,
426 viaParams := viaParams
427 }
428 }
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200429}
430
431template (present) OtherAuth
432tr_OtherAuth(template (present) charstring authScheme := ?,
433 template (present) CommaParam_List authParams := ?) := {
434 authScheme := authScheme,
435 authParams := authParams
436}
437
438template (value) OtherAuth
439ts_OtherAuth(template (value) charstring authScheme,
440 template (value) CommaParam_List authParams) := {
441 authScheme := authScheme,
442 authParams := authParams
443}
444
445template (present) Challenge
446tr_Challenge_digestCln(template (present) CommaParam_List digestCln := ?) := {
447 digestCln := digestCln
448}
449
450template (value) Challenge
451ts_Challenge_digestCln(template (value) CommaParam_List digestCln) := {
452 digestCln := digestCln
453}
454
455template (present) Challenge
456tr_Challenge_otherChallenge(template (present) OtherAuth otherChallenge := ?) := {
457 otherChallenge := otherChallenge
458}
459
460template (value) Challenge
461ts_Challenge_otherChallenge(template (value) OtherAuth otherChallenge) := {
462 otherChallenge := otherChallenge
463}
464
465template (present) WwwAuthenticate
466tr_WwwAuthenticate(template (present) Challenge_list challenge := ?) := {
467 fieldName := WWW_AUTHENTICATE_E,
468 challenge := challenge
469}
470
471template (value) WwwAuthenticate
472ts_WwwAuthenticate(template (value) Challenge_list challenge) := {
473 fieldName := WWW_AUTHENTICATE_E,
474 challenge := challenge
475}
Harald Welteb0d93602018-03-20 18:09:34 +0100476
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200477// RFC3329
478template (present) Security_client
479tr_Security_client(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
480 fieldName := SECURITY_CLIENT_E,
481 sec_mechanism_list := sec_mechanism_list
482}
483template (value) Security_client
484ts_Security_client(template (value) Security_mechanism_list sec_mechanism_list) := {
485 fieldName := SECURITY_CLIENT_E,
486 sec_mechanism_list := sec_mechanism_list
487}
488
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200489template (present) Security_server
490tr_Security_server(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
491 fieldName := SECURITY_SERVER_E,
492 sec_mechanism_list := sec_mechanism_list
493}
494template (value) Security_server
495ts_Security_server(template (value) Security_mechanism_list sec_mechanism_list) := {
496 fieldName := SECURITY_SERVER_E,
497 sec_mechanism_list := sec_mechanism_list
498}
499
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200500template (present) Security_mechanism
501tr_Security_mechanism(template (present) charstring name := ?,
502 template SemicolonParam_List params := *) := {
503 mechanism_name := name,
504 mechanism_params := params
505}
506template (value) Security_mechanism
507ts_Security_mechanism(template (value) charstring name,
508 template (omit) SemicolonParam_List params := omit) := {
509 mechanism_name := name,
510 mechanism_params := params
511}
512
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100513template (value) MessageHeader ts_SIP_msgHeader_empty := c_SIP_msgHeader_empty;
514template (value) MessageHeader
515ts_SIP_msgh_std(template (value) CallidString call_id,
516 template (value) SipAddr from_addr,
517 template (value) SipAddr to_addr,
518 template (omit) Contact contact,
519 template (value) charstring method,
520 template (value) integer seq_nr,
521 template (value) Via via,
522 template (omit) ContentType content_type := omit,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200523 template (omit)Authorization authorization := omit,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200524 template (omit) Allow allow := ts_Allow(c_SIP_defaultMethods),
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200525 template (omit) Expires expires := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200526 template (omit) Require require := omit,
527 template (omit) Security_client security_client := omit,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200528 template (omit) Security_server security_server := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200529 template (omit) Supported supported := omit,
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200530 template (omit) WwwAuthenticate wwwAuthenticate := omit
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100531 ) modifies ts_SIP_msgHeader_empty := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200532 allow := allow,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200533 authorization := authorization,
Harald Welteb0d93602018-03-20 18:09:34 +0100534 callId := {
535 fieldName := CALL_ID_E,
536 callid := call_id
537 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100538 contact := contact,
Harald Welteb0d93602018-03-20 18:09:34 +0100539 contentType := content_type,
540 cSeq := {
541 fieldName := CSEQ_E,
542 seqNumber := seq_nr,
543 method := method
544 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100545 expires := expires,
Harald Welteb0d93602018-03-20 18:09:34 +0100546 fromField := {
547 fieldName := FROM_E,
548 addressField := from_addr.addr,
549 fromParams := from_addr.params
550 },
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200551 require := require,
552 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200553 security_server := security_server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200554 supported := supported,
Harald Welteb0d93602018-03-20 18:09:34 +0100555 toField := {
556 fieldName := TO_E,
557 addressField := to_addr.addr,
558 toParams := to_addr.params
559 },
560 userAgent := {
561 fieldName := USER_AGENT_E,
562 userAgentBody := {
563 "osmo-ttcn3-hacks/0.23"
564 }
565 },
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200566 via := via,
567 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100568}
569
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100570template (present) MessageHeader
571tr_SIP_msgh_std(template CallidString call_id,
572 template SipAddr from_addr,
573 template SipAddr to_addr,
574 template Contact contact,
575 template (present) Via via := tr_Via_from(?),
576 template charstring method,
577 template ContentType content_type := *,
578 template integer seq_nr := ?,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200579 template Allow allow := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200580 template Expires expires := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200581 template Require require := *,
582 template Security_client security_client := *,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200583 template Security_server security_server := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200584 template Supported supported := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200585 template WwwAuthenticate wwwAuthenticate := *
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100586 ) modifies t_SIP_msgHeader_any := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200587 allow := allow,
Harald Welteb0d93602018-03-20 18:09:34 +0100588 callId := {
589 fieldName := CALL_ID_E,
590 callid := call_id
591 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100592 contact := contact,
Harald Welteb0d93602018-03-20 18:09:34 +0100593 contentType := content_type,
594 cSeq := {
595 fieldName := CSEQ_E,
596 seqNumber := seq_nr,
597 method := method
598 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100599 expires := expires,
Harald Welteb0d93602018-03-20 18:09:34 +0100600 fromField := {
601 fieldName := FROM_E,
602 addressField := from_addr.addr,
603 fromParams := from_addr.params
604 },
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200605 require := require,
606 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200607 security_server := security_server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200608 supported := supported,
Harald Welteb0d93602018-03-20 18:09:34 +0100609 toField := {
610 fieldName := TO_E,
611 addressField := to_addr.addr,
612 toParams := to_addr.params
613 },
614 userAgent := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200615 via := via,
616 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100617}
618
619
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100620template (value) PDU_SIP_Request
621ts_SIP_REGISTER(template (value) SipUrl sip_url_host_port,
622 template (value) CallidString call_id,
623 template (value) SipAddr from_addr,
624 template (value) SipAddr to_addr,
625 template (value) Via via,
626 integer seq_nr,
627 template (omit) Contact contact,
628 template (omit) Expires expires,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200629 template (omit) Authorization authorization := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200630 template (omit) Require require := omit,
631 template (omit) Security_client security_client := omit,
632 template (omit) Supported supported := omit,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100633 template (omit) charstring body := omit) := {
634 requestLine := ts_SIP_ReqLine(REGISTER_E, sip_url_host_port),
635 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
636 "REGISTER", seq_nr, via,
637 f_ContentTypeOrOmit(ts_CT_SDP, body),
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200638 authorization := authorization,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200639 expires := expires,
640 require := require,
641 security_client := security_client,
642 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100643 messageBody := body,
644 payload := omit
645}
646template (present) PDU_SIP_Request
647tr_SIP_REGISTER(template (present) SipUrl sip_url_host_port := ?,
648 template (present) CallidString call_id := ?,
649 template (present) SipAddr from_addr := ?,
650 template (present) SipAddr to_addr := ?,
Pau Espin Pedrol0dd3f262024-04-25 17:04:43 +0200651 template (present) Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100652 template integer seq_nr := *,
653 template Contact contact := *,
654 template Expires expires := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200655 template Require require := *,
656 template Security_client security_client := *,
657 template Supported supported := *,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100658 template charstring body := *) := {
659 requestLine := tr_SIP_ReqLine(REGISTER_E, sip_url_host_port),
660 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol0dd3f262024-04-25 17:04:43 +0200661 via, "REGISTER", *, seq_nr,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200662 expires := expires,
663 require := require,
664 security_client := security_client,
665 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100666 messageBody := body,
667 payload := omit
668}
669
670template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200671ts_SIP_INVITE(template (value) CallidString call_id,
672 template (value) SipAddr from_addr,
673 template (value) SipAddr to_addr,
674 template (value) Via via,
675 template (value) Contact contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100676 integer seq_nr,
677 template (omit) charstring body := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100678 requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200679 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100680 "INVITE", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200681 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100682 f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100683 messageBody := body,
684 payload := omit
685}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100686template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200687tr_SIP_INVITE(template (present) SipUrl uri,
688 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100689 template SipAddr from_addr,
690 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200691 template Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100692 template integer seq_nr,
693 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200694 requestLine := tr_SIP_ReqLine(INVITE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100695 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200696 via, "INVITE", *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100697 messageBody := body,
698 payload := omit
699}
700
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100701template (value) PDU_SIP_Request
702ts_SIP_BYE(CallidString call_id,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200703 template (value) SipAddr from_addr,
704 template (value) SipAddr to_addr,
705 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100706 integer seq_nr,
707 template (omit) charstring body) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100708 requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec),
709 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200710 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100711 messageBody := body,
712 payload := omit
713}
714
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100715template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200716tr_SIP_BYE(template (present) SipUrl uri,
717 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100718 template SipAddr from_addr,
719 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200720 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100721 template integer seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200722 template charstring body := *) := {
723 requestLine := tr_SIP_ReqLine(BYE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100724 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200725 via, "BYE", *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100726 messageBody := body,
727 payload := omit
728}
729
730
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100731template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200732ts_SIP_ACK(template (value) CallidString call_id,
733 template (value) SipAddr from_addr,
734 template (value) SipAddr to_addr,
735 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100736 integer seq_nr,
737 template (omit) charstring body) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100738 requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100739 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr,
740 ts_Contact_SipAddr(from_addr),
741 "ACK", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200742 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100743 f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100744 messageBody := body,
745 payload := omit
746}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100747template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200748tr_SIP_ACK(template (present) SipUrl uri,
749 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100750 template SipAddr from_addr,
751 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200752 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100753 template integer seq_nr,
754 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200755 requestLine := tr_SIP_ReqLine(ACK_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100756 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200757 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100758 "ACK", *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100759 messageBody := body,
760 payload := omit
761}
762
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200763template (present) PDU_SIP_Request
764tr_SIP_CANCEL(template (present) SipUrl uri,
765 template (present) CallidString call_id,
766 template (present) SipAddr from_addr,
767 template (present) SipAddr to_addr,
768 template (present) Via via,
769 template (present) integer seq_nr,
770 template charstring body := *) := {
771 requestLine := tr_SIP_ReqLine(CANCEL_E, uri),
772 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
773 via,
774 "CANCEL", *, seq_nr),
775 messageBody := body,
776 payload := omit
777}
778
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100779template (value) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200780ts_SIP_Response(template (value) CallidString call_id,
781 template (value) SipAddr from_addr,
782 template (value) SipAddr to_addr,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100783 charstring method,
784 integer status_code,
785 integer seq_nr,
786 charstring reason,
787 Via via,
788 template (omit) charstring body := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100789 statusLine := ts_SIP_StatusLine(status_code, reason),
790 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
791 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
792 messageBody := body,
793 payload := omit
794}
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +0200795/* 100 Trying */
796template (value) PDU_SIP_Response
797ts_SIP_Response_Trying(
798 template (value) CallidString call_id,
799 template (value) SipAddr from_addr,
800 template (value) SipAddr to_addr,
801 Via via,
802 integer seq_nr,
803 charstring method := "INVITE",
804 template (omit) charstring body := omit) := {
805 statusLine := ts_SIP_StatusLine(100, "Trying"),
806 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
807 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
808 messageBody := body,
809 payload := omit
810}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200811/* 180 Ringing */
812template (value) PDU_SIP_Response
813ts_SIP_Response_Ringing(
814 template (value) CallidString call_id,
815 template (value) SipAddr from_addr,
816 template (value) SipAddr to_addr,
817 Via via,
818 integer seq_nr,
819 charstring method := "INVITE",
820 template (omit) charstring body := omit) := {
821 statusLine := ts_SIP_StatusLine(180, "Ringing"),
822 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
823 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
824 messageBody := body,
825 payload := omit
826}
827
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100828template (present) PDU_SIP_Response
829tr_SIP_Response(template CallidString call_id,
830 template SipAddr from_addr,
831 template SipAddr to_addr,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200832 template (present) Via via := tr_Via_from(?),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100833 template Contact contact,
834 template charstring method,
835 template integer status_code,
836 template integer seq_nr := ?,
837 template charstring reason := ?,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200838 template charstring body := *) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100839 statusLine := tr_SIP_StatusLine(status_code, reason),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100840 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200841 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100842 method, *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100843 messageBody := body,
844 payload := omit
845}
846
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200847/* Expect during first REGISTER/INVITE/... when authorization is required: */
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100848template (present) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200849tr_SIP_Response_Unauthorized(
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100850 template CallidString call_id,
851 template SipAddr from_addr,
852 template SipAddr to_addr,
853 template (present) Via via := tr_Via_from(?),
854 template Contact contact := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200855 template (present) WwwAuthenticate wwwAuthenticate := ?,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100856 template integer seq_nr := ?,
857 template charstring method := "REGISTER",
858 template integer status_code := 401,
859 template charstring reason := "Unauthorized",
860 template charstring body := *) := {
861 statusLine := tr_SIP_StatusLine(status_code, reason),
862 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
863 via,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200864 method, *, seq_nr,
865 wwwAuthenticate := wwwAuthenticate),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100866 messageBody := body,
867 payload := omit
868}
Harald Welteb0d93602018-03-20 18:09:34 +0100869
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200870/* 100 Trying */
871template (present) PDU_SIP_Response
872tr_SIP_Response_Trying(
873 template CallidString call_id,
874 template SipAddr from_addr,
875 template SipAddr to_addr,
876 template (present) Via via := tr_Via_from(?),
877 template integer seq_nr := ?,
878 template charstring method := "INVITE",
879 template integer status_code := 100,
880 template charstring reason := "Trying",
881 template charstring body := *) := {
882 statusLine := tr_SIP_StatusLine(status_code, reason),
883 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
884 via,
885 method, *, seq_nr),
886 messageBody := body,
887 payload := omit
888}
889
890/* 180 Ringing */
891template (present) PDU_SIP_Response
892tr_SIP_Response_Ringing(
893 template CallidString call_id,
894 template SipAddr from_addr,
895 template SipAddr to_addr,
896 template (present) Via via := tr_Via_from(?),
897 template integer seq_nr := ?,
898 template charstring method := "INVITE",
899 template integer status_code := 180,
900 template charstring reason := "Ringing",
901 template charstring body := *) := {
902 statusLine := tr_SIP_StatusLine(status_code, reason),
903 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
904 via,
905 method, *, seq_nr),
906 messageBody := body,
907 payload := omit
908}
909
910/****************
911 * FUNCTIONS:
912 ****************/
913
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200914function f_sip_param_find(GenericParam_List li,
915 template (present) charstring id := ?)
916return template (omit) GenericParam {
917 var integer i;
918
919 for (i := 0; i < lengthof(li); i := i + 1) {
920 if (not ispresent(li[i])) {
921 continue;
922 }
923 if (match(li[i].id, id)) {
924 return li[i];
925 }
926 }
927 return omit;
928}
929
930function f_sip_param_find_or_fail(GenericParam_List li,
931 template (present) charstring id := ?)
932return GenericParam {
933 var template (omit) GenericParam parameter;
934 parameter := f_sip_param_find(li, id);
935 if (istemplatekind(parameter, "omit")) {
936 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
937 log2str("Param ", id, " not found in ", li));
938 }
939 return valueof(parameter);
940}
941
942function f_sip_param_get_value(GenericParam_List li,
943 template (present) charstring id := ?)
944return template (omit) charstring {
945 var template (omit) GenericParam parameter;
946 parameter := f_sip_param_find(li, id);
947 if (istemplatekind(parameter, "omit")) {
948 return omit;
949 }
950 return parameter.paramValue;
951}
952
953function f_sip_param_get_value_or_fail(GenericParam_List li,
954 template (present) charstring id := ?)
955return template (omit) charstring {
956 var GenericParam parameter;
957 parameter := f_sip_param_find_or_fail(li, id);
958 return parameter.paramValue;
959}
960
961function f_sip_param_get_value_present_or_fail(GenericParam_List li,
962 template (present) charstring id := ?)
963return charstring {
964 var GenericParam parameter;
965 parameter := f_sip_param_find_or_fail(li, id);
966 if (not ispresent(parameter.paramValue)) {
967 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
968 log2str("Param ", id, " value not present in ", li));
969 }
970 return parameter.paramValue;
971}
972
973function f_sip_param_match_value(GenericParam_List li,
974 template (present) charstring id := ?,
975 template charstring exp_paramValue := *)
976return boolean {
977 var template (omit) charstring val;
978 val := f_sip_param_get_value_or_fail(li, id);
979 if (istemplatekind(val, "omit")) {
980 return istemplatekind(val, "omit") or istemplatekind(val, "*");
981 }
982 return match(valueof(val), exp_paramValue);
983}
984
985function f_sip_param_match_value_or_fail(GenericParam_List li,
986 template (present) charstring id := ?,
987 template charstring exp_paramValue := *)
988{
989 var template (omit) charstring val := f_sip_param_get_value_or_fail(li, id);
990 if (istemplatekind(val, "omit")) {
991 if (istemplatekind(val, "omit") or istemplatekind(val, "*")) {
992 return;
993 } else {
994 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
995 log2str("Param ", id, " match failed: val ", val,
996 " vs exp ", exp_paramValue));
997 }
998 }
999 if (not match(valueof(val), exp_paramValue)) {
1000 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1001 log2str("Param ", id, " match failed: val ", val,
1002 " vs exp ", exp_paramValue));
1003 }
1004}
1005
1006function f_sip_param_remove(template (omit) GenericParam_List li_tpl, charstring id)
1007return GenericParam_List {
1008 var integer i;
1009 var GenericParam_List li;
1010 var GenericParam_List new_li := {};
1011
1012 if (istemplatekind(li_tpl, "omit")) {
1013 return {};
1014 }
1015
1016 li := valueof(li_tpl);
1017 for (i := 0; i < lengthof(li); i := i + 1) {
1018 if (not ispresent(li[i]) or
1019 not match(li[i].id, id)) {
1020 new_li := new_li & {li[i]};
1021 }
1022 }
1023 return new_li;
1024}
1025
1026function f_sip_param_set(template (omit) GenericParam_List li_tpl, charstring id, charstring val)
1027return GenericParam_List {
1028 var integer i;
1029 var GenericParam_List li;
1030 var GenericParam_List new_li := {};
1031 var boolean found := false;
1032
1033 if (istemplatekind(li_tpl, "omit")) {
1034 return { valueof(ts_Param(id, val)) };
1035 }
1036
1037 li := valueof(li_tpl);
1038 for (i := 0; i < lengthof(li); i := i + 1) {
1039 if (not ispresent(li[i]) or
1040 not match(li[i].id, id)) {
1041 new_li := new_li & {li[i]};
1042 continue;
1043 }
1044 new_li := new_li & { valueof(ts_Param(li[i].id, val)) };
1045 found := true;
1046 }
1047
1048 if (not found) {
1049 new_li := new_li & { valueof(ts_Param(id, val)) };
1050 }
1051 return new_li;
1052}
1053
1054/* Make sure string is quoted. */
1055function f_sip_str_quote(template (value) charstring val) return charstring {
1056 var charstring str := valueof(val);
1057 if (lengthof(str) == 0) {
1058 return "";
1059 }
1060
1061 if (str[0] != "\"") {
1062 return "\"" & str & "\"";
1063 }
1064 return str;
1065}
1066
1067/* Make sure string is unquoted.
1068 * Similar to unq() in RFC 2617 */
1069function f_sip_str_unquote(template (value) charstring val) return charstring {
1070 var charstring str := valueof(val);
1071 var integer len := lengthof(str);
1072
1073 if (len <= 1) {
1074 return str;
1075 }
1076
1077 if (str[0] == "\"" and str[len - 1] == "\"") {
1078 return substr(str, 1, len - 2);
1079 }
1080 return str;
1081}
1082
1083/* RFC 2617 3.2.2.2 A1 */
1084function f_sip_digest_A1(charstring user, charstring realm, charstring password) return charstring {
1085
1086 /* RFC 2617 3.2.2.2 A1 */
1087 var charstring A1 := f_sip_str_unquote(user) & ":" &
1088 f_sip_str_unquote(realm) & ":" &
1089 password;
1090 var charstring digestA1 := f_str_tolower(f_calculateMD5(A1));
1091 log("A1: md5('", A1, "') = ", digestA1);
1092 return digestA1;
1093}
1094
1095/* RFC 2617 3.2.2.2 A2 */
1096function f_sip_digest_A2(charstring method, charstring uri) return charstring {
1097
1098 var charstring A2 := method & ":" & uri
1099 var charstring digestA2 := f_str_tolower(f_calculateMD5(A2));
1100 log("A2: md5('", A2, "') = ", digestA2);
1101 return digestA2;
1102}
1103
1104/* RFC 2617 3.2.2.1 Request-Digest */
1105function f_sip_digest_RequestDigest(charstring digestA1, charstring nonce,
1106 charstring nc, charstring cnonce,
1107 charstring qop, charstring digestA2) return charstring {
1108 var charstring digest_data := f_sip_str_unquote(nonce) & ":" &
1109 nc & ":" &
1110 cnonce & ":" &
1111 f_sip_str_unquote(qop) & ":" &
1112 digestA2;
1113 var charstring req_digest := f_sip_digest_KD(digestA1, digest_data);
1114 log("Request-Digest: md5('", digestA1, ":", digest_data ,"') = ", req_digest);
1115 return req_digest;
1116}
1117
1118/* RFC 2617 3.2.1 The WWW-Authenticate Response Header
1119 * KD(secret, data) = H(concat(secret, ":", data))
1120 */
1121function f_sip_digest_KD(charstring secret, charstring data) return charstring {
1122 return f_str_tolower(f_calculateMD5(secret & ":" & data));
1123}
1124
1125/* Digest Auth: RFC 2617 */
1126function f_sip_digest_gen_Authorization(WwwAuthenticate www_authenticate,
1127 charstring user, charstring password,
1128 charstring method, charstring uri,
1129 charstring cnonce := "0a4f113b", integer nc_int := 1) return Authorization {
1130 var CommaParam_List digestCln;
1131 var template (value) Authorization authorization;
1132 var template (value) Credentials cred;
1133 var template (omit) GenericParam rx_param;
1134
1135 digestCln := www_authenticate.challenge[0].digestCln;
1136
1137 var charstring algorithm;
1138 rx_param := f_sip_param_find(digestCln, "algorithm");
1139 if (istemplatekind(rx_param, "omit")) {
1140 /* Assume MD5 if not set */
1141 algorithm := "MD5"
1142 } else {
1143 algorithm := valueof(rx_param.paramValue);
1144 if (f_strstr(algorithm, "MD5") == -1) {
1145 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1146 log2str("Unexpected algorithm: ", algorithm));
1147 }
1148 }
1149
1150 var charstring realm := f_sip_param_get_value_present_or_fail(digestCln, "realm");
1151 var charstring nonce := f_sip_param_get_value_present_or_fail(digestCln, "nonce");
1152 var charstring opaque := f_sip_param_get_value_present_or_fail(digestCln, "opaque");
1153 var charstring qop := f_sip_param_get_value_present_or_fail(digestCln, "qop");
1154
1155 if (f_strstr(qop, "auth") == -1) {
1156 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected qop: ", qop));
1157 }
1158 var charstring selected_qop := "auth";
1159
1160 /* RFC 2617 3.2.2.2 A1 */
1161 var charstring digestA1 := f_sip_digest_A1(user, realm, password);
1162 /* RFC 2617 3.2.2.3 A2 */
1163 var charstring digestA2 := f_sip_digest_A2(method, uri);
1164
1165 /* RFC 2617 3.2.2.1 Request-Digest */
1166 var charstring nc := f_str_tolower(hex2str(int2hex(nc_int, 8)));
1167 var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
1168 nc, cnonce,
1169 selected_qop, digestA2);
1170
1171 cred := ts_Credentials_DigestResponseMD5(user, realm, nonce,
1172 uri, req_digest,
1173 opaque, algorithm, selected_qop, cnonce, nc);
1174
1175 authorization := ts_Authorization(cred);
1176 return valueof(authorization);
1177}
1178
1179/* RFC 2617 3.5 Example */
1180function f_sip_digest_selftest() {
1181/*
1182The following example assumes that an access-protected document is
1183being requested from the server via a GET request. The URI of the
1184document is "http://www.nowhere.org/dir/index.html". Both client and
1185server know that the username for this document is "Mufasa", and the
1186password is "Circle Of Life" (with one space between each of the
1187three words).
1188
1189HTTP/1.1 401 Unauthorized
1190WWW-Authenticate: Digest
1191 realm="testrealm@host.com",
1192 qop="auth,auth-int",
1193 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1194 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1195
1196Authorization: Digest username="Mufasa",
1197 realm="testrealm@host.com",
1198 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1199 uri="/dir/index.html",
1200 qop=auth,
1201 nc=00000001,
1202 cnonce="0a4f113b",
1203 response="6629fae49393a05397450978507c4ef1",
1204 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1205*/
1206 var template (value) CommaParam_List digestCln := {
1207 ts_Param("realm", f_sip_str_quote("testrealm@host.com")),
1208 ts_Param("qop", f_sip_str_quote("auth,auth-int")),
1209 ts_Param("nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093")),
1210 ts_Param("opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"))
1211 };
1212 var template (value) WwwAuthenticate www_authenticate :=
1213 ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
1214
1215 var Authorization authorization :=
1216 f_sip_digest_gen_Authorization(valueof(www_authenticate),
1217 "Mufasa",
1218 "Circle Of Life",
1219 "GET",
1220 "/dir/index.html",
1221 cnonce := "0a4f113b",
1222 nc_int := 1);
1223
1224 var CommaParam_List digestResp := authorization.body.digestResponse;
1225 f_sip_param_match_value_or_fail(digestResp, "realm", f_sip_str_quote("testrealm@host.com"));
1226 f_sip_param_match_value_or_fail(digestResp, "nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093"));
1227 f_sip_param_match_value_or_fail(digestResp, "uri", f_sip_str_quote("/dir/index.html"));
1228 f_sip_param_match_value_or_fail(digestResp, "qop", "auth");
1229 f_sip_param_match_value_or_fail(digestResp, "nc", "00000001");
1230 f_sip_param_match_value_or_fail(digestResp, "cnonce", f_sip_str_quote("0a4f113b"));
1231 f_sip_param_match_value_or_fail(digestResp, "response", f_sip_str_quote("6629fae49393a05397450978507c4ef1"));
1232 f_sip_param_match_value_or_fail(digestResp, "opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"));
1233}
1234
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01001235/* RFC 3261 8.1.1.5:
1236 * "The sequence number value MUST be expressible as a 32-bit unsigned integer
1237 * and MUST be less than 2**31."
1238 */
1239function f_sip_rand_seq_nr() return integer {
1240 /* 2**31 = 2147483648 */
1241 return f_rnd_int(2147483648)
1242}
Harald Welteb0d93602018-03-20 18:09:34 +01001243
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001244function f_sip_next_seq_nr(integer seq_nr) return integer {
1245 return (seq_nr + 1) mod 2147483648;
1246}
1247
1248function f_sip_Request_inc_seq_nr(inout template (value) PDU_SIP_Request req) {
1249 req.msgHeader.cSeq.seqNumber := f_sip_next_seq_nr(valueof(req.msgHeader.cSeq.seqNumber));
1250}
1251
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001252function f_sip_rand_tag() return charstring {
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001253 /* Tags shall have at least 32 bit of randomness */
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001254 var integer rnd_int := f_rnd_int(4294967296);
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001255 /* Make collisions harder by appending time to the final string: */
1256 var integer ts_int := f_time_ms() mod 4294967296;
1257 return hex2str(int2hex(rnd_int, 8)) & "-" & hex2str(int2hex(ts_int, 8));
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001258}
1259
1260/* Generate a "branch" tag value.
1261 * RFC 3261 p.105 section 8:
1262 * "A common way to create this value is to compute a
1263 * cryptographic hash of the To tag, From tag, Call-ID header
1264 * field, the Request-URI of the request received (before
1265 * translation), the topmost Via header, and the sequence number
1266 * from the CSeq header field, in addition to any Proxy-Require
1267 * and Proxy-Authorization header fields that may be present. The
1268 * algorithm used to compute the hash is implementation-dependent,
1269 * but MD5 (RFC 1321 [35]),expressed in hexadecimal, is a reasonable
1270 * choice."
1271 * See also Section 8.1.1.7:
1272 * "The branch ID inserted by an element compliant with this
1273 * specification MUST always begin with the characters "z9hG4bK"."
1274 */
1275const charstring sip_magic_cookie := "z9hG4bK";
1276function f_sip_gen_branch(charstring tag_to,
1277 charstring tag_from,
1278 charstring tag_call_id,
1279 integer cseq) return charstring {
1280 var charstring str := tag_to & tag_from & tag_call_id & int2str(cseq);
1281 var charstring hash := f_calculateMD5(str);
1282 var charstring branch := sip_magic_cookie & hash;
1283 return branch;
1284}
1285
1286function f_sip_HostPort_to_str(HostPort host_port) return charstring {
1287 var charstring str := "";
1288 if (ispresent(host_port.host)) {
1289 str := host_port.host;
1290 }
1291 if (ispresent(host_port.portField)) {
1292 str := str & ":" & int2str(host_port.portField);
1293 }
1294 return str;
1295}
1296
1297function f_sip_SipUrl_to_str(SipUrl uri) return charstring {
1298 var charstring str := uri.scheme & f_sip_HostPort_to_str(uri.hostPort);
1299 return str;
1300}
1301
1302function f_sip_NameAddr_to_str(NameAddr naddr) return charstring {
1303 if (ispresent(naddr.displayName)) {
1304 return naddr.displayName & " <" & f_sip_SipUrl_to_str(naddr.addrSpec) & ">";
1305 } else {
1306 return f_sip_SipUrl_to_str(naddr.addrSpec);
1307 }
1308}
1309
1310function f_sip_SipAddr_to_str(SipAddr sip_addr) return charstring {
1311 if (ischosen(sip_addr.addr.nameAddr)) {
1312 return f_sip_NameAddr_to_str(sip_addr.addr.nameAddr);
1313 } else {
1314 return f_sip_SipUrl_to_str(sip_addr.addr.addrSpecUnion);
1315 }
1316}
1317
Harald Welteb0d93602018-03-20 18:09:34 +01001318}