]>
Commit | Line | Data |
---|---|---|
aba5acdf SH |
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 = (struct rtattr *) (((void *) n)+NLMSG_ALIGN(n->nlmsg_len)); | |
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 *) n)+NLMSG_ALIGN(n->nlmsg_len))-(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) return 0; | |
199 | memset(tb, 0, sizeof(tb)); | |
200 | parse_rtattr(tb, TCA_ATM_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)); | |
201 | if (tb[TCA_ATM_ADDR]) { | |
202 | if (RTA_PAYLOAD(tb[TCA_ATM_ADDR]) < | |
203 | sizeof(struct sockaddr_atmpvc)) | |
204 | fprintf(stderr,"ATM: address too short\n"); | |
205 | else { | |
206 | if (atm2text(buffer,MAX_ATM_ADDR_LEN, | |
207 | RTA_DATA(tb[TCA_ATM_ADDR]),A2T_PRETTY | A2T_NAME) < | |
208 | 0) fprintf(stderr,"atm2text error\n"); | |
209 | fprintf(f,"pvc %s ",buffer); | |
210 | } | |
211 | } | |
212 | if (tb[TCA_ATM_HDR]) { | |
213 | int i; | |
214 | ||
215 | fprintf(f,"hdr"); | |
216 | for (i = 0; i < RTA_PAYLOAD(tb[TCA_ATM_HDR]); i++) | |
217 | fprintf(f,"%c%02x",i ? '.' : ' ', | |
218 | ((unsigned char *) RTA_DATA(tb[TCA_ATM_HDR]))[i]); | |
219 | if (!i) fprintf(f," ."); | |
220 | fprintf(f," "); | |
221 | } | |
222 | if (tb[TCA_ATM_EXCESS]) { | |
223 | __u32 excess; | |
224 | ||
225 | if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS]) < sizeof(excess)) | |
226 | fprintf(stderr,"ATM: excess class ID too short\n"); | |
227 | else { | |
228 | excess = *(__u32 *) RTA_DATA(tb[TCA_ATM_EXCESS]); | |
229 | if (!excess) fprintf(f,"excess clp "); | |
230 | else { | |
231 | char buf[64]; | |
232 | ||
233 | print_tc_classid(buf,sizeof(buf),excess); | |
234 | fprintf(f,"excess %s ",buf); | |
235 | } | |
236 | } | |
237 | } | |
238 | if (tb[TCA_ATM_STATE]) { | |
239 | static const char *map[] = { ATM_VS2TXT_MAP }; | |
240 | int state; | |
241 | ||
242 | if (RTA_PAYLOAD(tb[TCA_ATM_STATE]) < sizeof(state)) | |
243 | fprintf(stderr,"ATM: state field too short\n"); | |
244 | else { | |
245 | state = *(int *) RTA_DATA(tb[TCA_ATM_STATE]); | |
246 | fprintf(f,"%s ",map[state]); | |
247 | } | |
248 | } | |
249 | return 0; | |
250 | } | |
251 | ||
252 | ||
253 | static int atm_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) | |
254 | { | |
255 | return 0; | |
256 | } | |
257 | ||
258 | ||
259 | struct qdisc_util atm_util = { | |
260 | NULL, | |
261 | "atm", | |
262 | atm_parse_opt, | |
263 | atm_print_opt, | |
264 | atm_print_xstats, | |
265 | ||
266 | atm_parse_class_opt, | |
267 | atm_print_opt | |
268 | }; |