]> git.ipfire.org Git - people/ms/network.git/blob - src/libnetwork/libnetwork.c
libnetwork: Add command that returns supported HT caps for wireless PHYs
[people/ms/network.git] / src / libnetwork / libnetwork.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2017 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <linux/nl80211.h>
24 #include <netlink/genl/ctrl.h>
25 #include <netlink/genl/genl.h>
26 #include <netlink/netlink.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <syslog.h>
32
33 #include <network/libnetwork.h>
34 #include <network/logging.h>
35 #include "libnetwork-private.h"
36
37 struct network_ctx {
38 int refcount;
39
40 // Logging
41 void (*log_fn)(struct network_ctx* ctx,
42 int priority, const char *file, int line, const char *fn,
43 const char *format, va_list args);
44 int log_priority;
45
46 // Netlink
47 struct nl_sock* nl_socket;
48 int nl80211_id;
49 };
50
51 void network_log(struct network_ctx* ctx,
52 int priority, const char* file, int line, const char* fn,
53 const char* format, ...) {
54 va_list args;
55
56 va_start(args, format);
57 ctx->log_fn(ctx, priority, file, line, fn, format, args);
58 va_end(args);
59 }
60
61 static void log_stderr(struct network_ctx* ctx,
62 int priority, const char* file, int line, const char* fn,
63 const char* format, va_list args) {
64 fprintf(stderr, "libnetwork: %s: ", fn);
65 vfprintf(stderr, format, args);
66 }
67
68 static int log_priority(const char* priority) {
69 char *endptr;
70
71 int prio = strtol(priority, &endptr, 10);
72
73 if (endptr[0] == '\0' || isspace(endptr[0]))
74 return prio;
75
76 if (strncmp(priority, "err", 3) == 0)
77 return LOG_ERR;
78
79 if (strncmp(priority, "info", 4) == 0)
80 return LOG_INFO;
81
82 if (strncmp(priority, "debug", 5) == 0)
83 return LOG_DEBUG;
84
85 return 0;
86 }
87
88 static int init_netlink(struct network_ctx* ctx) {
89 // Allocate netlink socket
90 ctx->nl_socket = nl_socket_alloc();
91 if (!ctx->nl_socket) {
92 ERROR(ctx, "Failed to allocate netlink socket\n");
93 return -ENOMEM;
94 }
95
96 // Connect the socket
97 if (genl_connect(ctx->nl_socket)) {
98 ERROR(ctx, "Failed to connect to generic netlink");
99 return -ENOLINK;
100 }
101
102 // Set buffer size
103 nl_socket_set_buffer_size(ctx->nl_socket, 8192, 8192);
104
105 // Register socket callback
106 struct nl_cb* callback = nl_cb_alloc(NL_CB_DEFAULT);
107 if (!callback) {
108 ERROR(ctx, "Could not allocate socket callback\n");
109 return -ENOMEM;
110 }
111
112 nl_socket_set_cb(ctx->nl_socket, callback);
113
114 // Get nl80211 id
115 ctx->nl80211_id = genl_ctrl_resolve(ctx->nl_socket, "nl80211");
116 if (ctx->nl80211_id < 0) {
117 ERROR(ctx, "Could not find nl80211\n");
118 return -ENOENT;
119 }
120
121 return 0;
122 }
123
124 static void network_free(struct network_ctx* ctx) {
125 DEBUG(ctx, "network ctx %p released\n", ctx);
126
127 // Free netlink socket
128 if (ctx->nl_socket)
129 nl_socket_free(ctx->nl_socket);
130
131 free(ctx);
132 }
133
134 NETWORK_EXPORT int network_new(struct network_ctx** ctx) {
135 struct network_ctx* c = calloc(1, sizeof(*c));
136 if (!c)
137 return -ENOMEM;
138
139 // Initialise basic variables
140 c->refcount = 1;
141
142 // Initialise logging
143 c->log_fn = log_stderr;
144 c->log_priority = LOG_ERR;
145
146 const char* env = secure_getenv("NETWORK_LOG");
147 if (env)
148 network_set_log_priority(c, log_priority(env));
149
150 // Initiate netlink connection
151 int r = init_netlink(c);
152 if (r) {
153 network_free(c);
154 return r;
155 }
156
157 INFO(c, "network ctx %p created\n", c);
158 DEBUG(c, "log_priority=%d\n", c->log_priority);
159
160 *ctx = c;
161 return 0;
162 }
163
164 NETWORK_EXPORT struct network_ctx* network_ref(struct network_ctx* ctx) {
165 if (!ctx)
166 return NULL;
167
168 ctx->refcount++;
169 return ctx;
170 }
171
172 NETWORK_EXPORT struct network_ctx* network_unref(struct network_ctx* ctx) {
173 if (!ctx)
174 return NULL;
175
176 if (--ctx->refcount > 0)
177 return ctx;
178
179 network_free(ctx);
180 return NULL;
181 }
182
183 NETWORK_EXPORT void network_set_log_fn(struct network_ctx* ctx,
184 void (*log_fn)(struct network_ctx* ctx, int priority, const char* file,
185 int line, const char* fn, const char* format, va_list args)) {
186 ctx->log_fn = log_fn;
187 INFO(ctx, "custom logging function %p registered\n", log_fn);
188 }
189
190 NETWORK_EXPORT int network_get_log_priority(struct network_ctx* ctx) {
191 return ctx->log_priority;
192 }
193
194 NETWORK_EXPORT void network_set_log_priority(struct network_ctx* ctx, int priority) {
195 ctx->log_priority = priority;
196 }
197
198 NETWORK_EXPORT const char* network_version() {
199 return "network " VERSION;
200 }
201
202 // Creates a netlink message that can be sent with network_send_netlink_message
203 struct nl_msg* network_make_netlink_message(struct network_ctx* ctx,
204 enum nl80211_commands cmd, int flags) {
205 // Allocate message
206 struct nl_msg* msg = nlmsg_alloc();
207 if (!msg)
208 return NULL;
209
210 genlmsg_put(msg, 0, 0, ctx->nl80211_id, 0, flags, cmd, 0);
211
212 DEBUG(ctx, "Created new netlink message %p\n", msg);
213
214 return msg;
215 }
216
217 static int __nl_ack_handler(struct nl_msg* msg, void* data) {
218 int* r = data;
219 *r = 0;
220
221 return NL_STOP;
222 }
223
224 static int __nl_finish_handler(struct nl_msg* msg, void* data) {
225 int* r = data;
226 *r = 0;
227
228 return NL_SKIP;
229 }
230
231 // Sends a netlink message and calls the handler to handle the result
232 int network_send_netlink_message(struct network_ctx* ctx, struct nl_msg* msg,
233 int(*handler)(struct nl_msg* msg, void* data), void* data) {
234 DEBUG(ctx, "Sending netlink message %p\n", msg);
235
236 // Sending the message
237 int r = nl_send_auto(ctx->nl_socket, msg);
238 if (r < 0) {
239 ERROR(ctx, "Error sending netlink message: %d\n", r);
240 return r;
241 }
242
243 // Register callback
244 struct nl_cb* callback = nl_cb_alloc(NL_CB_DEFAULT);
245 if (!callback) {
246 ERROR(ctx, "Could not allocate callback\n");
247 nlmsg_free(msg);
248
249 return -1;
250 }
251
252 r = 1;
253
254 nl_cb_set(callback, NL_CB_VALID, NL_CB_CUSTOM, handler, data);
255 nl_cb_set(callback, NL_CB_ACK, NL_CB_CUSTOM, __nl_ack_handler, &r);
256 nl_cb_set(callback, NL_CB_FINISH, NL_CB_CUSTOM, __nl_finish_handler, &r);
257
258 while (r > 0)
259 nl_recvmsgs(ctx->nl_socket, callback);
260
261 DEBUG(ctx, "Netlink message returned with status %d\n", r);
262
263 return r;
264 }