]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/ipl2tp.c
libnetlink: add size argument to rtnl_talk
[mirror_iproute2.git] / ip / ipl2tp.c
index a05e1a3a8a6c4ffc37fe985db20190ad616c54c8..2f7c9bf1c737f2a53681fe67ba7d49e8333f429e 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/genetlink.h>
 #include <linux/l2tp.h>
+#include "libgenl.h"
 
 #include "utils.h"
 #include "ip_common.h"
@@ -64,6 +65,8 @@ struct l2tp_parm {
        int session:1;
        int reorder_timeout;
        const char *ifname;
+       uint8_t l2spec_type;
+       uint8_t l2spec_len;
 };
 
 struct l2tp_stats {
@@ -92,20 +95,11 @@ static int genl_family = -1;
 
 static int create_tunnel(struct l2tp_parm *p)
 {
-       struct {
-               struct nlmsghdr         n;
-               struct genlmsghdr       g;
-               char                    buf[1024];
-       } req;
        uint32_t local_attr = L2TP_ATTR_IP_SADDR;
        uint32_t peer_attr = L2TP_ATTR_IP_DADDR;
 
-       memset(&req, 0, sizeof(req));
-       req.n.nlmsg_type = genl_family;
-       req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
-       req.g.cmd = L2TP_CMD_TUNNEL_CREATE;
-       req.g.version = L2TP_GENL_VERSION;
+       GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
+                    L2TP_CMD_TUNNEL_CREATE, NLM_F_REQUEST | NLM_F_ACK);
 
        addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
        addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
@@ -125,7 +119,7 @@ static int create_tunnel(struct l2tp_parm *p)
                addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
        }
 
-       if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+       if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
                return -2;
 
        return 0;
@@ -133,22 +127,12 @@ static int create_tunnel(struct l2tp_parm *p)
 
 static int delete_tunnel(struct l2tp_parm *p)
 {
-       struct {
-               struct nlmsghdr         n;
-               struct genlmsghdr       g;
-               char                    buf[128];
-       } req;
-
-       memset(&req, 0, sizeof(req));
-       req.n.nlmsg_type = genl_family;
-       req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
-       req.g.cmd = L2TP_CMD_TUNNEL_DELETE;
-       req.g.version = L2TP_GENL_VERSION;
+       GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
+                    L2TP_CMD_TUNNEL_DELETE, NLM_F_REQUEST | NLM_F_ACK);
 
        addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
 
-       if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+       if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
                return -2;
 
        return 0;
@@ -156,24 +140,16 @@ static int delete_tunnel(struct l2tp_parm *p)
 
 static int create_session(struct l2tp_parm *p)
 {
-       struct {
-               struct nlmsghdr         n;
-               struct genlmsghdr       g;
-               char                    buf[1024];
-       } req;
-
-       memset(&req, 0, sizeof(req));
-       req.n.nlmsg_type = genl_family;
-       req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
-       req.g.cmd = L2TP_CMD_SESSION_CREATE;
-       req.g.version = L2TP_GENL_VERSION;
+       GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
+                    L2TP_CMD_SESSION_CREATE, NLM_F_REQUEST | NLM_F_ACK);
 
        addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
        addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
        addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
        addattr32(&req.n, 1024, L2TP_ATTR_PEER_SESSION_ID, p->peer_session_id);
        addattr16(&req.n, 1024, L2TP_ATTR_PW_TYPE, p->pw_type);
+       addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type);
+       addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len);
 
        if (p->mtu)             addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu);
        if (p->recv_seq)        addattr(&req.n, 1024, L2TP_ATTR_RECV_SEQ);
@@ -190,7 +166,7 @@ static int create_session(struct l2tp_parm *p)
        if (p->ifname && p->ifname[0])
                addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
 
-       if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+       if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
                return -2;
 
        return 0;
@@ -198,22 +174,12 @@ static int create_session(struct l2tp_parm *p)
 
 static int delete_session(struct l2tp_parm *p)
 {
-       struct {
-               struct nlmsghdr         n;
-               struct genlmsghdr       g;
-               char                    buf[128];
-       } req;
-
-       memset(&req, 0, sizeof(req));
-       req.n.nlmsg_type = genl_family;
-       req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
-       req.g.cmd = L2TP_CMD_SESSION_DELETE;
-       req.g.version = L2TP_GENL_VERSION;
+       GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
+                    L2TP_CMD_SESSION_DELETE, NLM_F_REQUEST | NLM_F_ACK);
 
        addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
        addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
-       if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+       if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
                return -2;
 
        return 0;
@@ -309,6 +275,10 @@ static int get_response(struct nlmsghdr *n, void *arg)
                p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]);
        if (attrs[L2TP_ATTR_PEER_SESSION_ID])
                p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]);
+       if (attrs[L2TP_ATTR_L2SPEC_TYPE])
+               p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]);
+       if (attrs[L2TP_ATTR_L2SPEC_LEN])
+               p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);
 
        p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM];
        if (attrs[L2TP_ATTR_COOKIE])
@@ -396,20 +366,11 @@ static int session_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void
 
 static int get_session(struct l2tp_data *p)
 {
-       struct {
-               struct nlmsghdr         n;
-               struct genlmsghdr       g;
-               char buf[128];
-       } req;
-
-       memset(&req, 0, sizeof(req));
-       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
-       req.n.nlmsg_type = genl_family;
-       req.n.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
-       req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
+       GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
+                    L2TP_CMD_SESSION_GET,
+                    NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
 
-       req.g.cmd = L2TP_CMD_SESSION_GET;
-       req.g.version = L2TP_GENL_VERSION;
+       req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
 
        if (p->config.tunnel_id && p->config.session_id) {
                addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
@@ -439,20 +400,11 @@ static int tunnel_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void
 
 static int get_tunnel(struct l2tp_data *p)
 {
-       struct {
-               struct nlmsghdr         n;
-               struct genlmsghdr       g;
-               char buf[1024];
-       } req;
-
-       memset(&req, 0, sizeof(req));
-       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
-       req.n.nlmsg_type = genl_family;
-       req.n.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
-       req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
+       GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
+                    L2TP_CMD_TUNNEL_GET,
+                    NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
 
-       req.g.cmd = L2TP_CMD_TUNNEL_GET;
-       req.g.version = L2TP_GENL_VERSION;
+       req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
 
        if (p->config.tunnel_id)
                addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
@@ -522,6 +474,7 @@ static void usage(void)
        fprintf(stderr, "          session_id ID peer_session_id ID\n");
        fprintf(stderr, "          [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n");
        fprintf(stderr, "          [ offset OFFSET ] [ peer_offset OFFSET ]\n");
+       fprintf(stderr, "          [ l2spec_type L2SPEC ]\n");
        fprintf(stderr, "       ip l2tp del tunnel tunnel_id ID\n");
        fprintf(stderr, "       ip l2tp del session tunnel_id ID session_id ID\n");
        fprintf(stderr, "       ip l2tp show tunnel [ tunnel_id ID ]\n");
@@ -532,6 +485,7 @@ static void usage(void)
        fprintf(stderr, "       PORT   := { 0..65535 }\n");
        fprintf(stderr, "       ID     := { 1..4294967295 }\n");
        fprintf(stderr, "       HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n");
+       fprintf(stderr, "       L2SPEC := { none | default }\n");
        exit(-1);
 }
 
@@ -542,6 +496,10 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
        if (argc == 0)
                usage();
 
+       /* Defaults */
+       p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
+       p->l2spec_len = 4;
+
        while (argc > 0) {
                if (strcmp(*argv, "encap") == 0) {
                        NEXT_ARG();
@@ -550,7 +508,7 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
                        } else if (strcmp(*argv, "udp") == 0) {
                                p->encap = L2TP_ENCAPTYPE_UDP;
                        } else {
-                               fprintf(stderr, "Unknown tunnel encapsulation.\n");
+                               fprintf(stderr, "Unknown tunnel encapsulation \"%s\"\n", *argv);
                                exit(-1);
                        }
                } else if (strcmp(*argv, "name") == 0) {
@@ -636,6 +594,18 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
                        p->peer_cookie_len = slen / 2;
                        if (hex2mem(*argv, p->peer_cookie, p->peer_cookie_len) < 0)
                                invarg("cookie must be a hex string\n", *argv);
+               } else if (strcmp(*argv, "l2spec_type") == 0) {
+                       NEXT_ARG();
+                       if (strcasecmp(*argv, "default") == 0) {
+                               p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
+                               p->l2spec_len = 4;
+                       } else if (strcasecmp(*argv, "none") == 0) {
+                               p->l2spec_type = L2TP_L2SPECTYPE_NONE;
+                               p->l2spec_len = 0;
+                       } else {
+                               fprintf(stderr, "Unknown layer2specific header type \"%s\"\n", *argv);
+                               exit(-1);
+                       }
                } else if (strcmp(*argv, "tunnel") == 0) {
                        p->tunnel = 1;
                } else if (strcmp(*argv, "session") == 0) {
@@ -747,67 +717,6 @@ static int do_show(int argc, char **argv)
        return 0;
 }
 
-static int genl_parse_getfamily(struct nlmsghdr *nlh)
-{
-       struct rtattr *tb[CTRL_ATTR_MAX + 1];
-       struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
-       int len = nlh->nlmsg_len;
-       struct rtattr *attrs;
-
-       if (nlh->nlmsg_type != GENL_ID_CTRL) {
-               fprintf(stderr, "Not a controller message, nlmsg_len=%d "
-                       "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
-               return -1;
-       }
-
-       if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
-               fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
-               return -1;
-       }
-
-       len -= NLMSG_LENGTH(GENL_HDRLEN);
-
-       if (len < 0) {
-               fprintf(stderr, "wrong controller message len %d\n", len);
-               return -1;
-       }
-
-       attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
-       parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
-
-       if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
-               fprintf(stderr, "Missing family id TLV\n");
-               return -1;
-       }
-
-       return rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
-}
-
-int genl_ctrl_resolve_family(const char *family)
-{
-       struct {
-               struct nlmsghdr         n;
-               struct genlmsghdr       g;
-               char                    buf[1024];
-       } req;
-
-       memset(&req, 0, sizeof(req));
-       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
-       req.n.nlmsg_flags = NLM_F_REQUEST;
-       req.n.nlmsg_type = GENL_ID_CTRL;
-       req.g.cmd = CTRL_CMD_GETFAMILY;
-
-       addattr_l(&req.n, 1024, CTRL_ATTR_FAMILY_NAME,
-                 family, strlen(family) + 1);
-
-       if (rtnl_talk(&genl_rth, &req.n, 0, 0, &req.n) < 0) {
-               fprintf(stderr, "Error talking to the kernel\n");
-               return -2;
-       }
-
-       return genl_parse_getfamily(&req.n);
-}
-
 int do_ipl2tp(int argc, char **argv)
 {
        if (genl_family < 0) {
@@ -816,7 +725,7 @@ int do_ipl2tp(int argc, char **argv)
                        exit(1);
                }
 
-               genl_family = genl_ctrl_resolve_family(L2TP_GENL_NAME);
+               genl_family = genl_resolve_family(&genl_rth, L2TP_GENL_NAME);
                if (genl_family < 0)
                        exit(1);
        }
@@ -826,7 +735,7 @@ int do_ipl2tp(int argc, char **argv)
 
        if (matches(*argv, "add") == 0)
                return do_add(argc-1, argv+1);
-       if (matches(*argv, "del") == 0)
+       if (matches(*argv, "delete") == 0)
                return do_del(argc-1, argv+1);
        if (matches(*argv, "show") == 0 ||
            matches(*argv, "lst") == 0 ||