1 /* SPDX-License-Identifier: GPL-2.0 */
5 * Hacked 1998-2000 by Werner Almesberger, EPFL ICA
14 #include <sys/socket.h>
15 #include <sys/ioctl.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
20 #include <linux/atmdev.h>
21 #include <linux/atmarp.h>
27 #define MAX_HDR_LEN 64
30 static int atm_parse_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
31 struct nlmsghdr
*n
, const char *dev
)
34 fprintf(stderr
, "Usage: atm\n");
41 static void explain(void)
44 "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) [ qos QOS ] [ sndbuf BYTES ]\n"
45 " [ hdr HEX... ] [ excess ( CLASSID | clp ) ] [ clip ]\n");
49 static int atm_parse_class_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
50 struct nlmsghdr
*n
, const char *dev
)
52 struct sockaddr_atmsvc addr
= {};
55 unsigned char hdr
[MAX_HDR_LEN
];
63 (void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos
, 0);
64 (void) text2sap("blli:l2=iso8802", &sap
, 0);
66 if (!strcmp(*argv
, "pvc")) {
68 if (text2atm(*argv
, (struct sockaddr
*) &addr
,
69 sizeof(addr
), T2A_PVC
| T2A_NAME
) < 0) {
73 } else if (!strcmp(*argv
,"svc")) {
75 if (text2atm(*argv
, (struct sockaddr
*) &addr
,
76 sizeof(addr
), T2A_SVC
| T2A_NAME
) < 0) {
80 } else if (!strcmp(*argv
,"qos")) {
82 if (text2qos(*argv
, &qos
, 0) < 0) {
86 } else if (!strcmp(*argv
,"sndbuf")) {
90 sndbuf
= strtol(*argv
, &end
, 0);
95 } else if (!strcmp(*argv
,"sap")) {
97 if (addr
.sas_family
!= AF_ATMSVC
||
98 text2sap(*argv
, &sap
, T2A_NAME
) < 0) {
102 } else if (!strcmp(*argv
,"hdr")) {
108 for (walk
= *argv
; *walk
; walk
++) {
111 if (ptr
== hdr
+MAX_HDR_LEN
) {
112 fprintf(stderr
, "header is too long\n");
115 if (*walk
== '.') continue;
116 if (!isxdigit(walk
[0]) || !walk
[1] ||
117 !isxdigit(walk
[1])) {
121 sscanf(walk
, "%2x", &tmp
);
126 } else if (!strcmp(*argv
,"excess")) {
128 if (!strcmp(*argv
, "clp")) excess
= 0;
129 else if (get_tc_classid(&excess
, *argv
)) {
133 } else if (!strcmp(*argv
,"clip")) {
142 s
= socket(addr
.sas_family
, SOCK_DGRAM
, 0);
147 if (setsockopt(s
, SOL_ATM
, SO_ATMQOS
, &qos
, sizeof(qos
)) < 0) {
152 if (setsockopt(s
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
)) < 0) {
156 if (addr
.sas_family
== AF_ATMSVC
&& setsockopt(s
, SOL_ATM
, SO_ATMSAP
,
157 &sap
, sizeof(sap
)) < 0) {
161 if (connect(s
, (struct sockaddr
*) &addr
, addr
.sas_family
== AF_ATMPVC
?
162 sizeof(struct sockaddr_atmpvc
) : sizeof(addr
)) < 0) {
167 if (ioctl(s
, ATMARP_MKIP
, 0) < 0) {
168 perror("ioctl ATMARP_MKIP");
171 tail
= addattr_nest(n
, 1024, TCA_OPTIONS
);
172 addattr_l(n
, 1024, TCA_ATM_FD
, &s
, sizeof(s
));
174 addattr_l(n
, 1024, TCA_ATM_EXCESS
, &excess
, sizeof(excess
));
176 addattr_l(n
, 1024, TCA_ATM_HDR
, hdr
, hdr_len
);
177 addattr_nest_end(n
, tail
);
183 static int atm_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
185 struct rtattr
*tb
[TCA_ATM_MAX
+1];
186 char buffer
[MAX_ATM_ADDR_LEN
+1];
191 parse_rtattr_nested(tb
, TCA_ATM_MAX
, opt
);
192 if (tb
[TCA_ATM_ADDR
]) {
193 if (RTA_PAYLOAD(tb
[TCA_ATM_ADDR
]) <
194 sizeof(struct sockaddr_atmpvc
))
195 fprintf(stderr
, "ATM: address too short\n");
197 if (atm2text(buffer
, MAX_ATM_ADDR_LEN
,
198 RTA_DATA(tb
[TCA_ATM_ADDR
]), A2T_PRETTY
| A2T_NAME
) <
199 0) fprintf(stderr
, "atm2text error\n");
200 fprintf(f
, "pvc %s ", buffer
);
203 if (tb
[TCA_ATM_HDR
]) {
205 const __u8
*hdr
= RTA_DATA(tb
[TCA_ATM_HDR
]);
208 for (i
= 0; i
< RTA_PAYLOAD(tb
[TCA_ATM_HDR
]); i
++)
209 fprintf(f
, "%c%02x", i
? '.' : ' ', hdr
[i
]);
210 if (!i
) fprintf(f
, " .");
213 if (tb
[TCA_ATM_EXCESS
]) {
216 if (RTA_PAYLOAD(tb
[TCA_ATM_EXCESS
]) < sizeof(excess
))
217 fprintf(stderr
, "ATM: excess class ID too short\n");
219 excess
= rta_getattr_u32(tb
[TCA_ATM_EXCESS
]);
220 if (!excess
) fprintf(f
, "excess clp ");
224 print_tc_classid(buf
, sizeof(buf
), excess
);
225 fprintf(f
, "excess %s ", buf
);
229 if (tb
[TCA_ATM_STATE
]) {
230 static const char *map
[] = { ATM_VS2TXT_MAP
};
233 if (RTA_PAYLOAD(tb
[TCA_ATM_STATE
]) < sizeof(state
))
234 fprintf(stderr
, "ATM: state field too short\n");
236 state
= rta_getattr_u32(tb
[TCA_ATM_STATE
]);
237 fprintf(f
, "%s ", map
[state
]);
244 struct qdisc_util atm_qdisc_util
= {
246 .parse_qopt
= atm_parse_opt
,
247 .print_qopt
= atm_print_opt
,
248 .parse_copt
= atm_parse_class_opt
,
249 .print_copt
= atm_print_opt
,