Root/package/libs/libnl-tiny/src/unl.c

1#define _GNU_SOURCE
2#include <netlink/netlink.h>
3#include <netlink/genl/genl.h>
4#include <netlink/genl/ctrl.h>
5#include <netlink/genl/family.h>
6#include <sys/types.h>
7#include <net/if.h>
8#include <unistd.h>
9#include <fcntl.h>
10#include <linux/nl80211.h>
11
12#include "unl.h"
13
14static int unl_init(struct unl *unl)
15{
16    unl->sock = nl_socket_alloc();
17    if (!unl->sock)
18        return -1;
19
20    return 0;
21}
22
23int unl_genl_init(struct unl *unl, const char *family)
24{
25    memset(unl, 0, sizeof(*unl));
26
27    if (unl_init(unl))
28        goto error_out;
29
30    unl->hdrlen = NLMSG_ALIGN(sizeof(struct genlmsghdr));
31    unl->family_name = strdup(family);
32    if (!unl->family_name)
33        goto error;
34
35    if (genl_connect(unl->sock))
36        goto error;
37
38    if (genl_ctrl_alloc_cache(unl->sock, &unl->cache))
39        goto error;
40
41    unl->family = genl_ctrl_search_by_name(unl->cache, family);
42    if (!unl->family)
43        goto error;
44
45    return 0;
46
47error:
48    unl_free(unl);
49error_out:
50    return -1;
51}
52
53void unl_free(struct unl *unl)
54{
55    if (unl->family_name)
56        free(unl->family_name);
57
58    if (unl->sock)
59        nl_socket_free(unl->sock);
60
61    if (unl->cache)
62        nl_cache_free(unl->cache);
63
64    memset(unl, 0, sizeof(*unl));
65}
66
67static int
68ack_handler(struct nl_msg *msg, void *arg)
69{
70    int *err = arg;
71    *err = 0;
72    return NL_STOP;
73}
74
75static int
76finish_handler(struct nl_msg *msg, void *arg)
77{
78    int *err = arg;
79    *err = 0;
80    return NL_SKIP;
81}
82
83static int
84error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
85{
86    int *ret = arg;
87    *ret = err->error;
88    return NL_SKIP;
89}
90
91struct nl_msg *unl_genl_msg(struct unl *unl, int cmd, bool dump)
92{
93    struct nl_msg *msg;
94    int flags = 0;
95
96    msg = nlmsg_alloc();
97    if (!msg)
98        goto out;
99
100    if (dump)
101        flags |= NLM_F_DUMP;
102
103    genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
104            genl_family_get_id(unl->family), 0, flags, cmd, 0);
105
106out:
107    return msg;
108}
109
110int unl_genl_request(struct unl *unl, struct nl_msg *msg, unl_cb handler, void *arg)
111{
112    struct nlmsghdr *nlh;
113    struct nl_cb *cb;
114    int err;
115
116    cb = nl_cb_alloc(NL_CB_CUSTOM);
117    nlh = nlmsg_hdr(msg);
118
119    err = nl_send_auto_complete(unl->sock, msg);
120    if (err < 0)
121        goto out;
122
123    err = 1;
124    nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
125    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
126    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
127    if (handler)
128        nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handler, arg);
129
130    while (err > 0)
131        nl_recvmsgs(unl->sock, cb);
132
133out:
134    nlmsg_free(msg);
135    nl_cb_put(cb);
136    return err;
137}
138
139static int request_single_cb(struct nl_msg *msg, void *arg)
140{
141    struct nl_msg **dest = arg;
142
143    if (!*dest) {
144        nlmsg_get(msg);
145        *dest = msg;
146    }
147    return NL_SKIP;
148}
149
150int unl_genl_request_single(struct unl *unl, struct nl_msg *msg, struct nl_msg **dest)
151{
152    *dest = NULL;
153    return unl_genl_request(unl, msg, request_single_cb, dest);
154}
155
156static int no_seq_check(struct nl_msg *msg, void *arg)
157{
158    return NL_OK;
159}
160
161void unl_genl_loop(struct unl *unl, unl_cb handler, void *arg)
162{
163    struct nl_cb *cb;
164
165    cb = nl_cb_alloc(NL_CB_CUSTOM);
166    unl->loop_done = false;
167    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
168    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handler, arg);
169
170    while (!unl->loop_done)
171        nl_recvmsgs(unl->sock, cb);
172
173    nl_cb_put(cb);
174}
175
176int unl_genl_multicast_id(struct unl *unl, const char *name)
177{
178    struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
179    struct nlattr *groups, *group;
180    struct nl_msg *msg;
181    int ctrlid;
182    int ret = -1;
183    int rem;
184
185    msg = nlmsg_alloc();
186    if (!msg)
187        return -1;
188
189    ctrlid = genl_ctrl_resolve(unl->sock, "nlctrl");
190    genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
191    NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, unl->family_name);
192    unl_genl_request_single(unl, msg, &msg);
193    if (!msg)
194        return -1;
195
196    groups = unl_find_attr(unl, msg, CTRL_ATTR_MCAST_GROUPS);
197    if (!groups)
198        goto nla_put_failure;
199
200    nla_for_each_nested(group, groups, rem) {
201        const char *gn;
202
203        nla_parse(tb, CTRL_ATTR_MCAST_GRP_MAX, nla_data(group),
204              nla_len(group), NULL);
205
206        if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
207            !tb[CTRL_ATTR_MCAST_GRP_ID])
208            continue;
209
210        gn = nla_data(tb[CTRL_ATTR_MCAST_GRP_NAME]);
211        if (strcmp(gn, name) != 0)
212            continue;
213
214        ret = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
215        break;
216    }
217
218nla_put_failure:
219    nlmsg_free(msg);
220    return ret;
221}
222
223int unl_genl_subscribe(struct unl *unl, const char *name)
224{
225    int mcid;
226
227    mcid = unl_genl_multicast_id(unl, name);
228    if (mcid < 0)
229        return mcid;
230
231    return nl_socket_add_membership(unl->sock, mcid);
232}
233
234int unl_genl_unsubscribe(struct unl *unl, const char *name)
235{
236    int mcid;
237
238    mcid = unl_genl_multicast_id(unl, name);
239    if (mcid < 0)
240        return mcid;
241
242    return nl_socket_drop_membership(unl->sock, mcid);
243}
244
245int unl_nl80211_phy_lookup(const char *name)
246{
247    char buf[32];
248    int fd, pos;
249
250    snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
251
252    fd = open(buf, O_RDONLY);
253    if (fd < 0)
254        return -1;
255    pos = read(fd, buf, sizeof(buf) - 1);
256    if (pos < 0) {
257        close(fd);
258        return -1;
259    }
260    buf[pos] = '\0';
261    close(fd);
262    return atoi(buf);
263}
264
265int unl_nl80211_wdev_to_phy(struct unl *unl, int wdev)
266{
267    struct nl_msg *msg;
268    struct nlattr *attr;
269    int ret = -1;
270
271    msg = unl_genl_msg(unl, NL80211_CMD_GET_INTERFACE, false);
272    if (!msg)
273        return -1;
274
275    NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
276    if (unl_genl_request_single(unl, msg, &msg) < 0)
277        return -1;
278
279    attr = unl_find_attr(unl, msg, NL80211_ATTR_WIPHY);
280    if (!attr)
281        goto out;
282
283    ret = nla_get_u32(attr);
284out:
285nla_put_failure:
286    nlmsg_free(msg);
287    return ret;
288}
289
290
291

Archive Download this file



interactive