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