1/*
2 * Copyright (c) 2001-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 *
29 * $Begemot: libunimsg/netnatm/sig/sig_verify.c,v 1.19 2004/07/08 08:22:23 brandt Exp $
30 *
31 * Message verification with explicit action indicators.
32 */
33
34#include <netnatm/unimsg.h>
35#include <netnatm/saal/sscfudef.h>
36#include <netnatm/msg/unistruct.h>
37#include <netnatm/msg/unimsglib.h>
38#include <netnatm/sig/uni.h>
39
40#include <netnatm/sig/unipriv.h>
41#include <netnatm/sig/unimkmsg.h>
42
43void
44uni_mandate_ie(struct uni *uni, enum uni_ietype ie)
45{
46	struct uni_ierr *e;
47
48	FOREACH_ERR(e, uni)
49		if (e->ie == ie) {
50			e->man = 1;
51			return;
52		}
53	if (UNI_SAVE_IERR(&uni->cx, ie, UNI_IEACT_DEFAULT, UNI_IERR_MIS))
54		uni->cx.err[uni->cx.errcnt - 1].man = 1;
55}
56
57/*
58 * This special handling is required for ADD PARTY, PARTY ALERTING and
59 * ADD PARTY ACKNOWLEDGE by Q.2971 9.5.3.2.1.
60 * It means, that the EPREF should be handled as mandatory only if
61 * no other IEs have explicit action indicators.
62 */
63void
64uni_mandate_epref(struct uni *uni, struct uni_ie_epref *epref)
65{
66	struct uni_ierr *e;
67	int maxact;
68
69	if (!IE_ISPRESENT(*epref)) {
70		/*
71		 * 9.5.3.2.1 -- missing endpoint reference
72		 */
73
74		/*
75		 * a) if any unrecognized or IE with error has a CLEAR
76		 *    action indicator, this takes precedence.
77		 * b) if any unrecognized or IE with error has a
78		 *    discard message and report action indicator, this takes
79		 *    precedence.
80		 * c) if any unrecognized or IE with error has a
81		 *    discard message action indicator, this takes
82		 *    precedence.
83		 *
84		 * In any of these cases we must remove the EPREF IE
85		 * if it has CLEAR, otherwise the CLEAR would take over.
86		 */
87		maxact = -1;
88		FOREACH_ERR(e, uni) {
89			if (e->ie == UNI_IE_EPREF)
90				continue;
91			if (e->act == UNI_IEACT_CLEAR)
92				maxact = UNI_IEACT_CLEAR;
93			else if (e->act == UNI_IEACT_MSG_REPORT) {
94				if (maxact == -1 && maxact != UNI_IEACT_CLEAR)
95					maxact = UNI_IEACT_MSG_REPORT;
96			} else if (e->act == UNI_IEACT_MSG_IGNORE) {
97				if (maxact == -1)
98					maxact = UNI_IEACT_MSG_IGNORE;
99			}
100		}
101
102		if (maxact != -1) {
103			/* ok, second pass to remove UNI_IE_EPREF */
104			FOREACH_ERR(e, uni)
105				if (e->ie == UNI_IE_EPREF) {
106					memmove(e, e + 1,
107					    (uni->cx.errcnt - (e - uni->cx.err)
108					    - 1) * sizeof(uni->cx.err[0]));
109					uni->cx.errcnt--;
110					break;
111				}
112			return;
113
114		}
115
116		/*
117		 * d) if nothing of the above, the IE is mandatory
118		 */
119		uni_mandate_ie(uni, UNI_IE_EPREF);
120		return;
121
122	}
123	if (IE_ISGOOD(*epref))
124		return;
125
126	/*
127	 * It has an error obviously
128	 * 9.5.3.2.2
129	 *
130	 * It turns out, that Q.2931 handling just does the right thing
131	 * if we don't mandate the IE.
132	 */
133	return;
134}
135
136/*
137 * Look, what to do with this message. We assume, that the message itself is
138 * recognized.
139 *
140 * This is rather complicated. We must use the information provided in the
141 * fields of the context, because IEs with length errors may not be set
142 * altogether.
143 */
144enum verify
145uni_verify(struct uni *uni, enum uni_msgact msgact)
146{
147	struct uni_ierr *e1;
148
149	if (uni->debug[UNI_FAC_VERIFY] >= 2) {
150		FOREACH_ERR(e1, uni) {
151			VERBOSE(uni, UNI_FAC_VERIFY, 2, "ie=%02x err=%u man=%d"
152			    " act=%u", e1->ie, e1->err, e1->man, e1->act);
153		}
154	}
155
156	/*
157	 * Look for missing mandatory IEs. The action indicator is ignored
158	 * according to 5.6.7.1. If IEs are missing the action is to
159	 * ignore the message and report status for all messages except
160	 * RELEASE, RELEASE_COMPLETE and SETUP. Because we must differentiate
161	 * this RAI from other RAIs in this case, use another return code.
162	 * Note, that mandatory IEs with errors are not handled here.
163	 */
164	FOREACH_ERR(e1, uni) {
165		if (e1->err == UNI_IERR_MIS) {
166			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
167			    UNI_CAUSE_MANDAT);
168			VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAIM");
169			return (VFY_RAIM);
170		}
171	}
172
173	/*
174	 * When any IE with error specifies a CLR action indicator, this
175	 * takes precedence obviously. There are two cases here:
176	 * unrecognized IEs and IEs with error. So we look through the
177	 * error array twice and send only one STATUS. Unrecognized will
178	 * take precedence.
179	 *
180	 * 5.7.2a)
181	 */
182	FOREACH_ERR(e1, uni) {
183		if (e1->act == UNI_IEACT_CLEAR && e1->err == UNI_IERR_UNK) {
184			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
185			    UNI_CAUSE_IE_NIMPL);
186			VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR1");
187			return (VFY_CLR);
188		}
189	}
190
191	FOREACH_ERR(e1, uni) {
192		if (e1->act == UNI_IEACT_CLEAR &&
193		   (e1->err == UNI_IERR_LEN || e1->err == UNI_IERR_BAD ||
194		    e1->err == UNI_IERR_ACC)) {
195			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
196			    UNI_CAUSE_IE_INV);
197			VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR2");
198			return (VFY_CLR);
199		}
200	}
201
202	/*
203	 * Now check, whether anybody wants to explicitly ignore the message
204	 * and report status.
205	 *
206	 * 5.7.2a)
207	 */
208	FOREACH_ERR(e1, uni) {
209		if (e1->act == UNI_IEACT_MSG_REPORT && e1->err == UNI_IERR_UNK) {
210			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
211			    UNI_CAUSE_IE_NIMPL);
212			VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
213			return (VFY_RAI);
214		}
215	}
216
217	FOREACH_ERR(e1, uni) {
218		if (e1->act == UNI_IEACT_MSG_REPORT &&
219		   (e1->err == UNI_IERR_LEN || e1->err == UNI_IERR_BAD ||
220		    e1->err == UNI_IERR_ACC)) {
221			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
222			    UNI_CAUSE_IE_INV);
223			VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
224			return (VFY_RAI);
225		}
226	}
227
228	/*
229	 * Now look whether some IE wants to explicitely ignore the message
230	 * without any report.
231	 */
232	FOREACH_ERR(e1, uni) {
233		if (e1->act == UNI_IEACT_MSG_IGNORE) {
234			VERBOSE(uni, UNI_FAC_VERIFY, 1, "I1");
235			return (VFY_I);
236		}
237	}
238
239	/*
240	 * At this point we have left only
241	 *  mandatory and non-mandatory IEs with error that want the IE to be
242	 *  ignored or ignored with report or defaulted.
243	 * Because a mandatory IE with errors lead to
244	 * the message beeing ignored, we make this of higher
245	 * precedence, than the rest.
246	 */
247	FOREACH_ERR(e1, uni) {
248		if (e1->man) {
249			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
250			    UNI_CAUSE_MANDAT);
251			VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
252			return (VFY_RAI);
253		}
254	}
255
256	/*
257	 * Now look for ignoring the IE and reporting. This takes precedence
258	 * over simply ignoring it. We also collect defaulted (non-mandatory)
259	 * IEs.
260	 *
261	 * 5.7.2d) and 5.6.8.1
262	 */
263	FOREACH_ERR(e1, uni) {
264		if ((e1->act == UNI_IEACT_DEFAULT ||
265		     e1->act == UNI_IEACT_REPORT)
266		    && e1->err != UNI_IERR_UNK) {
267			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
268			    UNI_CAUSE_IE_INV);
269			VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAP");
270			return (VFY_RAP);
271		}
272	}
273
274	FOREACH_ERR(e1, uni) {
275		if ((e1->act == UNI_IEACT_DEFAULT ||
276		     e1->act == UNI_IEACT_REPORT)
277		    && e1->err == UNI_IERR_UNK) {
278			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
279			    UNI_CAUSE_IE_NIMPL);
280			VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAPU");
281			return (VFY_RAPU);
282		}
283	}
284
285	/*
286	 * This leaves us with IEs, that want to be ignored. Among these may
287	 * be mandatory IEs. If we have an mandatory IEs here in the error
288	 * array, then the message wil not contain enough information and
289	 * must be handled according to 5.8 as either in 5.6.7.1 (this
290	 * means, that mandatory IEs cannot really be ignored) or 5.7.1.
291	 */
292	FOREACH_ERR(e1, uni) {
293		if (e1->man) {
294			MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
295			    UNI_CAUSE_MANDAT);
296			if (msgact == UNI_MSGACT_CLEAR) {
297				VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR3");
298				return (VFY_CLR);
299			}
300			if (msgact == UNI_MSGACT_IGNORE) {
301				VERBOSE(uni, UNI_FAC_VERIFY, 1, "I2");
302				return (VFY_I);
303			}
304			VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
305			return (VFY_RAI);
306		}
307	}
308
309	/*
310	 * Now only non-mandatory IEs are left, that want to be explicitely
311	 * ignored.
312	 */
313	if (uni->cx.errcnt != 0)
314		MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
315		    UNI_CAUSE_IE_INV);
316
317	VERBOSE(uni, UNI_FAC_VERIFY, 1, "OK");
318	return (VFY_OK);
319}
320
321/*
322 * Collect the IE identifiers for some of the known cause codes.
323 */
324void
325uni_vfy_collect_ies(struct uni *uni)
326{
327	struct uni_ierr *e;
328
329#define STUFF_IE(IE)						\
330	uni->cause.u.ie.ie[uni->cause.u.ie.len++] = (IE);	\
331	if (uni->cause.u.ie.len == UNI_CAUSE_IE_N)		\
332		break;
333
334	uni->cause.u.ie.len = 0;
335	if (uni->cause.cause == UNI_CAUSE_MANDAT) {
336		FOREACH_ERR(e, uni) {
337			if (e->err == UNI_IERR_MIS || e->man != 0) {
338				STUFF_IE(e->ie);
339			}
340		}
341
342	} else if (uni->cause.cause == UNI_CAUSE_IE_NIMPL) {
343		FOREACH_ERR(e, uni) {
344			if (e->err == UNI_IERR_UNK) {
345				STUFF_IE(e->ie);
346			}
347		}
348
349	} else if (uni->cause.cause == UNI_CAUSE_IE_INV) {
350		FOREACH_ERR(e, uni) {
351			if (e->err == UNI_IERR_LEN ||
352			    e->err == UNI_IERR_BAD ||
353			    e->err == UNI_IERR_ACC) {
354				STUFF_IE(e->ie);
355			}
356		}
357	} else
358		return;
359
360	if (uni->cause.u.ie.len != 0)
361		uni->cause.h.present |= UNI_CAUSE_IE_P;
362}
363
364
365void
366uni_respond_status_verify(struct uni *uni, struct uni_cref *cref,
367    enum uni_callstate cs, struct uni_ie_epref *epref,
368    enum uni_epstate ps)
369{
370	struct uni_all *resp;
371
372	if ((resp = UNI_ALLOC()) == NULL)
373		return;
374
375	uni_vfy_collect_ies(uni);
376
377	MK_MSG_RESP(resp, UNI_STATUS, cref);
378	MK_IE_CALLSTATE(resp->u.status.callstate, cs);
379	resp->u.status.cause = uni->cause;
380	if (epref && IE_ISGOOD(*epref)) {
381		MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag);
382		MK_IE_EPSTATE(resp->u.status.epstate, ps);
383	}
384
385	uni_send_output(resp, uni);
386
387	UNI_FREE(resp);
388}
389
390/*
391 * Handling of Q.2971 9.5.8.1:
392 */
393void
394uni_vfy_remove_unknown(struct uni *uni)
395{
396	struct uni_ierr *e1, *e0;
397	int flag = 0;
398
399	FOREACH_ERR(e1, uni) {
400		if (e1->err == UNI_IERR_UNK) {
401			if (e1->act == UNI_IEACT_CLEAR ||
402			    e1->act == UNI_IEACT_MSG_IGNORE ||
403			    e1->act == UNI_IEACT_MSG_REPORT)
404				return;
405			if (e1->act == UNI_IEACT_REPORT ||
406			    e1->act == UNI_IEACT_DEFAULT)
407				flag = 1;
408		}
409	}
410	if (flag)
411		return;
412	e0 = e1 = uni->cx.err;
413	while (e1 < uni->cx.err + uni->cx.errcnt) {
414		if (e1->err != UNI_IERR_UNK) {
415			if (e0 != e1)
416				*e0 = *e1;
417			e0++;
418		}
419		e1++;
420	}
421	uni->cx.errcnt = e0 - uni->cx.err;
422}
423
424/*
425 * Handling for ADD_PARTY_REJ and DROP_PARTY_ACK with bad cause
426 */
427void
428uni_vfy_remove_cause(struct uni *uni)
429{
430	struct uni_ierr *e1, *e0;
431
432	e0 = e1 = uni->cx.err;
433	while (e1 < uni->cx.err + uni->cx.errcnt) {
434		if (e1->ie != UNI_IE_CAUSE) {
435			if (e0 != e1)
436				*e0 = *e1;
437			e0++;
438		}
439		e1++;
440	}
441	uni->cx.errcnt = e0 - uni->cx.err;
442}
443