blob: 48dbdf067665338184183db60e2d97f945611c04 [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
75int gtp_dev_create(const char *ifname)
76{
77 char buf[MNL_SOCKET_BUFFER_SIZE];
78 struct nlmsghdr *nlh;
79 struct ifinfomsg *ifm;
80 unsigned int seq = time(NULL);
81 struct nlattr *nest, *nest2;
82
83 nlh = gtp_put_nlmsg(buf, RTM_NEWLINK, NLM_F_CREATE | NLM_F_ACK, seq);
84 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
85 ifm->ifi_family = AF_INET;
86 ifm->ifi_change |= IFF_UP;
87 ifm->ifi_flags |= IFF_UP;
88
89 mnl_attr_put_u32(nlh, IFLA_LINK, if_nametoindex(ifname));
90 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);
93 mnl_attr_put_u32(nlh, IFLA_GTP_LOCAL_ADDR_IPV4, 0);
94 mnl_attr_put_u32(nlh, IFLA_GTP_HASHSIZE, 131072);
95 mnl_attr_nest_end(nlh, nest2);
96 mnl_attr_nest_end(nlh, nest);
97
98 return gtp_dev_talk(nlh, seq);
99}
Pablo Neira Ayuso14506662014-02-20 18:43:15 +0100100EXPORT_SYMBOL(gtp_dev_create);
Pablo Neira Ayuso41ff5382014-02-22 23:07:41 +0100101
102int gtp_dev_destroy(const char *ifname)
103{
104 char buf[MNL_SOCKET_BUFFER_SIZE];
105 struct nlmsghdr *nlh;
106 struct ifinfomsg *ifm;
107 unsigned int seq = time(NULL);
108
109 nlh = gtp_put_nlmsg(buf, RTM_DELLINK, NLM_F_ACK, seq);
110 ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
111 ifm->ifi_family = AF_INET;
112 ifm->ifi_change |= IFF_UP;
113 ifm->ifi_flags &= ~IFF_UP;
114 ifm->ifi_index = if_nametoindex(ifname);
115
116 return gtp_dev_talk(nlh, seq);
117}
118EXPORT_SYMBOL(gtp_dev_destroy);