blob: ca5b419a0877443039ed81c44b60105e13469a55 [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
31static int gtp_dev_talk(struct nlmsghdr *nlh, uint32_t seq)
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010032{
33 struct mnl_socket *nl;
34 char buf[MNL_SOCKET_BUFFER_SIZE];
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010035 int ret;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010036
37 nl = mnl_socket_open(NETLINK_ROUTE);
38 if (nl == NULL) {
39 perror("mnl_socket_open");
40 return -1;
41 }
42
43 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
44 perror("mnl_socket_bind");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010045 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010046 }
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010047
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010048 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
49 perror("mnl_socket_send");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010050 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010051 }
52
53 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
54 if (ret == -1) {
55 perror("read");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010056 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010057 }
58
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010059 ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL);
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010060 if (ret == -1){
61 perror("callback");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010062 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010063 }
64
65 mnl_socket_close(nl);
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010066 return 0;
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010067err:
68 mnl_socket_close(nl);
69 return -1;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010070}
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010071
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010072int gtp_dev_create(const char *gtp_ifname, const char *real_ifname,
73 int fd0, int fd1)
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010074{
75 char buf[MNL_SOCKET_BUFFER_SIZE];
76 struct nlmsghdr *nlh;
77 struct ifinfomsg *ifm;
78 unsigned int seq = time(NULL);
79 struct nlattr *nest, *nest2;
80
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010081 nlh = gtp_put_nlmsg(buf, RTM_NEWLINK,
82 NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK, seq);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010083 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
84 ifm->ifi_family = AF_INET;
85 ifm->ifi_change |= IFF_UP;
86 ifm->ifi_flags |= IFF_UP;
87
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010088 mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(real_ifname));
89 mnl_attr_put_str(nlh, IFLA_IFNAME, gtp_ifname);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010090 nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO);
91 mnl_attr_put_str(nlh, IFLA_INFO_KIND, "gtp");
92 nest2 = mnl_attr_nest_start(nlh, IFLA_INFO_DATA);
Pablo Neira Ayusodea76a02014-02-23 21:55:42 +010093 mnl_attr_put_u32(nlh, IFLA_GTP_FD0, fd0);
94 mnl_attr_put_u32(nlh, IFLA_GTP_FD1, fd1);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010095 mnl_attr_put_u32(nlh, IFLA_GTP_HASHSIZE, 131072);
96 mnl_attr_nest_end(nlh, nest2);
97 mnl_attr_nest_end(nlh, nest);
98
99 return gtp_dev_talk(nlh, seq);
100}
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100101EXPORT_SYMBOL(gtp_dev_create);
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100102
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100103int gtp_dev_destroy(const char *gtp_ifname)
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100104{
105 char buf[MNL_SOCKET_BUFFER_SIZE];
106 struct nlmsghdr *nlh;
107 struct ifinfomsg *ifm;
108 unsigned int seq = time(NULL);
109
110 nlh = gtp_put_nlmsg(buf, RTM_DELLINK, NLM_F_ACK, seq);
111 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
112 ifm->ifi_family = AF_INET;
113 ifm->ifi_change |= IFF_UP;
114 ifm->ifi_flags &= ~IFF_UP;
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100115 ifm->ifi_index = if_nametoindex(gtp_ifname);
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100116
117 return gtp_dev_talk(nlh, seq);
118}
119EXPORT_SYMBOL(gtp_dev_destroy);