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 <[email protected]>
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  */
47 enum {
48 	T_CBR23 = 100, T_nrtVBR2_6_UBR12, T_rtVBR236, T_rtVBR2_6
49 };
50 
51 static 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;
54 static 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 
58 static const u_int fcbr3 = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P;
59 static const u_int bcbr3 = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P;
60 static const u_int fvbr16 = UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_FSCR1_P |
61     UNI_TRAFFIC_FMBS1_P;
62 static const u_int bvbr16 = UNI_TRAFFIC_BPCR1_P | UNI_TRAFFIC_BSCR1_P |
63     UNI_TRAFFIC_BMBS1_P;
64 static const u_int fvbr23 = UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_FSCR0_P |
65     UNI_TRAFFIC_FMBS0_P;
66 static const u_int bvbr23 = UNI_TRAFFIC_BPCR1_P | UNI_TRAFFIC_BSCR0_P |
67     UNI_TRAFFIC_BMBS0_P;
68 static const u_int fvbr4 = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P;
69 static const u_int bvbr4 = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P;
70 
71 int
uni_classify_traffic(const struct uni_ie_bearer * bearer,const struct uni_ie_traffic * traffic,enum uni_traffic_class * fclass,enum uni_traffic_class * bclass,char * ebuf,size_t ebufsiz)72 uni_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