#include <linux/genetlink.h>
#include <linux/l2tp.h>
+#include "libgenl.h"
#include "utils.h"
#include "ip_common.h"
int session:1;
int reorder_timeout;
const char *ifname;
+ uint8_t l2spec_type;
+ uint8_t l2spec_len;
};
struct l2tp_stats {
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);
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;
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;
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);
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;
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;
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])
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);
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);
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");
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);
}
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();
} 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) {
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) {
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) {
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);
}
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 ||