4 * Hacked 1998-2000 by Werner Almesberger, EPFL ICA
13 #include <sys/socket.h>
14 #include <sys/ioctl.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
19 #include <linux/atmdev.h>
20 #include <linux/atmarp.h>
26 #define MAX_HDR_LEN 64
29 static int atm_parse_opt(struct qdisc_util
*qu
, int argc
, char **argv
, struct nlmsghdr
*n
, const char *dev
)
32 fprintf(stderr
, "Usage: atm\n");
39 static void explain(void)
41 fprintf(stderr
, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) [ qos QOS ] [ sndbuf BYTES ]\n");
42 fprintf(stderr
, " [ hdr HEX... ] [ excess ( CLASSID | clp ) ] [ clip ]\n");
46 static int atm_parse_class_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
47 struct nlmsghdr
*n
, const char *dev
)
49 struct sockaddr_atmsvc addr
= {};
52 unsigned char hdr
[MAX_HDR_LEN
];
60 (void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos
, 0);
61 (void) text2sap("blli:l2=iso8802", &sap
, 0);
63 if (!strcmp(*argv
, "pvc")) {
65 if (text2atm(*argv
, (struct sockaddr
*) &addr
,
66 sizeof(addr
), T2A_PVC
| T2A_NAME
) < 0) {
70 } else if (!strcmp(*argv
,"svc")) {
72 if (text2atm(*argv
, (struct sockaddr
*) &addr
,
73 sizeof(addr
), T2A_SVC
| T2A_NAME
) < 0) {
77 } else if (!strcmp(*argv
,"qos")) {
79 if (text2qos(*argv
, &qos
, 0) < 0) {
83 } else if (!strcmp(*argv
,"sndbuf")) {
87 sndbuf
= strtol(*argv
, &end
, 0);
92 } else if (!strcmp(*argv
,"sap")) {
94 if (addr
.sas_family
!= AF_ATMSVC
||
95 text2sap(*argv
, &sap
, T2A_NAME
) < 0) {
99 } else if (!strcmp(*argv
,"hdr")) {
105 for (walk
= *argv
; *walk
; walk
++) {
108 if (ptr
== hdr
+MAX_HDR_LEN
) {
109 fprintf(stderr
, "header is too long\n");
112 if (*walk
== '.') continue;
113 if (!isxdigit(walk
[0]) || !walk
[1] ||
114 !isxdigit(walk
[1])) {
118 sscanf(walk
, "%2x", &tmp
);
123 } else if (!strcmp(*argv
,"excess")) {
125 if (!strcmp(*argv
, "clp")) excess
= 0;
126 else if (get_tc_classid(&excess
, *argv
)) {
130 } else if (!strcmp(*argv
,"clip")) {
139 s
= socket(addr
.sas_family
, SOCK_DGRAM
, 0);
144 if (setsockopt(s
, SOL_ATM
, SO_ATMQOS
, &qos
, sizeof(qos
)) < 0) {
149 if (setsockopt(s
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
)) < 0) {
153 if (addr
.sas_family
== AF_ATMSVC
&& setsockopt(s
, SOL_ATM
, SO_ATMSAP
,
154 &sap
, sizeof(sap
)) < 0) {
158 if (connect(s
, (struct sockaddr
*) &addr
, addr
.sas_family
== AF_ATMPVC
?
159 sizeof(struct sockaddr_atmpvc
) : sizeof(addr
)) < 0) {
164 if (ioctl(s
, ATMARP_MKIP
, 0) < 0) {
165 perror("ioctl ATMARP_MKIP");
168 tail
= NLMSG_TAIL(n
);
169 addattr_l(n
, 1024, TCA_OPTIONS
, NULL
, 0);
170 addattr_l(n
, 1024, TCA_ATM_FD
, &s
, sizeof(s
));
171 if (excess
) addattr_l(n
, 1024, TCA_ATM_EXCESS
, &excess
, sizeof(excess
));
172 if (hdr_len
!= -1) addattr_l(n
, 1024, TCA_ATM_HDR
, hdr
, hdr_len
);
173 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
179 static int atm_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
181 struct rtattr
*tb
[TCA_ATM_MAX
+1];
182 char buffer
[MAX_ATM_ADDR_LEN
+1];
187 parse_rtattr_nested(tb
, TCA_ATM_MAX
, opt
);
188 if (tb
[TCA_ATM_ADDR
]) {
189 if (RTA_PAYLOAD(tb
[TCA_ATM_ADDR
]) <
190 sizeof(struct sockaddr_atmpvc
))
191 fprintf(stderr
, "ATM: address too short\n");
193 if (atm2text(buffer
, MAX_ATM_ADDR_LEN
,
194 RTA_DATA(tb
[TCA_ATM_ADDR
]), A2T_PRETTY
| A2T_NAME
) <
195 0) fprintf(stderr
, "atm2text error\n");
196 fprintf(f
, "pvc %s ", buffer
);
199 if (tb
[TCA_ATM_HDR
]) {
201 const __u8
*hdr
= RTA_DATA(tb
[TCA_ATM_HDR
]);
204 for (i
= 0; i
< RTA_PAYLOAD(tb
[TCA_ATM_HDR
]); i
++)
205 fprintf(f
, "%c%02x", i
? '.' : ' ', hdr
[i
]);
206 if (!i
) fprintf(f
, " .");
209 if (tb
[TCA_ATM_EXCESS
]) {
212 if (RTA_PAYLOAD(tb
[TCA_ATM_EXCESS
]) < sizeof(excess
))
213 fprintf(stderr
, "ATM: excess class ID too short\n");
215 excess
= rta_getattr_u32(tb
[TCA_ATM_EXCESS
]);
216 if (!excess
) fprintf(f
, "excess clp ");
220 print_tc_classid(buf
, sizeof(buf
), excess
);
221 fprintf(f
, "excess %s ", buf
);
225 if (tb
[TCA_ATM_STATE
]) {
226 static const char *map
[] = { ATM_VS2TXT_MAP
};
229 if (RTA_PAYLOAD(tb
[TCA_ATM_STATE
]) < sizeof(state
))
230 fprintf(stderr
, "ATM: state field too short\n");
232 state
= rta_getattr_u32(tb
[TCA_ATM_STATE
]);
233 fprintf(f
, "%s ", map
[state
]);
240 struct qdisc_util atm_qdisc_util
= {
242 .parse_qopt
= atm_parse_opt
,
243 .print_qopt
= atm_print_opt
,
244 .parse_copt
= atm_parse_class_opt
,
245 .print_copt
= atm_print_opt
,