Home | History | Annotate | Download | only in tc
      1 /*
      2  * q_atm.c		ATM.
      3  *
      4  * Hacked 1998-2000 by Werner Almesberger, EPFL ICA
      5  *
      6  */
      7 
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <unistd.h>
     11 #include <ctype.h>
     12 #include <syslog.h>
     13 #include <fcntl.h>
     14 #include <sys/socket.h>
     15 #include <sys/ioctl.h>
     16 #include <netinet/in.h>
     17 #include <arpa/inet.h>
     18 #include <string.h>
     19 #include <atm.h>
     20 #include <linux/atmdev.h>
     21 #include <linux/atmarp.h>
     22 
     23 #include "utils.h"
     24 #include "tc_util.h"
     25 
     26 
     27 #define MAX_HDR_LEN 64
     28 
     29 
     30 static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
     31 {
     32 	if (argc) {
     33 		fprintf(stderr,"Usage: atm\n");
     34 		return -1;
     35 	}
     36 	return 0;
     37 }
     38 
     39 
     40 static void explain(void)
     41 {
     42 	fprintf(stderr, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) "
     43 	    "[ qos QOS ] [ sndbuf BYTES ]\n");
     44 	fprintf(stderr, "  [ hdr HEX... ] [ excess ( CLASSID | clp ) ] "
     45 	  "[ clip ]\n");
     46 }
     47 
     48 
     49 static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
     50    struct nlmsghdr *n)
     51 {
     52 	struct sockaddr_atmsvc addr;
     53 	struct atm_qos qos;
     54 	struct atm_sap sap;
     55 	unsigned char hdr[MAX_HDR_LEN];
     56 	__u32 excess = 0;
     57 	struct rtattr *tail;
     58 	int sndbuf = 0;
     59 	int hdr_len = -1;
     60 	int set_clip = 0;
     61 	int s;
     62 
     63 	memset(&addr,0,sizeof(addr));
     64 	(void) text2qos("aal5,ubr:sdu=9180,rx:none",&qos,0);
     65 	(void) text2sap("blli:l2=iso8802",&sap,0);
     66 	while (argc > 0) {
     67 		if (!strcmp(*argv,"pvc")) {
     68 			NEXT_ARG();
     69 			if (text2atm(*argv,(struct sockaddr *) &addr,
     70 			    sizeof(addr),T2A_PVC | T2A_NAME) < 0) {
     71 				explain();
     72 				return -1;
     73 			}
     74 		}
     75 		else if (!strcmp(*argv,"svc")) {
     76 			NEXT_ARG();
     77 			if (text2atm(*argv,(struct sockaddr *) &addr,
     78 			    sizeof(addr),T2A_SVC | T2A_NAME) < 0) {
     79 				explain();
     80 				return -1;
     81 			}
     82 		}
     83 		else if (!strcmp(*argv,"qos")) {
     84 			NEXT_ARG();
     85 			if (text2qos(*argv,&qos,0) < 0) {
     86 				explain();
     87 				return -1;
     88 			}
     89 		}
     90 		else if (!strcmp(*argv,"sndbuf")) {
     91 			char *end;
     92 
     93 			NEXT_ARG();
     94 			sndbuf = strtol(*argv,&end,0);
     95 			if (*end) {
     96 				explain();
     97 				return -1;
     98 			}
     99 		}
    100 		else if (!strcmp(*argv,"sap")) {
    101 			NEXT_ARG();
    102 			if (addr.sas_family != AF_ATMSVC ||
    103 			    text2sap(*argv,&sap,T2A_NAME) < 0) {
    104 				explain();
    105 				return -1;
    106 			}
    107 		}
    108 		else if (!strcmp(*argv,"hdr")) {
    109 			unsigned char *ptr;
    110 			char *walk;
    111 
    112 			NEXT_ARG();
    113 			ptr = hdr;
    114 			for (walk = *argv; *walk; walk++) {
    115 				int tmp;
    116 
    117 				if (ptr == hdr+MAX_HDR_LEN) {
    118 					fprintf(stderr,"header is too long\n");
    119 					return -1;
    120 				}
    121 				if (*walk == '.') continue;
    122 				if (!isxdigit(walk[0]) || !walk[1] ||
    123 				    !isxdigit(walk[1])) {
    124 					explain();
    125 					return -1;
    126 				}
    127 				sscanf(walk,"%2x",&tmp);
    128 				*ptr++ = tmp;
    129 				walk++;
    130 			}
    131 			hdr_len = ptr-hdr;
    132 		}
    133 		else if (!strcmp(*argv,"excess")) {
    134 			NEXT_ARG();
    135 			if (!strcmp(*argv,"clp")) excess = 0;
    136 			else if (get_tc_classid(&excess,*argv)) {
    137 					explain();
    138 					return -1;
    139 				}
    140 		}
    141 		else if (!strcmp(*argv,"clip")) {
    142 			set_clip = 1;
    143 		}
    144 		else {
    145 			explain();
    146 			return 1;
    147 		}
    148 		argc--;
    149 		argv++;
    150 	}
    151 	s = socket(addr.sas_family,SOCK_DGRAM,0);
    152 	if (s < 0) {
    153 		perror("socket");
    154 		return -1;
    155 	}
    156 	if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) {
    157 		perror("SO_ATMQOS");
    158 		return -1;
    159 	}
    160 	if (sndbuf)
    161 	    if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
    162 		perror("SO_SNDBUF");
    163 	    return -1;
    164 	}
    165 	if (addr.sas_family == AF_ATMSVC && setsockopt(s,SOL_ATM,SO_ATMSAP,
    166 	    &sap,sizeof(sap)) < 0) {
    167 		perror("SO_ATMSAP");
    168 		return -1;
    169 	}
    170 	if (connect(s,(struct sockaddr *) &addr,addr.sas_family == AF_ATMPVC ?
    171 	    sizeof(struct sockaddr_atmpvc) : sizeof(addr)) < 0) {
    172 		perror("connect");
    173 		return -1;
    174 	}
    175 	if (set_clip)
    176 		if (ioctl(s,ATMARP_MKIP,0) < 0) {
    177 			perror("ioctl ATMARP_MKIP");
    178 			return -1;
    179 		}
    180 	tail = NLMSG_TAIL(n);
    181 	addattr_l(n,1024,TCA_OPTIONS,NULL,0);
    182 	addattr_l(n,1024,TCA_ATM_FD,&s,sizeof(s));
    183 	if (excess) addattr_l(n,1024,TCA_ATM_EXCESS,&excess,sizeof(excess));
    184 	if (hdr_len != -1) addattr_l(n,1024,TCA_ATM_HDR,hdr,hdr_len);
    185 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
    186 	return 0;
    187 }
    188 
    189 
    190 
    191 static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
    192 {
    193 	struct rtattr *tb[TCA_ATM_MAX+1];
    194 	char buffer[MAX_ATM_ADDR_LEN+1];
    195 
    196 	if (opt == NULL)
    197 		return 0;
    198 
    199 	parse_rtattr_nested(tb, TCA_ATM_MAX, opt);
    200 	if (tb[TCA_ATM_ADDR]) {
    201 		if (RTA_PAYLOAD(tb[TCA_ATM_ADDR]) <
    202 		    sizeof(struct sockaddr_atmpvc))
    203 			fprintf(stderr,"ATM: address too short\n");
    204 		else {
    205 			if (atm2text(buffer,MAX_ATM_ADDR_LEN,
    206 			    RTA_DATA(tb[TCA_ATM_ADDR]),A2T_PRETTY | A2T_NAME) <
    207 			    0) fprintf(stderr,"atm2text error\n");
    208 			fprintf(f,"pvc %s ",buffer);
    209 		}
    210 	}
    211 	if (tb[TCA_ATM_HDR]) {
    212 		int i;
    213 
    214 		fprintf(f,"hdr");
    215 		for (i = 0; i < RTA_PAYLOAD(tb[TCA_ATM_HDR]); i++)
    216 			fprintf(f,"%c%02x",i ? '.' : ' ',
    217 			    ((unsigned char *) RTA_DATA(tb[TCA_ATM_HDR]))[i]);
    218 		if (!i) fprintf(f," .");
    219 		fprintf(f," ");
    220 	}
    221 	if (tb[TCA_ATM_EXCESS]) {
    222 		__u32 excess;
    223 
    224 		if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS]) < sizeof(excess))
    225 			fprintf(stderr,"ATM: excess class ID too short\n");
    226 		else {
    227 			excess = *(__u32 *) RTA_DATA(tb[TCA_ATM_EXCESS]);
    228 			if (!excess) fprintf(f,"excess clp ");
    229 			else {
    230 				char buf[64];
    231 
    232 				print_tc_classid(buf,sizeof(buf),excess);
    233 				fprintf(f,"excess %s ",buf);
    234 			}
    235 		}
    236 	}
    237 	if (tb[TCA_ATM_STATE]) {
    238 		static const char *map[] = { ATM_VS2TXT_MAP };
    239 		int state;
    240 
    241 		if (RTA_PAYLOAD(tb[TCA_ATM_STATE]) < sizeof(state))
    242 			fprintf(stderr,"ATM: state field too short\n");
    243 		else {
    244 			state = *(int *) RTA_DATA(tb[TCA_ATM_STATE]);
    245 			fprintf(f,"%s ",map[state]);
    246 		}
    247 	}
    248 	return 0;
    249 }
    250 
    251 
    252 struct qdisc_util atm_qdisc_util = {
    253 	.id 		= "atm",
    254 	.parse_qopt	= atm_parse_opt,
    255 	.print_qopt	= atm_print_opt,
    256 	.parse_copt	= atm_parse_class_opt,
    257 	.print_copt	= atm_print_opt,
    258 };
    259