iproute2/tc/q_atm.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * q_atm.c              ATM.
   4 *
   5 * Hacked 1998-2000 by Werner Almesberger, EPFL ICA
   6 *
   7 */
   8
   9#include <stdio.h>
  10#include <stdlib.h>
  11#include <unistd.h>
  12#include <ctype.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
  30static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv,
  31                         struct nlmsghdr *n, const char *dev)
  32{
  33        if (argc) {
  34                fprintf(stderr, "Usage: atm\n");
  35                return -1;
  36        }
  37        return 0;
  38}
  39
  40
  41static void explain(void)
  42{
  43        fprintf(stderr,
  44                "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) [ qos QOS ] [ sndbuf BYTES ]\n"
  45                "  [ hdr HEX... ] [ excess ( CLASSID | clp ) ] [ clip ]\n");
  46}
  47
  48
  49static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
  50        struct nlmsghdr *n, const char *dev)
  51{
  52        struct sockaddr_atmsvc addr = {};
  53        struct atm_qos qos;
  54        struct atm_sap sap;
  55        unsigned char hdr[MAX_HDR_LEN];
  56        __u32 excess = 0;
  57        struct rtattr *tail;
  58        int sndbuf = 0;
  59        int hdr_len = -1;
  60        int set_clip = 0;
  61        int s;
  62
  63        (void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos, 0);
  64        (void) text2sap("blli:l2=iso8802", &sap, 0);
  65        while (argc > 0) {
  66                if (!strcmp(*argv, "pvc")) {
  67                        NEXT_ARG();
  68                        if (text2atm(*argv, (struct sockaddr *) &addr,
  69                            sizeof(addr), T2A_PVC | T2A_NAME) < 0) {
  70                                explain();
  71                                return -1;
  72                        }
  73                } else if (!strcmp(*argv,"svc")) {
  74                        NEXT_ARG();
  75                        if (text2atm(*argv, (struct sockaddr *) &addr,
  76                            sizeof(addr), T2A_SVC | T2A_NAME) < 0) {
  77                                explain();
  78                                return -1;
  79                        }
  80                } else if (!strcmp(*argv,"qos")) {
  81                        NEXT_ARG();
  82                        if (text2qos(*argv, &qos, 0) < 0) {
  83                                explain();
  84                                return -1;
  85                        }
  86                } else if (!strcmp(*argv,"sndbuf")) {
  87                        char *end;
  88
  89                        NEXT_ARG();
  90                        sndbuf = strtol(*argv, &end, 0);
  91                        if (*end) {
  92                                explain();
  93                                return -1;
  94                        }
  95                } else if (!strcmp(*argv,"sap")) {
  96                        NEXT_ARG();
  97                        if (addr.sas_family != AF_ATMSVC ||
  98                            text2sap(*argv, &sap, T2A_NAME) < 0) {
  99                                explain();
 100                                return -1;
 101                        }
 102                } else if (!strcmp(*argv,"hdr")) {
 103                        unsigned char *ptr;
 104                        char *walk;
 105
 106                        NEXT_ARG();
 107                        ptr = hdr;
 108                        for (walk = *argv; *walk; walk++) {
 109                                int tmp;
 110
 111                                if (ptr == hdr+MAX_HDR_LEN) {
 112                                        fprintf(stderr, "header is too long\n");
 113                                        return -1;
 114                                }
 115                                if (*walk == '.') continue;
 116                                if (!isxdigit(walk[0]) || !walk[1] ||
 117                                    !isxdigit(walk[1])) {
 118                                        explain();
 119                                        return -1;
 120                                }
 121                                sscanf(walk, "%2x", &tmp);
 122                                *ptr++ = tmp;
 123                                walk++;
 124                        }
 125                        hdr_len = ptr-hdr;
 126                } else if (!strcmp(*argv,"excess")) {
 127                        NEXT_ARG();
 128                        if (!strcmp(*argv, "clp")) excess = 0;
 129                        else if (get_tc_classid(&excess, *argv)) {
 130                                        explain();
 131                                        return -1;
 132                                }
 133                } else if (!strcmp(*argv,"clip")) {
 134                        set_clip = 1;
 135                } else {
 136                        explain();
 137                        return 1;
 138                }
 139                argc--;
 140                argv++;
 141        }
 142        s = socket(addr.sas_family, SOCK_DGRAM, 0);
 143        if (s < 0) {
 144                perror("socket");
 145                return -1;
 146        }
 147        if (setsockopt(s, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) {
 148                perror("SO_ATMQOS");
 149                return -1;
 150        }
 151        if (sndbuf)
 152            if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) {
 153                perror("SO_SNDBUF");
 154            return -1;
 155        }
 156        if (addr.sas_family == AF_ATMSVC && setsockopt(s, SOL_ATM, SO_ATMSAP,
 157            &sap, sizeof(sap)) < 0) {
 158                perror("SO_ATMSAP");
 159                return -1;
 160        }
 161        if (connect(s, (struct sockaddr *) &addr, addr.sas_family == AF_ATMPVC ?
 162            sizeof(struct sockaddr_atmpvc) : sizeof(addr)) < 0) {
 163                perror("connect");
 164                return -1;
 165        }
 166        if (set_clip)
 167                if (ioctl(s, ATMARP_MKIP, 0) < 0) {
 168                        perror("ioctl ATMARP_MKIP");
 169                        return -1;
 170                }
 171        tail = addattr_nest(n, 1024, TCA_OPTIONS);
 172        addattr_l(n, 1024, TCA_ATM_FD, &s, sizeof(s));
 173        if (excess)
 174                addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess));
 175        if (hdr_len != -1)
 176                addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len);
 177        addattr_nest_end(n, tail);
 178        return 0;
 179}
 180
 181
 182
 183static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 184{
 185        struct rtattr *tb[TCA_ATM_MAX+1];
 186        char buffer[MAX_ATM_ADDR_LEN+1];
 187
 188        if (opt == NULL)
 189                return 0;
 190
 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");
 196                else {
 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);
 201                }
 202        }
 203        if (tb[TCA_ATM_HDR]) {
 204                int i;
 205                const __u8 *hdr = RTA_DATA(tb[TCA_ATM_HDR]);
 206
 207                fprintf(f, "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, " .");
 211                fprintf(f, " ");
 212        }
 213        if (tb[TCA_ATM_EXCESS]) {
 214                __u32 excess;
 215
 216                if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS]) < sizeof(excess))
 217                        fprintf(stderr, "ATM: excess class ID too short\n");
 218                else {
 219                        excess = rta_getattr_u32(tb[TCA_ATM_EXCESS]);
 220                        if (!excess) fprintf(f, "excess clp ");
 221                        else {
 222                                char buf[64];
 223
 224                                print_tc_classid(buf, sizeof(buf), excess);
 225                                fprintf(f, "excess %s ", buf);
 226                        }
 227                }
 228        }
 229        if (tb[TCA_ATM_STATE]) {
 230                static const char *map[] = { ATM_VS2TXT_MAP };
 231                int state;
 232
 233                if (RTA_PAYLOAD(tb[TCA_ATM_STATE]) < sizeof(state))
 234                        fprintf(stderr, "ATM: state field too short\n");
 235                else {
 236                        state = rta_getattr_u32(tb[TCA_ATM_STATE]);
 237                        fprintf(f, "%s ", map[state]);
 238                }
 239        }
 240        return 0;
 241}
 242
 243
 244struct qdisc_util atm_qdisc_util = {
 245        .id             = "atm",
 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,
 250};
 251