iproute2/ip/ipl2tp.c
<<
>>
Prefs
   1/*
   2 * ipl2tp.c            "ip l2tp"
   3 *
   4 *              This program is free software; you can redistribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Original Author:     James Chapman <jchapman@katalix.com>
  10 *
  11 */
  12
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <string.h>
  16#include <unistd.h>
  17#include <errno.h>
  18#include <sys/types.h>
  19#include <sys/socket.h>
  20#include <arpa/inet.h>
  21#include <sys/ioctl.h>
  22#include <linux/if.h>
  23#include <linux/if_arp.h>
  24#include <linux/ip.h>
  25
  26#include <linux/genetlink.h>
  27#include <linux/l2tp.h>
  28#include "libgenl.h"
  29
  30#include "utils.h"
  31#include "ip_common.h"
  32
  33enum {
  34        L2TP_ADD,
  35        L2TP_CHG,
  36        L2TP_DEL,
  37        L2TP_GET
  38};
  39
  40struct l2tp_parm {
  41        uint32_t tunnel_id;
  42        uint32_t peer_tunnel_id;
  43        uint32_t session_id;
  44        uint32_t peer_session_id;
  45        enum l2tp_encap_type encap;
  46        uint16_t local_udp_port;
  47        uint16_t peer_udp_port;
  48        int cookie_len;
  49        uint8_t cookie[8];
  50        int peer_cookie_len;
  51        uint8_t peer_cookie[8];
  52        inet_prefix local_ip;
  53        inet_prefix peer_ip;
  54
  55        uint16_t pw_type;
  56        unsigned int udp6_csum_tx:1;
  57        unsigned int udp6_csum_rx:1;
  58        unsigned int udp_csum:1;
  59        unsigned int recv_seq:1;
  60        unsigned int send_seq:1;
  61        unsigned int tunnel:1;
  62        unsigned int session:1;
  63        int reorder_timeout;
  64        const char *ifname;
  65        uint8_t l2spec_type;
  66        uint8_t l2spec_len;
  67};
  68
  69struct l2tp_stats {
  70        uint64_t data_rx_packets;
  71        uint64_t data_rx_bytes;
  72        uint64_t data_rx_errors;
  73        uint64_t data_rx_oos_packets;
  74        uint64_t data_rx_oos_discards;
  75        uint64_t data_tx_packets;
  76        uint64_t data_tx_bytes;
  77        uint64_t data_tx_errors;
  78};
  79
  80struct l2tp_data {
  81        struct l2tp_parm config;
  82        struct l2tp_stats stats;
  83};
  84
  85/* netlink socket */
  86static struct rtnl_handle genl_rth;
  87static int genl_family = -1;
  88
  89/*****************************************************************************
  90 * Netlink actions
  91 *****************************************************************************/
  92
  93static int create_tunnel(struct l2tp_parm *p)
  94{
  95        uint32_t local_attr = L2TP_ATTR_IP_SADDR;
  96        uint32_t peer_attr = L2TP_ATTR_IP_DADDR;
  97
  98        GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
  99                     L2TP_CMD_TUNNEL_CREATE, NLM_F_REQUEST | NLM_F_ACK);
 100
 101        addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
 102        addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
 103        addattr8(&req.n, 1024, L2TP_ATTR_PROTO_VERSION, 3);
 104        addattr16(&req.n, 1024, L2TP_ATTR_ENCAP_TYPE, p->encap);
 105
 106        if (p->local_ip.family == AF_INET6)
 107                local_attr = L2TP_ATTR_IP6_SADDR;
 108        addattr_l(&req.n, 1024, local_attr, &p->local_ip.data,
 109                  p->local_ip.bytelen);
 110
 111        if (p->peer_ip.family == AF_INET6)
 112                peer_attr = L2TP_ATTR_IP6_DADDR;
 113        addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data,
 114                  p->peer_ip.bytelen);
 115
 116        if (p->encap == L2TP_ENCAPTYPE_UDP) {
 117                addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port);
 118                addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
 119                if (p->udp_csum)
 120                        addattr8(&req.n, 1024, L2TP_ATTR_UDP_CSUM, 1);
 121                if (!p->udp6_csum_tx)
 122                        addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX);
 123                if (!p->udp6_csum_rx)
 124                        addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_RX);
 125        }
 126
 127        if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
 128                return -2;
 129
 130        return 0;
 131}
 132
 133static int delete_tunnel(struct l2tp_parm *p)
 134{
 135        GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
 136                     L2TP_CMD_TUNNEL_DELETE, NLM_F_REQUEST | NLM_F_ACK);
 137
 138        addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
 139
 140        if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
 141                return -2;
 142
 143        return 0;
 144}
 145
 146static int create_session(struct l2tp_parm *p)
 147{
 148        GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
 149                     L2TP_CMD_SESSION_CREATE, NLM_F_REQUEST | NLM_F_ACK);
 150
 151        addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
 152        addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
 153        addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
 154        addattr32(&req.n, 1024, L2TP_ATTR_PEER_SESSION_ID, p->peer_session_id);
 155        addattr16(&req.n, 1024, L2TP_ATTR_PW_TYPE, p->pw_type);
 156        addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type);
 157        addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len);
 158
 159        if (p->recv_seq)
 160                addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1);
 161        if (p->send_seq)
 162                addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1);
 163        if (p->reorder_timeout)
 164                addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT,
 165                                          p->reorder_timeout);
 166        if (p->cookie_len)
 167                addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
 168                          p->cookie, p->cookie_len);
 169        if (p->peer_cookie_len)
 170                addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE,
 171                          p->peer_cookie,  p->peer_cookie_len);
 172        if (p->ifname)
 173                addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
 174
 175        if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
 176                return -2;
 177
 178        return 0;
 179}
 180
 181static int delete_session(struct l2tp_parm *p)
 182{
 183        GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
 184                     L2TP_CMD_SESSION_DELETE, NLM_F_REQUEST | NLM_F_ACK);
 185
 186        addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
 187        addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
 188        if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
 189                return -2;
 190
 191        return 0;
 192}
 193
 194static void print_cookie(const char *name, const char *fmt,
 195                         const uint8_t *cookie, int len)
 196{
 197        char abuf[32];
 198        size_t n;
 199
 200        n = snprintf(abuf, sizeof(abuf),
 201                     "%02x%02x%02x%02x",
 202                     cookie[0], cookie[1], cookie[2], cookie[3]);
 203        if (len == 8)
 204                snprintf(abuf + n, sizeof(abuf) - n,
 205                         "%02x%02x%02x%02x",
 206                         cookie[4], cookie[5],
 207                         cookie[6], cookie[7]);
 208
 209        print_string(PRINT_ANY, name, fmt, abuf);
 210}
 211
 212static void print_tunnel(const struct l2tp_data *data)
 213{
 214        const struct l2tp_parm *p = &data->config;
 215        char buf[INET6_ADDRSTRLEN];
 216
 217        open_json_object(NULL);
 218        print_uint(PRINT_ANY, "tunnel_id", "Tunnel %u,", p->tunnel_id);
 219        print_string(PRINT_ANY, "encap", " encap %s",
 220                     p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
 221                     p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??");
 222        print_nl();
 223
 224        print_string(PRINT_ANY, "local", "  From %s ",
 225                     inet_ntop(p->local_ip.family, p->local_ip.data,
 226                               buf, sizeof(buf)));
 227        print_string(PRINT_ANY, "peer", "to %s",
 228                     inet_ntop(p->peer_ip.family, p->peer_ip.data,
 229                               buf, sizeof(buf)));
 230        print_nl();
 231
 232        print_uint(PRINT_ANY, "peer_tunnel", "  Peer tunnel %u",
 233                   p->peer_tunnel_id);
 234        print_nl();
 235
 236        if (p->encap == L2TP_ENCAPTYPE_UDP) {
 237                print_string(PRINT_FP, NULL,
 238                             "  UDP source / dest ports:", NULL);
 239
 240                print_hu(PRINT_ANY, "local_port", " %hu",
 241                           p->local_udp_port);
 242                print_hu(PRINT_ANY, "peer_port", "/%hu",
 243                           p->peer_udp_port);
 244                print_nl();
 245
 246                switch (p->local_ip.family) {
 247                case AF_INET:
 248                        print_bool(PRINT_JSON, "checksum",
 249                                   NULL, p->udp_csum);
 250                        print_string(PRINT_FP, NULL,
 251                                     "  UDP checksum: %s\n",
 252                                     p->udp_csum ? "enabled" : "disabled");
 253                        break;
 254                case AF_INET6:
 255                        if (is_json_context()) {
 256                                print_bool(PRINT_JSON, "checksum_tx",
 257                                           NULL, p->udp6_csum_tx);
 258
 259                                print_bool(PRINT_JSON, "checksum_rx",
 260                                           NULL, p->udp6_csum_tx);
 261                        } else {
 262                                printf("  UDP checksum: %s%s%s%s\n",
 263                                       p->udp6_csum_tx && p->udp6_csum_rx
 264                                       ? "enabled" : "",
 265                                       p->udp6_csum_tx && !p->udp6_csum_rx
 266                                       ? "tx" : "",
 267                                       !p->udp6_csum_tx && p->udp6_csum_rx
 268                                       ? "rx" : "",
 269                                       !p->udp6_csum_tx && !p->udp6_csum_rx
 270                                       ? "disabled" : "");
 271                        }
 272                        break;
 273                }
 274        }
 275        close_json_object();
 276}
 277
 278static void print_session(struct l2tp_data *data)
 279{
 280        struct l2tp_parm *p = &data->config;
 281
 282        open_json_object(NULL);
 283
 284        print_uint(PRINT_ANY, "session_id", "Session %u", p->session_id);
 285        print_uint(PRINT_ANY, "tunnel_id",  " in tunnel %u", p->tunnel_id);
 286        print_nl();
 287
 288        print_uint(PRINT_ANY, "peer_session_id",
 289                     "  Peer session %u,", p->peer_session_id);
 290        print_uint(PRINT_ANY, "peer_tunnel_id",
 291                     " tunnel %u",  p->peer_tunnel_id);
 292        print_nl();
 293
 294        if (p->ifname != NULL) {
 295                print_color_string(PRINT_ANY, COLOR_IFNAME,
 296                                   "interface", "  interface name: %s" , p->ifname);
 297                print_nl();
 298        }
 299
 300        /* Show offsets only for plain console output (for legacy scripts) */
 301        print_uint(PRINT_FP, "offset", "  offset %u,", 0);
 302        print_uint(PRINT_FP, "peer_offset", " peer offset %u\n", 0);
 303
 304        if (p->cookie_len > 0)
 305                print_cookie("cookie", "  cookie %s",
 306                             p->cookie, p->cookie_len);
 307
 308        if (p->peer_cookie_len > 0)
 309                print_cookie("peer_cookie", "  peer cookie %s",
 310                             p->peer_cookie, p->peer_cookie_len);
 311
 312        if (p->reorder_timeout != 0)
 313                print_uint(PRINT_ANY, "reorder_timeout",
 314                           "  reorder timeout: %u", p->reorder_timeout);
 315
 316
 317        if (p->send_seq || p->recv_seq) {
 318                print_string(PRINT_FP, NULL, "%s  sequence numbering:", _SL_);
 319
 320                if (p->send_seq)
 321                        print_null(PRINT_ANY, "send_seq", " send", NULL);
 322                if (p->recv_seq)
 323                        print_null(PRINT_ANY, "recv_seq", " recv", NULL);
 324
 325        }
 326        print_string(PRINT_FP, NULL, "\n", NULL);
 327        close_json_object();
 328}
 329
 330static int get_response(struct nlmsghdr *n, void *arg)
 331{
 332        struct genlmsghdr *ghdr;
 333        struct l2tp_data *data = arg;
 334        struct l2tp_parm *p = &data->config;
 335        struct rtattr *attrs[L2TP_ATTR_MAX + 1];
 336        struct rtattr *nla_stats, *rta;
 337        int len;
 338
 339        /* Validate message and parse attributes */
 340        if (n->nlmsg_type == NLMSG_ERROR)
 341                return -EBADMSG;
 342
 343        ghdr = NLMSG_DATA(n);
 344        len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr));
 345        if (len < 0)
 346                return -1;
 347
 348        parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
 349
 350        if (attrs[L2TP_ATTR_PW_TYPE])
 351                p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]);
 352        if (attrs[L2TP_ATTR_ENCAP_TYPE])
 353                p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
 354        if (attrs[L2TP_ATTR_CONN_ID])
 355                p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]);
 356        if (attrs[L2TP_ATTR_PEER_CONN_ID])
 357                p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]);
 358        if (attrs[L2TP_ATTR_SESSION_ID])
 359                p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]);
 360        if (attrs[L2TP_ATTR_PEER_SESSION_ID])
 361                p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]);
 362        if (attrs[L2TP_ATTR_L2SPEC_TYPE])
 363                p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]);
 364        if (attrs[L2TP_ATTR_L2SPEC_LEN])
 365                p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);
 366
 367        if (attrs[L2TP_ATTR_UDP_CSUM])
 368                p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]);
 369
 370        p->udp6_csum_tx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX];
 371        p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX];
 372
 373        if (attrs[L2TP_ATTR_COOKIE])
 374                memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
 375                       p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE]));
 376
 377        if (attrs[L2TP_ATTR_PEER_COOKIE])
 378                memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
 379                       p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));
 380
 381        if (attrs[L2TP_ATTR_RECV_SEQ])
 382                p->recv_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_RECV_SEQ]);
 383        if (attrs[L2TP_ATTR_SEND_SEQ])
 384                p->send_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_SEND_SEQ]);
 385
 386        if (attrs[L2TP_ATTR_RECV_TIMEOUT])
 387                p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]);
 388
 389        rta = attrs[L2TP_ATTR_IP_SADDR];
 390        p->local_ip.family = AF_INET;
 391        if (!rta) {
 392                rta = attrs[L2TP_ATTR_IP6_SADDR];
 393                p->local_ip.family = AF_INET6;
 394        }
 395        if (rta && get_addr_rta(&p->local_ip, rta, p->local_ip.family))
 396                return -1;
 397
 398        rta = attrs[L2TP_ATTR_IP_DADDR];
 399        p->peer_ip.family = AF_INET;
 400        if (!rta) {
 401                rta = attrs[L2TP_ATTR_IP6_DADDR];
 402                p->peer_ip.family = AF_INET6;
 403        }
 404        if (rta && get_addr_rta(&p->peer_ip, rta, p->peer_ip.family))
 405                return -1;
 406
 407        if (attrs[L2TP_ATTR_UDP_SPORT])
 408                p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]);
 409        if (attrs[L2TP_ATTR_UDP_DPORT])
 410                p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]);
 411        if (attrs[L2TP_ATTR_IFNAME])
 412                p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]);
 413
 414        nla_stats = attrs[L2TP_ATTR_STATS];
 415        if (nla_stats) {
 416                struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1];
 417
 418                parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats);
 419
 420                if (tb[L2TP_ATTR_TX_PACKETS])
 421                        data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]);
 422                if (tb[L2TP_ATTR_TX_BYTES])
 423                        data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]);
 424                if (tb[L2TP_ATTR_TX_ERRORS])
 425                        data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]);
 426                if (tb[L2TP_ATTR_RX_PACKETS])
 427                        data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]);
 428                if (tb[L2TP_ATTR_RX_BYTES])
 429                        data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]);
 430                if (tb[L2TP_ATTR_RX_ERRORS])
 431                        data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]);
 432                if (tb[L2TP_ATTR_RX_SEQ_DISCARDS])
 433                        data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]);
 434                if (tb[L2TP_ATTR_RX_OOS_PACKETS])
 435                        data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]);
 436        }
 437
 438        return 0;
 439}
 440
 441static int session_nlmsg(struct nlmsghdr *n, void *arg)
 442{
 443        int ret = get_response(n, arg);
 444
 445        if (ret == 0)
 446                print_session(arg);
 447
 448        return ret;
 449}
 450
 451static int get_session(struct l2tp_data *p)
 452{
 453        GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
 454                     L2TP_CMD_SESSION_GET,
 455                     NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
 456
 457        req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
 458
 459        if (p->config.tunnel_id && p->config.session_id) {
 460                addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
 461                addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID,
 462                          p->config.session_id);
 463        }
 464
 465        if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
 466                return -2;
 467
 468        new_json_obj(json);
 469        if (rtnl_dump_filter(&genl_rth, session_nlmsg, p) < 0) {
 470                fprintf(stderr, "Dump terminated\n");
 471                exit(1);
 472        }
 473        delete_json_obj();
 474        fflush(stdout);
 475
 476        return 0;
 477}
 478
 479static int tunnel_nlmsg(struct nlmsghdr *n, void *arg)
 480{
 481        int ret = get_response(n, arg);
 482
 483        if (ret == 0)
 484                print_tunnel(arg);
 485
 486        return ret;
 487}
 488
 489static int get_tunnel(struct l2tp_data *p)
 490{
 491        GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
 492                     L2TP_CMD_TUNNEL_GET,
 493                     NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
 494
 495        req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
 496
 497        if (p->config.tunnel_id)
 498                addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
 499
 500        if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
 501                return -2;
 502
 503        new_json_obj(json);
 504        if (rtnl_dump_filter(&genl_rth, tunnel_nlmsg, p) < 0) {
 505                fprintf(stderr, "Dump terminated\n");
 506                exit(1);
 507        }
 508        delete_json_obj();
 509        fflush(stdout);
 510
 511        return 0;
 512}
 513
 514/*****************************************************************************
 515 * Command parser
 516 *****************************************************************************/
 517
 518static void usage(void) __attribute__((noreturn));
 519
 520static void usage(void)
 521{
 522        fprintf(stderr, "Usage: ip l2tp add tunnel\n"
 523                "          remote ADDR local ADDR\n"
 524                "          tunnel_id ID peer_tunnel_id ID\n"
 525                "          [ encap { ip | udp } ]\n"
 526                "          [ udp_sport PORT ] [ udp_dport PORT ]\n"
 527                "          [ udp_csum { on | off } ]\n"
 528                "          [ udp6_csum_tx { on | off } ]\n"
 529                "          [ udp6_csum_rx { on | off } ]\n"
 530                "Usage: ip l2tp add session [ name NAME ]\n"
 531                "          tunnel_id ID\n"
 532                "          session_id ID peer_session_id ID\n"
 533                "          [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"
 534                "          [ seq { none | send | recv | both } ]\n"
 535                "          [ l2spec_type L2SPEC ]\n"
 536                "       ip l2tp del tunnel tunnel_id ID\n"
 537                "       ip l2tp del session tunnel_id ID session_id ID\n"
 538                "       ip l2tp show tunnel [ tunnel_id ID ]\n"
 539                "       ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n"
 540                "\n"
 541                "Where: NAME   := STRING\n"
 542                "       ADDR   := { IP_ADDRESS | any }\n"
 543                "       PORT   := { 0..65535 }\n"
 544                "       ID     := { 1..4294967295 }\n"
 545                "       HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n"
 546                "       L2SPEC := { none | default }\n");
 547
 548        exit(-1);
 549}
 550
 551static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
 552{
 553        memset(p, 0, sizeof(*p));
 554
 555        if (argc == 0)
 556                usage();
 557
 558        /* Defaults */
 559        p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
 560        p->l2spec_len = 4;
 561        p->udp6_csum_rx = 1;
 562        p->udp6_csum_tx = 1;
 563
 564        while (argc > 0) {
 565                if (strcmp(*argv, "encap") == 0) {
 566                        NEXT_ARG();
 567                        if (strcmp(*argv, "ip") == 0) {
 568                                p->encap = L2TP_ENCAPTYPE_IP;
 569                        } else if (strcmp(*argv, "udp") == 0) {
 570                                p->encap = L2TP_ENCAPTYPE_UDP;
 571                        } else {
 572                                fprintf(stderr, "Unknown tunnel encapsulation \"%s\"\n", *argv);
 573                                exit(-1);
 574                        }
 575                } else if (strcmp(*argv, "name") == 0) {
 576                        NEXT_ARG();
 577                        if (check_ifname(*argv))
 578                                invarg("\"name\" not a valid ifname", *argv);
 579                        p->ifname = *argv;
 580                } else if (strcmp(*argv, "remote") == 0) {
 581                        NEXT_ARG();
 582                        if (get_addr(&p->peer_ip, *argv, AF_UNSPEC))
 583                                invarg("invalid remote address\n", *argv);
 584                } else if (strcmp(*argv, "local") == 0) {
 585                        NEXT_ARG();
 586                        if (get_addr(&p->local_ip, *argv, AF_UNSPEC))
 587                                invarg("invalid local address\n", *argv);
 588                } else if ((strcmp(*argv, "tunnel_id") == 0) ||
 589                           (strcmp(*argv, "tid") == 0)) {
 590                        __u32 uval;
 591
 592                        NEXT_ARG();
 593                        if (get_u32(&uval, *argv, 0))
 594                                invarg("invalid ID\n", *argv);
 595                        p->tunnel_id = uval;
 596                } else if ((strcmp(*argv, "peer_tunnel_id") == 0) ||
 597                           (strcmp(*argv, "ptid") == 0)) {
 598                        __u32 uval;
 599
 600                        NEXT_ARG();
 601                        if (get_u32(&uval, *argv, 0))
 602                                invarg("invalid ID\n", *argv);
 603                        p->peer_tunnel_id = uval;
 604                } else if ((strcmp(*argv, "session_id") == 0) ||
 605                           (strcmp(*argv, "sid") == 0)) {
 606                        __u32 uval;
 607
 608                        NEXT_ARG();
 609                        if (get_u32(&uval, *argv, 0))
 610                                invarg("invalid ID\n", *argv);
 611                        p->session_id = uval;
 612                } else if ((strcmp(*argv, "peer_session_id") == 0) ||
 613                           (strcmp(*argv, "psid") == 0)) {
 614                        __u32 uval;
 615
 616                        NEXT_ARG();
 617                        if (get_u32(&uval, *argv, 0))
 618                                invarg("invalid ID\n", *argv);
 619                        p->peer_session_id = uval;
 620                } else if (strcmp(*argv, "udp_sport") == 0) {
 621                        __u16 uval;
 622
 623                        NEXT_ARG();
 624                        if (get_u16(&uval, *argv, 0))
 625                                invarg("invalid port\n", *argv);
 626                        p->local_udp_port = uval;
 627                } else if (strcmp(*argv, "udp_dport") == 0) {
 628                        __u16 uval;
 629
 630                        NEXT_ARG();
 631                        if (get_u16(&uval, *argv, 0))
 632                                invarg("invalid port\n", *argv);
 633                        p->peer_udp_port = uval;
 634                } else if (strcmp(*argv, "udp_csum") == 0) {
 635                        NEXT_ARG();
 636                        if (strcmp(*argv, "on") == 0)
 637                                p->udp_csum = 1;
 638                        else if (strcmp(*argv, "off") == 0)
 639                                p->udp_csum = 0;
 640                        else
 641                                invarg("invalid option for udp_csum\n", *argv);
 642                } else if (strcmp(*argv, "udp6_csum_rx") == 0) {
 643                        NEXT_ARG();
 644                        if (strcmp(*argv, "on") == 0)
 645                                p->udp6_csum_rx = 1;
 646                        else if (strcmp(*argv, "off") == 0)
 647                                p->udp6_csum_rx = 0;
 648                        else
 649                                invarg("invalid option for udp6_csum_rx\n"
 650                                                , *argv);
 651                } else if (strcmp(*argv, "udp6_csum_tx") == 0) {
 652                        NEXT_ARG();
 653                        if (strcmp(*argv, "on") == 0)
 654                                p->udp6_csum_tx = 1;
 655                        else if (strcmp(*argv, "off") == 0)
 656                                p->udp6_csum_tx = 0;
 657                        else
 658                                invarg("invalid option for udp6_csum_tx\n"
 659                                                , *argv);
 660                } else if (strcmp(*argv, "offset") == 0) {
 661                        fprintf(stderr, "Ignoring option \"offset\"\n");
 662                        NEXT_ARG();
 663                } else if (strcmp(*argv, "peer_offset") == 0) {
 664                        fprintf(stderr, "Ignoring option \"peer_offset\"\n");
 665                        NEXT_ARG();
 666                } else if (strcmp(*argv, "cookie") == 0) {
 667                        int slen;
 668
 669                        NEXT_ARG();
 670                        slen = strlen(*argv);
 671                        if ((slen != 8) && (slen != 16))
 672                                invarg("cookie must be either 8 or 16 hex digits\n", *argv);
 673
 674                        p->cookie_len = slen / 2;
 675                        if (hex2mem(*argv, p->cookie, p->cookie_len) < 0)
 676                                invarg("cookie must be a hex string\n", *argv);
 677                } else if (strcmp(*argv, "peer_cookie") == 0) {
 678                        int slen;
 679
 680                        NEXT_ARG();
 681                        slen = strlen(*argv);
 682                        if ((slen != 8) && (slen != 16))
 683                                invarg("cookie must be either 8 or 16 hex digits\n", *argv);
 684
 685                        p->peer_cookie_len = slen / 2;
 686                        if (hex2mem(*argv, p->peer_cookie, p->peer_cookie_len) < 0)
 687                                invarg("cookie must be a hex string\n", *argv);
 688                } else if (strcmp(*argv, "l2spec_type") == 0) {
 689                        NEXT_ARG();
 690                        if (strcasecmp(*argv, "default") == 0) {
 691                                p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
 692                                p->l2spec_len = 4;
 693                        } else if (strcasecmp(*argv, "none") == 0) {
 694                                p->l2spec_type = L2TP_L2SPECTYPE_NONE;
 695                                p->l2spec_len = 0;
 696                        } else {
 697                                fprintf(stderr,
 698                                        "Unknown layer2specific header type \"%s\"\n",
 699                                        *argv);
 700                                exit(-1);
 701                        }
 702                } else if (strcmp(*argv, "seq") == 0) {
 703                        NEXT_ARG();
 704                        if (strcasecmp(*argv, "both") == 0) {
 705                                p->recv_seq = 1;
 706                                p->send_seq = 1;
 707                        } else if (strcasecmp(*argv, "recv") == 0) {
 708                                p->recv_seq = 1;
 709                        } else if (strcasecmp(*argv, "send") == 0) {
 710                                p->send_seq = 1;
 711                        } else if (strcasecmp(*argv, "none") == 0) {
 712                                p->recv_seq = 0;
 713                                p->send_seq = 0;
 714                        } else {
 715                                fprintf(stderr,
 716                                        "Unknown seq value \"%s\"\n", *argv);
 717                                exit(-1);
 718                        }
 719                } else if (strcmp(*argv, "tunnel") == 0) {
 720                        p->tunnel = 1;
 721                } else if (strcmp(*argv, "session") == 0) {
 722                        p->session = 1;
 723                } else if (matches(*argv, "help") == 0) {
 724                        usage();
 725                } else {
 726                        fprintf(stderr, "Unknown command: %s\n", *argv);
 727                        usage();
 728                }
 729
 730                argc--; argv++;
 731        }
 732
 733        return 0;
 734}
 735
 736
 737static int do_add(int argc, char **argv)
 738{
 739        struct l2tp_parm p;
 740        int ret = 0;
 741
 742        if (parse_args(argc, argv, L2TP_ADD, &p) < 0)
 743                return -1;
 744
 745        if (!p.tunnel && !p.session)
 746                missarg("tunnel or session");
 747
 748        if (p.tunnel_id == 0)
 749                missarg("tunnel_id");
 750
 751        /* session_id and peer_session_id must be provided for sessions */
 752        if ((p.session) && (p.peer_session_id == 0))
 753                missarg("peer_session_id");
 754        if ((p.session) && (p.session_id == 0))
 755                missarg("session_id");
 756
 757        /* peer_tunnel_id is needed for tunnels */
 758        if ((p.tunnel) && (p.peer_tunnel_id == 0))
 759                missarg("peer_tunnel_id");
 760
 761        if (p.tunnel) {
 762                if (p.local_ip.family == AF_UNSPEC)
 763                        missarg("local");
 764
 765                if (p.peer_ip.family == AF_UNSPEC)
 766                        missarg("remote");
 767
 768                if (p.encap == L2TP_ENCAPTYPE_UDP) {
 769                        if (p.local_udp_port == 0)
 770                                missarg("udp_sport");
 771                        if (p.peer_udp_port == 0)
 772                                missarg("udp_dport");
 773                }
 774
 775                ret = create_tunnel(&p);
 776        }
 777
 778        if (p.session) {
 779                /* Only ethernet pseudowires supported */
 780                p.pw_type = L2TP_PWTYPE_ETH;
 781
 782                ret = create_session(&p);
 783        }
 784
 785        return ret;
 786}
 787
 788static int do_del(int argc, char **argv)
 789{
 790        struct l2tp_parm p;
 791
 792        if (parse_args(argc, argv, L2TP_DEL, &p) < 0)
 793                return -1;
 794
 795        if (!p.tunnel && !p.session)
 796                missarg("tunnel or session");
 797
 798        if ((p.tunnel) && (p.tunnel_id == 0))
 799                missarg("tunnel_id");
 800        if ((p.session) && (p.session_id == 0))
 801                missarg("session_id");
 802
 803        if (p.session_id)
 804                return delete_session(&p);
 805        else
 806                return delete_tunnel(&p);
 807
 808        return -1;
 809}
 810
 811static int do_show(int argc, char **argv)
 812{
 813        struct l2tp_data data;
 814        struct l2tp_parm *p = &data.config;
 815
 816        if (parse_args(argc, argv, L2TP_GET, p) < 0)
 817                return -1;
 818
 819        if (!p->tunnel && !p->session)
 820                missarg("tunnel or session");
 821
 822        if (p->session)
 823                get_session(&data);
 824        else
 825                get_tunnel(&data);
 826
 827        return 0;
 828}
 829
 830int do_ipl2tp(int argc, char **argv)
 831{
 832        if (argc < 1 || !matches(*argv, "help"))
 833                usage();
 834
 835        if (genl_init_handle(&genl_rth, L2TP_GENL_NAME, &genl_family))
 836                exit(1);
 837
 838        if (matches(*argv, "add") == 0)
 839                return do_add(argc-1, argv+1);
 840        if (matches(*argv, "delete") == 0)
 841                return do_del(argc-1, argv+1);
 842        if (matches(*argv, "show") == 0 ||
 843            matches(*argv, "lst") == 0 ||
 844            matches(*argv, "list") == 0)
 845                return do_show(argc-1, argv+1);
 846
 847        fprintf(stderr,
 848                "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv);
 849        exit(-1);
 850}
 851