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 const __u8 *hdr = RTA_DATA(tb[TCA_ATM_HDR]); 214 215 fprintf(f,"hdr"); 216 for (i = 0; i < RTA_PAYLOAD(tb[TCA_ATM_HDR]); i++) 217 fprintf(f,"%c%02x", i ? '.' : ' ', 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 = rta_getattr_u32(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