blob: 0dd54737b3550198b720e040b92abcdab2ce0aa2 [file] [log] [blame]
Pablo Neira Ayuso14506662014-02-20 18:43:15 +01001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <time.h>
6#include <arpa/inet.h>
7#include <sys/socket.h>
8#include <netinet/in.h>
9#include <inttypes.h>
10
11#include <libmnl/libmnl.h>
12#include <linux/genetlink.h>
13
14#include <libgtpnl/gtpnl.h>
15
16#include <net/if.h>
17#include <linux/gtp_nl.h>
18
19#include "internal.h"
20
21static void gtp_build_payload(struct nlmsghdr *nlh, uint64_t tid,
22 uint32_t ifidx, uint32_t sgsn_addr,
23 uint32_t ms_addr, uint32_t version)
24{
25 mnl_attr_put_u32(nlh, GTPA_VERSION, version);
26 mnl_attr_put_u32(nlh, GTPA_LINK, ifidx);
27 mnl_attr_put_u32(nlh, GTPA_SGSN_ADDRESS, sgsn_addr);
28 mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, ms_addr);
29 mnl_attr_put_u64(nlh, GTPA_TID, tid);
30}
31
32int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, const char *ifname,
33 const char *ms_addr, const char *sgsn_addr, uint64_t tid,
34 int gtp_version)
35{
36 uint32_t gtp_ifidx;
37 struct in_addr ms, sgsn;
38 struct nlmsghdr *nlh;
39 char buf[MNL_SOCKET_BUFFER_SIZE];
40 uint32_t seq = time(NULL);
41
42 gtp_ifidx = if_nametoindex(ifname);
43 if (gtp_ifidx == 0){
44 fprintf(stderr, "wrong GTP interface %s\n", ifname);
45 return -1;
46 }
47
48 if (inet_aton(ms_addr, &ms) < 0) {
49 perror("bad address for ms");
50 return -1;
51 }
52
53 if (inet_aton(sgsn_addr, &sgsn) < 0) {
54 perror("bad address for sgsn");
55 return -1;
56 }
57
58 if (gtp_version > GTP_V1) {
59 fprintf(stderr, "wrong GTP version %u, use v0 or v1\n",
60 gtp_version);
61 return -1;
62 }
63
64 nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_EXCL | NLM_F_ACK, ++seq,
65 GTP_CMD_TUNNEL_NEW);
66 gtp_build_payload(nlh, tid, gtp_ifidx, sgsn.s_addr,
67 ms.s_addr, gtp_version);
68
69 if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
70 perror("genl_socket_talk");
71
72 return 0;
73}
74EXPORT_SYMBOL(gtp_add_tunnel);
75
76int gtp_del_tunnel(int genl_id, struct mnl_socket *nl, const char *ifname,
77 uint64_t tid, uint32_t gtp_version)
78{
79 uint32_t gtp_ifidx;
80 char buf[MNL_SOCKET_BUFFER_SIZE];
81 struct nlmsghdr *nlh;
82 uint32_t seq = time(NULL);
83
84 gtp_ifidx = if_nametoindex(ifname);
85
86 nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_ACK, ++seq,
87 GTP_CMD_TUNNEL_DELETE);
88 gtp_build_payload(nlh, tid, gtp_ifidx, 0, 0, gtp_version);
89
90 if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
91 perror("genl_socket_talk");
92
93 return 0;
94}
95EXPORT_SYMBOL(gtp_del_tunnel);
96
97struct gtp_pdp {
98 uint32_t version;
99 uint64_t tid;
100 struct in_addr sgsn_addr;
101 struct in_addr ms_addr;
102};
103
104static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
105{
106 const struct nlattr **tb = data;
107 int type = mnl_attr_get_type(attr);
108
109 if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
110 return MNL_CB_OK;
111
112 switch(type) {
113 case GTPA_TID:
114 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
115 perror("mnl_attr_validate");
116 return MNL_CB_ERROR;
117 }
118 break;
119 case GTPA_SGSN_ADDRESS:
120 case GTPA_MS_ADDRESS:
121 case GTPA_VERSION:
122 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
123 perror("mnl_attr_validate");
124 return MNL_CB_ERROR;
125 }
126 break;
127 default:
128 break;
129 }
130 tb[type] = attr;
131 return MNL_CB_OK;
132}
133
134static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data)
135{
136 struct nlattr *tb[GTPA_MAX + 1] = {};
137 struct gtp_pdp pdp;
138 struct genlmsghdr *genl;
139
140 mnl_attr_parse(nlh, sizeof(*genl), genl_gtp_validate_cb, tb);
141 if (tb[GTPA_TID])
142 pdp.tid = mnl_attr_get_u64(tb[GTPA_TID]);
143 if (tb[GTPA_SGSN_ADDRESS]) {
144 pdp.sgsn_addr.s_addr =
145 mnl_attr_get_u32(tb[GTPA_SGSN_ADDRESS]);
146 }
147 if (tb[GTPA_MS_ADDRESS]) {
148 pdp.ms_addr.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]);
149 }
150 if (tb[GTPA_VERSION]) {
151 pdp.version = mnl_attr_get_u32(tb[GTPA_VERSION]);
152 }
153
154 printf("version %u ", pdp.version);
155 printf("tid %"PRIu64" ms_addr %s ", pdp.tid, inet_ntoa(pdp.sgsn_addr));
156 printf("sgsn_addr %s\n", inet_ntoa(pdp.ms_addr));
157
158 return MNL_CB_OK;
159}
160
161int gtp_list_tunnel(int genl_id, struct mnl_socket *nl)
162{
163 char buf[MNL_SOCKET_BUFFER_SIZE];
164 struct nlmsghdr *nlh;
165 uint32_t seq = time(NULL);
166
167 nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_DUMP, 0,
168 GTP_CMD_TUNNEL_GET);
169
170 if (genl_socket_talk(nl, nlh, seq, genl_gtp_attr_cb, NULL) < 0) {
171 perror("genl_socket_talk");
172 return 0;
173 }
174
175 return 0;
176}
177EXPORT_SYMBOL(gtp_list_tunnel);