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/msg/traffic.c,v 1.4 2004/07/08 08:22:05 brandt Exp $
30 *
31 * Traffic classification
32 */
33
34#include <netnatm/unimsg.h>
35#include <netnatm/msg/unistruct.h>
36#include <netnatm/msg/unimsglib.h>
37#ifdef _KERNEL
38#include <sys/systm.h>
39#else
40#include <stdio.h>
41#endif
42
43/*
44 * Try to set the parameters for the CPCS from the parameters of the
45 * connection.
46 */
47enum {
48	T_CBR23 = 100, T_nrtVBR2_6_UBR12, T_rtVBR236, T_rtVBR2_6
49};
50
51static const u_int fmask = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P |
52    UNI_TRAFFIC_FSCR0_P | UNI_TRAFFIC_FSCR1_P | UNI_TRAFFIC_FMBS0_P |
53    UNI_TRAFFIC_FMBS1_P | UNI_TRAFFIC_FABR1_P;
54static const u_int bmask = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P |
55    UNI_TRAFFIC_BSCR0_P | UNI_TRAFFIC_BSCR1_P | UNI_TRAFFIC_BMBS0_P |
56    UNI_TRAFFIC_BMBS1_P | UNI_TRAFFIC_BABR1_P;
57
58static const u_int fcbr3 = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P;
59static const u_int bcbr3 = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P;
60static const u_int fvbr16 = UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_FSCR1_P |
61    UNI_TRAFFIC_FMBS1_P;
62static const u_int bvbr16 = UNI_TRAFFIC_BPCR1_P | UNI_TRAFFIC_BSCR1_P |
63    UNI_TRAFFIC_BMBS1_P;
64static const u_int fvbr23 = UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_FSCR0_P |
65    UNI_TRAFFIC_FMBS0_P;
66static const u_int bvbr23 = UNI_TRAFFIC_BPCR1_P | UNI_TRAFFIC_BSCR0_P |
67    UNI_TRAFFIC_BMBS0_P;
68static const u_int fvbr4 = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P;
69static const u_int bvbr4 = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P;
70
71int
72uni_classify_traffic(const struct uni_ie_bearer *bearer,
73    const struct uni_ie_traffic *traffic,
74    enum uni_traffic_class *fclass, enum uni_traffic_class *bclass,
75    char *ebuf, size_t ebufsiz)
76{
77	u_int tclass;
78	u_int ft, bt, be, ftag, btag;
79
80	/* classify */
81	switch (bearer->bclass) {
82
83	  case UNI_BEARER_A:
84		if (!(bearer->h.present & UNI_BEARER_ATC_P)) {
85			tclass = T_CBR23;
86			break;
87		}
88		switch (bearer->atc) {
89
90		  case UNI_BEARER_ATC_CBR1:
91			tclass = UNI_TRAFFIC_CBR1;
92			break;
93
94		  default:
95			snprintf(ebuf, ebufsiz, "bad ATC=%#02x for BCOB-A",
96			    bearer->atc);
97			return (-1);
98		}
99		break;
100
101	  case UNI_BEARER_C:
102		if (!(bearer->h.present & UNI_BEARER_ATC_P)) {
103			tclass = T_nrtVBR2_6_UBR12;
104			break;
105		}
106		switch (bearer->atc) {
107
108		  case UNI_BEARER_ATC_VBR1:
109			tclass = UNI_TRAFFIC_rtVBR1;
110			break;
111
112		  case UNI_BEARER_ATC_VBR:
113			tclass = T_rtVBR236;
114			break;
115
116		  case UNI_BEARER_ATC_NVBR1:
117			tclass = UNI_TRAFFIC_nrtVBR1;
118			break;
119
120		  case UNI_BEARER_ATC_ABR:
121			tclass = UNI_TRAFFIC_ABR;
122			break;
123
124		  default:
125			snprintf(ebuf, ebufsiz, "bad ATC=%#02x for BCOB-C",
126			    bearer->atc);
127			return (-1);
128		}
129		break;
130
131	  case UNI_BEARER_X:
132		if (!(bearer->h.present & UNI_BEARER_ATC_P)) {
133			tclass = T_nrtVBR2_6_UBR12;
134			break;
135		}
136		switch (bearer->atc) {
137
138		  case UNI_BEARER_ATC_CBR1:
139			tclass = UNI_TRAFFIC_CBR1;
140			break;
141
142		  case UNI_BEARER_ATC_CBR:
143		  case UNI_BEARER_ATCX_4:
144		  case UNI_BEARER_ATCX_6:
145			tclass = T_CBR23;
146			break;
147
148		  case UNI_BEARER_ATC_VBR1:
149			tclass = UNI_TRAFFIC_rtVBR1;
150			break;
151
152		  case UNI_BEARER_ATCX_1:
153		  case UNI_BEARER_ATC_VBR:
154			tclass = T_rtVBR2_6;
155			break;
156
157		  case UNI_BEARER_ATC_NVBR1:
158			tclass = UNI_TRAFFIC_nrtVBR1;
159			break;
160
161		  case UNI_BEARER_ATCX_0:
162		  case UNI_BEARER_ATCX_2:
163		  case UNI_BEARER_ATCX_8:
164		  case UNI_BEARER_ATC_NVBR:
165			tclass = T_nrtVBR2_6_UBR12;
166			break;
167
168		  case UNI_BEARER_ATC_ABR:
169			tclass = UNI_TRAFFIC_ABR;
170			break;
171
172		  default:
173			snprintf(ebuf, ebufsiz, "bad ATC=%#02x for BCOB-X",
174			    bearer->atc);
175			return (-1);
176		}
177		break;
178
179	  case UNI_BEARER_TVP:
180		snprintf(ebuf, ebufsiz, "unsupported bearer class tVP");
181		return (-1);
182
183	  default:
184		snprintf(ebuf, ebufsiz, "bad bearer class %#02x",
185		    bearer->bclass);
186		return (-1);
187	}
188
189	/*
190	 * Now traffic IE
191	 */
192	ft = traffic->h.present & fmask;
193	bt = traffic->h.present & bmask;
194	be = traffic->h.present & UNI_TRAFFIC_BEST_P;
195	ftag = (traffic->h.present & UNI_TRAFFIC_MOPT_P) && traffic->t.ftag;
196	btag = (traffic->h.present & UNI_TRAFFIC_MOPT_P) && traffic->t.btag;
197
198#define NOBE(C)								\
199	if (be) {							\
200		snprintf(ebuf, ebufsiz, "illegal BE for " C);		\
201		return (-1);						\
202	}
203
204#define NOFT(C)								\
205	if (ftag) {							\
206		snprintf(ebuf, ebufsiz, "illegal forward tag in " C);	\
207		return (-1);						\
208	}
209
210#define NOBT(C)								\
211	if (btag) {							\
212		snprintf(ebuf, ebufsiz, "illegal backward tag in " C);	\
213		return (-1);						\
214	}
215
216#define FBAD(C) do {							\
217	snprintf(ebuf, ebufsiz, "bad forward CRs for " C);		\
218	return (-1);							\
219    } while (0)
220
221#define BBAD(C) do {							\
222	snprintf(ebuf, ebufsiz, "bad backward CRs for " C);		\
223	return (-1);							\
224    } while (0)
225
226	switch (tclass) {
227
228	  case UNI_TRAFFIC_CBR1:
229		NOBE("CBR.1");
230		if (ft != UNI_TRAFFIC_FPCR1_P)
231			FBAD("CBR.1");
232		NOFT("CBR.1");
233		if (bt != UNI_TRAFFIC_BPCR1_P)
234			BBAD("CBR.1");
235		NOBT("CBR.1");
236		*fclass = *bclass = UNI_TRAFFIC_CBR1;
237		break;
238
239	  case T_CBR23:
240		NOBE("CBR.2/3");
241		if (ft == UNI_TRAFFIC_FPCR0_P) {
242			*fclass = UNI_TRAFFIC_CBR2;
243			NOFT("CBR.2");
244		} else if (ft == fcbr3) {
245			*fclass = UNI_TRAFFIC_CBR3;
246			if (!ftag) {
247				snprintf(ebuf, ebufsiz, "need forward tagging for CBR.3");
248				return (-1);
249			}
250		} else
251			FBAD("CBR.2/3");
252		if (bt == UNI_TRAFFIC_BPCR0_P) {
253			*bclass = UNI_TRAFFIC_CBR2;
254			NOBT("CBR.2");
255		} else if (bt == bcbr3) {
256			*bclass = UNI_TRAFFIC_CBR3;
257			if (!btag) {
258				snprintf(ebuf, ebufsiz, "need backward tagging for CBR.3");
259				return (-1);
260			}
261		} else
262			BBAD("CBR.2/3");
263		break;
264
265	  case UNI_TRAFFIC_rtVBR1:
266		NOBE("rtVBR.1");
267		if (ft != fvbr16)
268			FBAD("rtVBR.1");
269		NOFT("rtVBR.1");
270		if (bt != bvbr16)
271			BBAD("rtVBR.1");
272		NOBT("rtVBR.1");
273		*fclass = *bclass = UNI_TRAFFIC_rtVBR1;
274		break;
275
276	  case T_rtVBR236:
277		NOBE("rtVBR.2/3/6");
278		if (ft == fvbr23) {
279			if (ftag)
280				*fclass = UNI_TRAFFIC_rtVBR3;
281			else
282				*fclass = UNI_TRAFFIC_rtVBR2;
283		} else if (ft == fvbr16) {
284			*fclass = UNI_TRAFFIC_rtVBR6;
285			NOFT("rtVBR.6");
286		} else
287			FBAD("rtVBR.2/3/6");
288		if (bt == bvbr23) {
289			if (btag)
290				*bclass = UNI_TRAFFIC_rtVBR3;
291			else
292				*bclass = UNI_TRAFFIC_rtVBR2;
293		} else if (bt == bvbr16) {
294			*bclass = UNI_TRAFFIC_rtVBR6;
295			NOBT("rtVBR.6");
296		} else
297			BBAD("rtVBR.2/3/6");
298		break;
299
300	  case T_rtVBR2_6:
301		NOBE("rtVBR.2-6");
302		if (ft == fvbr23) {
303			if (ftag)
304				*fclass = UNI_TRAFFIC_rtVBR3;
305			else
306				*fclass = UNI_TRAFFIC_rtVBR2;
307		} else if (ft == fvbr4) {
308			*fclass = UNI_TRAFFIC_rtVBR4;
309		} else if (ft == UNI_TRAFFIC_FPCR1_P) {
310			*fclass = UNI_TRAFFIC_rtVBR5;
311			NOFT("rtVBR.5");
312		} else if (ft == fvbr16) {
313			*fclass = UNI_TRAFFIC_rtVBR6;
314			NOFT("rtVBR.6");
315		} else
316			FBAD("rtVBR.2-6");
317		if (bt == bvbr23) {
318			if (btag)
319				*bclass = UNI_TRAFFIC_rtVBR3;
320			else
321				*bclass = UNI_TRAFFIC_rtVBR2;
322		} else if (bt == bvbr4) {
323			*bclass = UNI_TRAFFIC_rtVBR4;
324		} else if (bt == UNI_TRAFFIC_BPCR1_P) {
325			*bclass = UNI_TRAFFIC_rtVBR5;
326			NOBT("rtVBR.5");
327		} else if (bt == bvbr16) {
328			*bclass = UNI_TRAFFIC_rtVBR6;
329			NOBT("rtVBR.6");
330		} else
331			BBAD("rtVBR.2-6");
332		break;
333
334	  case UNI_TRAFFIC_nrtVBR1:
335		NOBE("nrtVBR.1");
336		if (ft != fvbr16)
337			FBAD("nrtVBR.1");
338		NOFT("nrtVBR.1");
339		if (bt != bvbr16)
340			BBAD("nrtVBR.1");
341		NOBT("nrtVBR.1");
342		*fclass = *bclass = UNI_TRAFFIC_nrtVBR1;
343		break;
344
345	  case T_nrtVBR2_6_UBR12:
346		if (be) {
347			if (ft != UNI_TRAFFIC_FPCR1_P)
348				FBAD("UBR.1/2");
349			if (bt != UNI_TRAFFIC_BPCR1_P)
350				BBAD("UBR.1/2");
351			if (ftag)
352				*fclass = UNI_TRAFFIC_UBR2;
353			else
354				*fclass = UNI_TRAFFIC_UBR1;
355			if (btag)
356				*bclass = UNI_TRAFFIC_UBR2;
357			else
358				*bclass = UNI_TRAFFIC_UBR1;
359			break;
360		}
361		if (ft == fvbr23) {
362			if (ftag)
363				*fclass = UNI_TRAFFIC_nrtVBR3;
364			else
365				*fclass = UNI_TRAFFIC_nrtVBR2;
366		} else if (ft == fvbr4) {
367			*fclass = UNI_TRAFFIC_nrtVBR4;
368		} else if (ft == UNI_TRAFFIC_FPCR1_P) {
369			*fclass = UNI_TRAFFIC_nrtVBR5;
370			NOFT("nrtVBR.5");
371		} else if (ft == fvbr16) {
372			*fclass = UNI_TRAFFIC_nrtVBR6;
373			NOFT("nrtVBR.6");
374		} else
375			FBAD("nrtVBR.2-6");
376		if (bt == bvbr23) {
377			if (btag)
378				*bclass = UNI_TRAFFIC_nrtVBR3;
379			else
380				*bclass = UNI_TRAFFIC_nrtVBR2;
381		} else if (bt == bvbr4) {
382			*bclass = UNI_TRAFFIC_nrtVBR4;
383		} else if (bt == UNI_TRAFFIC_BPCR1_P) {
384			*bclass = UNI_TRAFFIC_nrtVBR5;
385			NOBT("nrtVBR.5");
386		} else if (bt == bvbr16) {
387			*bclass = UNI_TRAFFIC_nrtVBR6;
388			NOBT("nrtVBR.6");
389		} else
390			BBAD("nrtVBR.2-6");
391		break;
392
393	  case UNI_TRAFFIC_ABR:
394		NOBE("ABR");
395		if (ft != UNI_TRAFFIC_FPCR1_P)
396			FBAD("ABR");
397		if (bt != UNI_TRAFFIC_BPCR1_P)
398			BBAD("ABR");
399		NOFT("ABR");
400		NOBT("ABR");
401		*fclass = *bclass = UNI_TRAFFIC_ABR;
402		break;
403	}
404
405	return (0);
406}
407