xio: refactor fopencookie related functions
[netsniff-ng.git] / mac80211.c
blob32f75f1cdd9ff8cf374fcf2d632ae7ecbd295656
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2012 Daniel Borkmann.
4 * Subject to the GPL, version 2.
5 * Parts derived from iw, subject to ISC license.
6 * Copyright 2007, 2008 Johannes Berg
7 * Copyright 2007 Andy Lutomirski
8 * Copyright 2007 Mike Kershaw
9 * Copyright 2008-2009 Luis R. Rodriguez
12 #define _GNU_SOURCE
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <limits.h>
18 #include <linux/nl80211.h>
19 #include <libnl3/netlink/genl/genl.h>
20 #include <libnl3/netlink/genl/family.h>
21 #include <libnl3/netlink/genl/ctrl.h>
22 #include <libnl3/netlink/msg.h>
23 #include <libnl3/netlink/attr.h>
25 #include "die.h"
26 #include "str.h"
27 #include "xutils.h"
28 #include "mac80211.h"
29 #include "xmalloc.h"
30 #include "built_in.h"
32 struct nl80211_state {
33 struct nl_sock *nl_sock;
34 struct nl_cache *nl_cache;
35 struct genl_family *nl80211;
38 static void get_mac80211_phydev(const char *device, char *phydev_path,
39 size_t phydev_len)
41 int ret;
42 char *pathstr;
43 ssize_t num;
45 ret = asprintf(&pathstr, "/sys/class/net/%s/phy80211", device);
46 if (ret < 0)
47 panic("Can't generate path name string for /sys/class/net device");
49 num = readlink(pathstr, phydev_path, phydev_len);
50 if (num < 0) {
51 if (errno == ENOENT || errno == EINVAL)
52 panic("It's probably not a mac80211 device!\n");
53 panic("Can't readlink %s: %s!\n", pathstr, strerror(errno));
56 xfree(pathstr);
57 phydev_path[min(num, phydev_len - 1)] = 0;
60 static inline struct nl_msg *nl80211_nlmsg_xalloc(void)
62 struct nl_msg *ret = nlmsg_alloc();
63 if (!ret)
64 panic("Cannot allocate nlmsg memory!\n");
65 return ret;
68 static inline struct nl_sock *nl80211_nl_socket_xalloc(void)
70 struct nl_sock *ret = nl_socket_alloc();
71 if (!ret)
72 panic("Cannot allocate nl socket memory!\n");
73 return ret;
76 static void nl80211_init(struct nl80211_state *state, const char *device)
78 int ret;
80 state->nl_sock = nl80211_nl_socket_xalloc();
82 ret = genl_connect(state->nl_sock);
83 if (ret)
84 panic("Cannot connect generic netlink!\n");
86 ret = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache);
87 if (ret < 0)
88 panic("Failed to allocate generic netlink cache: %s!",
89 nl_geterror(-ret));
91 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
92 if (!state->nl80211)
93 panic("nl80211 not found in netlink cache!\n");
96 static void nl80211_cleanup(struct nl80211_state *state)
98 genl_family_put(state->nl80211);
100 nl_cache_free(state->nl_cache);
101 nl_socket_free(state->nl_sock);
104 static int nl80211_wait_handler(struct nl_msg *msg, void *arg)
106 int *finished = arg;
108 *finished = 1;
110 return NL_STOP;
113 static int nl80211_error_handler(struct sockaddr_nl *nla,
114 struct nlmsgerr *err,
115 void *arg)
117 panic("nl80211 returned with error %d\n", err->error);
120 static int nl80211_add_mon_if(struct nl80211_state *state, const char *device,
121 const char *mondevice)
123 int ifindex, ret;
124 struct nl_msg *msg;
125 struct nl_cb *cb = NULL;
126 int finished = 0;
128 ifindex = device_ifindex(device);
130 msg = nl80211_nlmsg_xalloc();
132 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
133 0, NL80211_CMD_NEW_INTERFACE, 0);
135 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
136 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice);
137 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
139 ret = nl_send_auto_complete(state->nl_sock, msg);
140 if (ret < 0) {
141 if (ret == -ENFILE) {
142 nlmsg_free(msg);
143 return -EBUSY;
146 panic("Cannot send_auto_complete!\n");
149 cb = nl_cb_alloc(NL_CB_CUSTOM);
150 if (!cb)
151 panic("Cannot alloc nl_cb!\n");
153 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_wait_handler, &finished);
154 nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_handler, NULL);
156 nl_recvmsgs(state->nl_sock, cb);
158 if (!finished) {
159 ret = nl_wait_for_ack(state->nl_sock);
160 if (ret < 0) {
161 if (ret == -ENFILE) {
162 nlmsg_free(msg);
163 return -EBUSY;
166 panic("Waiting for netlink ack failed!\n");
170 nl_cb_put(cb);
171 nlmsg_free(msg);
172 return 0;
174 nla_put_failure:
175 panic("nla put failure!\n");
176 return -EIO; /* dummy */
179 static int nl80211_del_mon_if(struct nl80211_state *state, const char *device,
180 const char *mondevice)
182 int ifindex, ret;
183 struct nl_msg *msg;
185 ifindex = device_ifindex(mondevice);
187 msg = nl80211_nlmsg_xalloc();
189 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
190 0, NL80211_CMD_DEL_INTERFACE, 0);
192 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
194 ret = nl_send_auto_complete(state->nl_sock, msg);
195 if (ret < 0)
196 panic("Cannot send_auto_complete!\n");
198 ret = nl_wait_for_ack(state->nl_sock);
199 if (ret < 0)
200 panic("Waiting for netlink ack failed!\n");
202 nlmsg_free(msg);
203 return 0;
205 nla_put_failure:
206 panic("nla put failure!\n");
207 return -EIO; /* dummy */
210 void enter_rfmon_mac80211(const char *device, char **mondev)
212 int ret;
213 short flags;
214 uint32_t n;
215 char phydev_path[256];
216 struct nl80211_state nlstate;
218 /* XXX: is this already a monN device? */
219 get_mac80211_phydev(device, phydev_path, sizeof(phydev_path));
220 nl80211_init(&nlstate, device);
222 for (n = 0; n < UINT_MAX; n++) {
223 char mondevice[32];
225 slprintf(mondevice, sizeof(mondevice), "mon%u", n);
226 ret = nl80211_add_mon_if(&nlstate, device, mondevice);
227 if (ret == 0) {
228 *mondev = xstrdup(mondevice);
230 flags = device_get_flags(*mondev);
231 flags |= IFF_UP | IFF_RUNNING;
232 device_set_flags(*mondev, flags);
234 nl80211_cleanup(&nlstate);
235 return;
239 panic("No free monN interfaces!\n");
242 void leave_rfmon_mac80211(const char *device, const char *mondev)
244 short flags;
245 struct nl80211_state nlstate;
247 flags = device_get_flags(mondev);
248 flags &= ~(IFF_UP | IFF_RUNNING);
249 device_set_flags(mondev, flags);
251 nl80211_init(&nlstate, device);
252 nl80211_del_mon_if(&nlstate, device, mondev);
253 nl80211_cleanup(&nlstate);