4 * 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
, struct nlmsghdr
*n
)
33 fprintf(stderr
,"Usage: atm\n");
40 static void explain(void)
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 ) ] "
49 static int atm_parse_class_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
52 struct sockaddr_atmsvc addr
;
55 unsigned char hdr
[MAX_HDR_LEN
];
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);
67 if (!strcmp(*argv
,"pvc")) {
69 if (text2atm(*argv
,(struct sockaddr
*) &addr
,
70 sizeof(addr
),T2A_PVC
| T2A_NAME
) < 0) {
75 else if (!strcmp(*argv
,"svc")) {
77 if (text2atm(*argv
,(struct sockaddr
*) &addr
,
78 sizeof(addr
),T2A_SVC
| T2A_NAME
) < 0) {
83 else if (!strcmp(*argv
,"qos")) {
85 if (text2qos(*argv
,&qos
,0) < 0) {
90 else if (!strcmp(*argv
,"sndbuf")) {
94 sndbuf
= strtol(*argv
,&end
,0);
100 else if (!strcmp(*argv
,"sap")) {
102 if (addr
.sas_family
!= AF_ATMSVC
||
103 text2sap(*argv
,&sap
,T2A_NAME
) < 0) {
108 else if (!strcmp(*argv
,"hdr")) {
114 for (walk
= *argv
; *walk
; walk
++) {
117 if (ptr
== hdr
+MAX_HDR_LEN
) {
118 fprintf(stderr
,"header is too long\n");
121 if (*walk
== '.') continue;
122 if (!isxdigit(walk
[0]) || !walk
[1] ||
123 !isxdigit(walk
[1])) {
127 sscanf(walk
,"%2x",&tmp
);
133 else if (!strcmp(*argv
,"excess")) {
135 if (!strcmp(*argv
,"clp")) excess
= 0;
136 else if (get_tc_classid(&excess
,*argv
)) {
141 else if (!strcmp(*argv
,"clip")) {
151 s
= socket(addr
.sas_family
,SOCK_DGRAM
,0);
156 if (setsockopt(s
,SOL_ATM
,SO_ATMQOS
,&qos
,sizeof(qos
)) < 0) {
161 if (setsockopt(s
,SOL_SOCKET
,SO_SNDBUF
,&sndbuf
,sizeof(sndbuf
)) < 0) {
165 if (addr
.sas_family
== AF_ATMSVC
&& setsockopt(s
,SOL_ATM
,SO_ATMSAP
,
166 &sap
,sizeof(sap
)) < 0) {
170 if (connect(s
,(struct sockaddr
*) &addr
,addr
.sas_family
== AF_ATMPVC
?
171 sizeof(struct sockaddr_atmpvc
) : sizeof(addr
)) < 0) {
176 if (ioctl(s
,ATMARP_MKIP
,0) < 0) {
177 perror("ioctl ATMARP_MKIP");
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
;
191 static int atm_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
193 struct rtattr
*tb
[TCA_ATM_MAX
+1];
194 char buffer
[MAX_ATM_ADDR_LEN
+1];
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");
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
);
211 if (tb
[TCA_ATM_HDR
]) {
213 const __u8
*hdr
= RTA_DATA(tb
[TCA_ATM_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
," .");
221 if (tb
[TCA_ATM_EXCESS
]) {
224 if (RTA_PAYLOAD(tb
[TCA_ATM_EXCESS
]) < sizeof(excess
))
225 fprintf(stderr
,"ATM: excess class ID too short\n");
227 excess
= rta_getattr_u32(tb
[TCA_ATM_EXCESS
]);
228 if (!excess
) fprintf(f
,"excess clp ");
232 print_tc_classid(buf
,sizeof(buf
),excess
);
233 fprintf(f
,"excess %s ",buf
);
237 if (tb
[TCA_ATM_STATE
]) {
238 static const char *map
[] = { ATM_VS2TXT_MAP
};
241 if (RTA_PAYLOAD(tb
[TCA_ATM_STATE
]) < sizeof(state
))
242 fprintf(stderr
,"ATM: state field too short\n");
244 state
= *(int *) RTA_DATA(tb
[TCA_ATM_STATE
]);
245 fprintf(f
,"%s ",map
[state
]);
252 struct qdisc_util atm_qdisc_util
= {
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
,