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)
43 fprintf(stderr
, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) [ qos QOS ] [ sndbuf BYTES ]\n");
44 fprintf(stderr
, " [ hdr HEX... ] [ excess ( CLASSID | clp ) ] [ clip ]\n");
48 static int atm_parse_class_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
49 struct nlmsghdr
*n
, const char *dev
)
51 struct sockaddr_atmsvc addr
= {};
54 unsigned char hdr
[MAX_HDR_LEN
];
62 (void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos
, 0);
63 (void) text2sap("blli:l2=iso8802", &sap
, 0);
65 if (!strcmp(*argv
, "pvc")) {
67 if (text2atm(*argv
, (struct sockaddr
*) &addr
,
68 sizeof(addr
), T2A_PVC
| T2A_NAME
) < 0) {
72 } else if (!strcmp(*argv
,"svc")) {
74 if (text2atm(*argv
, (struct sockaddr
*) &addr
,
75 sizeof(addr
), T2A_SVC
| T2A_NAME
) < 0) {
79 } else if (!strcmp(*argv
,"qos")) {
81 if (text2qos(*argv
, &qos
, 0) < 0) {
85 } else if (!strcmp(*argv
,"sndbuf")) {
89 sndbuf
= strtol(*argv
, &end
, 0);
94 } else if (!strcmp(*argv
,"sap")) {
96 if (addr
.sas_family
!= AF_ATMSVC
||
97 text2sap(*argv
, &sap
, T2A_NAME
) < 0) {
101 } else if (!strcmp(*argv
,"hdr")) {
107 for (walk
= *argv
; *walk
; walk
++) {
110 if (ptr
== hdr
+MAX_HDR_LEN
) {
111 fprintf(stderr
, "header is too long\n");
114 if (*walk
== '.') continue;
115 if (!isxdigit(walk
[0]) || !walk
[1] ||
116 !isxdigit(walk
[1])) {
120 sscanf(walk
, "%2x", &tmp
);
125 } else if (!strcmp(*argv
,"excess")) {
127 if (!strcmp(*argv
, "clp")) excess
= 0;
128 else if (get_tc_classid(&excess
, *argv
)) {
132 } else if (!strcmp(*argv
,"clip")) {
141 s
= socket(addr
.sas_family
, SOCK_DGRAM
, 0);
146 if (setsockopt(s
, SOL_ATM
, SO_ATMQOS
, &qos
, sizeof(qos
)) < 0) {
151 if (setsockopt(s
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
)) < 0) {
155 if (addr
.sas_family
== AF_ATMSVC
&& setsockopt(s
, SOL_ATM
, SO_ATMSAP
,
156 &sap
, sizeof(sap
)) < 0) {
160 if (connect(s
, (struct sockaddr
*) &addr
, addr
.sas_family
== AF_ATMPVC
?
161 sizeof(struct sockaddr_atmpvc
) : sizeof(addr
)) < 0) {
166 if (ioctl(s
, ATMARP_MKIP
, 0) < 0) {
167 perror("ioctl ATMARP_MKIP");
170 tail
= addattr_nest(n
, 1024, TCA_OPTIONS
);
171 addattr_l(n
, 1024, TCA_ATM_FD
, &s
, sizeof(s
));
173 addattr_l(n
, 1024, TCA_ATM_EXCESS
, &excess
, sizeof(excess
));
175 addattr_l(n
, 1024, TCA_ATM_HDR
, hdr
, hdr_len
);
176 addattr_nest_end(n
, tail
);
182 static int atm_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
184 struct rtattr
*tb
[TCA_ATM_MAX
+1];
185 char buffer
[MAX_ATM_ADDR_LEN
+1];
190 parse_rtattr_nested(tb
, TCA_ATM_MAX
, opt
);
191 if (tb
[TCA_ATM_ADDR
]) {
192 if (RTA_PAYLOAD(tb
[TCA_ATM_ADDR
]) <
193 sizeof(struct sockaddr_atmpvc
))
194 fprintf(stderr
, "ATM: address too short\n");
196 if (atm2text(buffer
, MAX_ATM_ADDR_LEN
,
197 RTA_DATA(tb
[TCA_ATM_ADDR
]), A2T_PRETTY
| A2T_NAME
) <
198 0) fprintf(stderr
, "atm2text error\n");
199 fprintf(f
, "pvc %s ", buffer
);
202 if (tb
[TCA_ATM_HDR
]) {
204 const __u8
*hdr
= RTA_DATA(tb
[TCA_ATM_HDR
]);
207 for (i
= 0; i
< RTA_PAYLOAD(tb
[TCA_ATM_HDR
]); i
++)
208 fprintf(f
, "%c%02x", i
? '.' : ' ', hdr
[i
]);
209 if (!i
) fprintf(f
, " .");
212 if (tb
[TCA_ATM_EXCESS
]) {
215 if (RTA_PAYLOAD(tb
[TCA_ATM_EXCESS
]) < sizeof(excess
))
216 fprintf(stderr
, "ATM: excess class ID too short\n");
218 excess
= rta_getattr_u32(tb
[TCA_ATM_EXCESS
]);
219 if (!excess
) fprintf(f
, "excess clp ");
223 print_tc_classid(buf
, sizeof(buf
), excess
);
224 fprintf(f
, "excess %s ", buf
);
228 if (tb
[TCA_ATM_STATE
]) {
229 static const char *map
[] = { ATM_VS2TXT_MAP
};
232 if (RTA_PAYLOAD(tb
[TCA_ATM_STATE
]) < sizeof(state
))
233 fprintf(stderr
, "ATM: state field too short\n");
235 state
= rta_getattr_u32(tb
[TCA_ATM_STATE
]);
236 fprintf(f
, "%s ", map
[state
]);
243 struct qdisc_util atm_qdisc_util
= {
245 .parse_qopt
= atm_parse_opt
,
246 .print_qopt
= atm_print_opt
,
247 .parse_copt
= atm_parse_class_opt
,
248 .print_copt
= atm_print_opt
,