blob: 519cacb72ac3f67c63e2ae78138e6da952c02e20 [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
48 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
49 sizeof(struct ifinfomsg));
50
51 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
52 perror("mnl_socket_send");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010053 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010054 }
55
56 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
57 if (ret == -1) {
58 perror("read");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010059 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010060 }
61
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010062 ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL);
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010063 if (ret == -1){
64 perror("callback");
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010065 goto err;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010066 }
67
68 mnl_socket_close(nl);
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010069 return 0;
Pablo Neira Ayuso3876ef62014-02-22 22:50:00 +010070err:
71 mnl_socket_close(nl);
72 return -1;
Pablo Neira Ayuso14506662014-02-20 18:43:15 +010073}
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010074
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010075int gtp_dev_create(const char *gtp_ifname, const char *real_ifname,
76 int fd0, int fd1)
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010077{
78 char buf[MNL_SOCKET_BUFFER_SIZE];
79 struct nlmsghdr *nlh;
80 struct ifinfomsg *ifm;
81 unsigned int seq = time(NULL);
82 struct nlattr *nest, *nest2;
83
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010084 nlh = gtp_put_nlmsg(buf, RTM_NEWLINK,
85 NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK, seq);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010086 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
87 ifm->ifi_family = AF_INET;
88 ifm->ifi_change |= IFF_UP;
89 ifm->ifi_flags |= IFF_UP;
90
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +010091 mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(real_ifname));
92 mnl_attr_put_str(nlh, IFLA_IFNAME, gtp_ifname);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010093 nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO);
94 mnl_attr_put_str(nlh, IFLA_INFO_KIND, "gtp");
95 nest2 = mnl_attr_nest_start(nlh, IFLA_INFO_DATA);
Pablo Neira Ayusodea76a02014-02-23 21:55:42 +010096 mnl_attr_put_u32(nlh, IFLA_GTP_FD0, fd0);
97 mnl_attr_put_u32(nlh, IFLA_GTP_FD1, fd1);
Pablo Neira Ayuso10df0592014-02-22 22:57:07 +010098 mnl_attr_put_u32(nlh, IFLA_GTP_HASHSIZE, 131072);
99 mnl_attr_nest_end(nlh, nest2);
100 mnl_attr_nest_end(nlh, nest);
101
102 return gtp_dev_talk(nlh, seq);
103}
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100104EXPORT_SYMBOL(gtp_dev_create);
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100105
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100106int gtp_dev_destroy(const char *gtp_ifname)
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100107{
108 char buf[MNL_SOCKET_BUFFER_SIZE];
109 struct nlmsghdr *nlh;
110 struct ifinfomsg *ifm;
111 unsigned int seq = time(NULL);
112
113 nlh = gtp_put_nlmsg(buf, RTM_DELLINK, NLM_F_ACK, seq);
114 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
115 ifm->ifi_family = AF_INET;
116 ifm->ifi_change |= IFF_UP;
117 ifm->ifi_flags &= ~IFF_UP;
Pablo Neira Ayuso7aa20872014-02-24 11:38:52 +0100118 ifm->ifi_index = if_nametoindex(gtp_ifname);
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100119
120 return gtp_dev_talk(nlh, seq);
121}
122EXPORT_SYMBOL(gtp_dev_destroy);