blob: 7481ced290e052dee0ed183ae919962c5d2a4038 [file] [log] [blame]
Pablo Neira Ayuso14506662014-02-20 18:43:15 +01001#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
5#include <time.h>
6
7#include <libmnl/libmnl.h>
8#include <net/if.h>
9#include <linux/if_link.h>
10#include <linux/rtnetlink.h>
11
12#include <libgtpnl/gtpnl.h>
13
14#include <linux/gtp_nl.h>
15
16#include "internal.h"
17
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010018static struct nlmsghdr *
19gtp_put_nlmsg(char *buf, uint16_t type, uint16_t nl_flags, uint32_t seq)
20{
21 struct nlmsghdr *nlh;
22
23 nlh = mnl_nlmsg_put_header(buf);
24 nlh->nlmsg_type = type;
25 nlh->nlmsg_flags = NLM_F_REQUEST | nl_flags;
26 nlh->nlmsg_seq = seq;
27
28 return nlh;
29}
30
Pablo Neira Ayuso1f683292014-03-20 16:21:29 +010031static struct mnl_socket *rtnl_open(void)
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010032{
33 struct mnl_socket *nl;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010034
35 nl = mnl_socket_open(NETLINK_ROUTE);
36 if (nl == NULL) {
37 perror("mnl_socket_open");
Pablo Neira Ayuso1f683292014-03-20 16:21:29 +010038 return NULL;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010039 }
40
41 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
42 perror("mnl_socket_bind");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010043 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010044 }
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010045
Pablo Neira Ayuso1f683292014-03-20 16:21:29 +010046 return nl;
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010047err:
48 mnl_socket_close(nl);
Pablo Neira Ayuso1f683292014-03-20 16:21:29 +010049 return NULL;
50}
51
52static int rtnl_talk(struct mnl_socket *nl, struct nlmsghdr *nlh)
53{
54 char buf[MNL_SOCKET_BUFFER_SIZE];
55 int ret;
56
57 ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
58 if (ret < 0)
59 return ret;
60
61 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
62 if (ret < 0)
63 return ret;
64
65 return mnl_cb_run(buf, ret, nlh->nlmsg_seq, mnl_socket_get_portid(nl),
66 NULL, NULL);
67}
68
69static int gtp_dev_talk(struct nlmsghdr *nlh, uint32_t seq)
70{
71 struct mnl_socket *nl;
72 int ret;
73
74 nl = rtnl_open();
75 if (nl == NULL)
76 return -1;
77
78 ret = rtnl_talk(nl, nlh);
79
80 mnl_socket_close(nl);
81 return ret;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010082}
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010083
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010084int gtp_dev_create(const char *gtp_ifname, const char *real_ifname,
85 int fd0, int fd1)
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010086{
87 char buf[MNL_SOCKET_BUFFER_SIZE];
88 struct nlmsghdr *nlh;
89 struct ifinfomsg *ifm;
90 unsigned int seq = time(NULL);
91 struct nlattr *nest, *nest2;
92
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010093 nlh = gtp_put_nlmsg(buf, RTM_NEWLINK,
94 NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK, seq);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010095 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
96 ifm->ifi_family = AF_INET;
97 ifm->ifi_change |= IFF_UP;
98 ifm->ifi_flags |= IFF_UP;
99
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100100 mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(real_ifname));
101 mnl_attr_put_str(nlh, IFLA_IFNAME, gtp_ifname);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +0100102 nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO);
103 mnl_attr_put_str(nlh, IFLA_INFO_KIND, "gtp");
104 nest2 = mnl_attr_nest_start(nlh, IFLA_INFO_DATA);
Pablo Neira Ayusodea76a02014-02-23 21:55:42 +0100105 mnl_attr_put_u32(nlh, IFLA_GTP_FD0, fd0);
106 mnl_attr_put_u32(nlh, IFLA_GTP_FD1, fd1);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +0100107 mnl_attr_put_u32(nlh, IFLA_GTP_HASHSIZE, 131072);
108 mnl_attr_nest_end(nlh, nest2);
109 mnl_attr_nest_end(nlh, nest);
110
111 return gtp_dev_talk(nlh, seq);
112}
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100113EXPORT_SYMBOL(gtp_dev_create);
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100114
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100115int gtp_dev_destroy(const char *gtp_ifname)
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100116{
117 char buf[MNL_SOCKET_BUFFER_SIZE];
118 struct nlmsghdr *nlh;
119 struct ifinfomsg *ifm;
120 unsigned int seq = time(NULL);
121
122 nlh = gtp_put_nlmsg(buf, RTM_DELLINK, NLM_F_ACK, seq);
123 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
124 ifm->ifi_family = AF_INET;
125 ifm->ifi_change |= IFF_UP;
126 ifm->ifi_flags &= ~IFF_UP;
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100127 ifm->ifi_index = if_nametoindex(gtp_ifname);
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100128
129 return gtp_dev_talk(nlh, seq);
130}
131EXPORT_SYMBOL(gtp_dev_destroy);