/* text2qos.c - Converts textual representation of QOS parameters to binary
encoding */
/* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include "atm.h"
#define fetch __atmlib_fetch
#define RATE_ERROR -2
int __t2q_get_rate(const char **text,int up)
{
const char mult[] = "kKmMgGg";
const char *multiplier;
char *end;
unsigned int rate,fract;
int power;
if (!strncmp(*text,"max",3)) {
*text += 3;
return ATM_MAX_PCR;
}
rate = strtoul(*text,&end,10);
power = fract = 0;
if (*end == '.')
for (end++; *end && isdigit(*end); end++) {
fract = fract*10+*end-48;
if (--power == -9) break;
}
multiplier = NULL;
if (*end && (multiplier = strchr(mult,*end))) {
while (multiplier >= mult) {
if (rate > UINT_MAX/1000) return RATE_ERROR;
rate *= 1000;
power += 3;
multiplier -= 2;
}
end++;
}
while (power && fract)
if (power < 0) {
fract /= 10;
power++;
}
else {
fract *= 10;
power--;
}
rate += fract;
if (strlen(end) < 3) {
if (multiplier) return RATE_ERROR;
}
else if (!strncmp(end,"cps",3)) end += 3;
else if (!strncmp(end,"bps",3)) {
rate = (rate+(up ? 8*ATM_CELL_PAYLOAD-1 : 0))/8/
ATM_CELL_PAYLOAD;
end += 3;
}
else if (multiplier) return RATE_ERROR;
if (rate > INT_MAX) return RATE_ERROR;
*text = end;
return rate;
}
static int params(const char **text,struct atm_trafprm *a,
struct atm_trafprm *b)
{
int value;
char *end;
if (*(*text)++ != ':') return -1;
while (1) {
if (!**text) return -1;
switch (fetch(text,"max_pcr=","pcr=","min_pcr=","max_sdu=","sdu=",
NULL)) {
case 0:
if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1;
if (a) a->max_pcr = value;
if (b) b->max_pcr = value;
break;
case 1:
if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1;
if (a) a->pcr = value;
if (b) b->pcr = value;
break;
case 2:
if ((value = __t2q_get_rate(text,1)) == RATE_ERROR) return -1;
if (value == ATM_MAX_PCR) return -1;
if (a) a->min_pcr = value;
if (b) b->min_pcr = value;
break;
case 3:
case 4:
value = strtol(*text,&end,10);
if (value < 0) return -1;
*text = end;
if (a) a->max_sdu = value;
if (b) b->max_sdu = value;
break;
default:
return 0;
}
if (!**text) break;
if (*(*text)++ != ',') return -1;
}
return 0;
}
int text2qos(const char *text,struct atm_qos *qos,int flags)
{
int traffic_class,aal;
traffic_class = ATM_NONE;
aal = ATM_NO_AAL;
do {
static const unsigned char aal_number[] = { ATM_AAL0, ATM_AAL5 };
int item;
item = fetch(&text,"!none","ubr","cbr","vbr","abr","aal0","aal5",NULL);
switch (item) {
case 1:
case 2:
/* we don't support VBR yet */
case 4:
traffic_class = item;
break;
case 5:
case 6:
aal = aal_number[item-5];
break;
default:
return -1;
}
}
while (*text == ',' ? text++ : 0);
if (!traffic_class) return -1;
if (qos && !(flags & T2Q_DEFAULTS)) memset(qos,0,sizeof(*qos));
if (qos) qos->txtp.traffic_class = qos->rxtp.traffic_class = traffic_class;
if (qos && aal) qos->aal = aal;
if (!*text) return 0;
if (params(&text,qos ? &qos->txtp : NULL,qos ? &qos->rxtp : NULL))
return -1;
if (!*text) return 0;
switch (fetch(&text,"tx","rx",NULL)) {
case 0:
if (!fetch(&text,":none",NULL)) {
if (qos) qos->txtp.traffic_class = ATM_NONE;
if (*text == ',') text++;
break;
}
if (params(&text,qos ? &qos->txtp : NULL,NULL)) return -1;
break;
case 1:
text -= 2;
break;
default:
return -1;
}
if (!*text) return 0;
if (fetch(&text,"rx",NULL)) return -1;
if (!fetch(&text,":none",NULL) && qos) qos->rxtp.traffic_class = ATM_NONE;
else if (params(&text,qos ? &qos->rxtp : NULL,NULL)) return -1;
return *text ? -1 : 0;
}