netsniff-ng: remove unnecessary zeroing of packet counters in init_ctx()
[netsniff-ng.git] / mac80211.c
blob9aea5a0e6a7b07c9322b731fce01670c512b5845
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 <sys/socket.h>
19 #include <linux/if.h>
20 #include <linux/nl80211.h>
21 #include <netlink/genl/genl.h>
22 #include <netlink/genl/family.h>
23 #include <netlink/genl/ctrl.h>
24 #include <netlink/msg.h>
25 #include <netlink/attr.h>
27 #include "str.h"
28 #include "dev.h"
29 #include "mac80211.h"
30 #include "xmalloc.h"
31 #include "built_in.h"
33 struct nl80211_state {
34 struct nl_sock *nl_sock;
35 struct nl_cache *nl_cache;
36 struct genl_family *nl80211;
39 static void get_mac80211_phydev(const char *device, char *phydev_path,
40 size_t phydev_len)
42 int ret;
43 char *pathstr;
44 ssize_t num;
46 ret = asprintf(&pathstr, "/sys/class/net/%s/phy80211", device);
47 if (ret < 0)
48 panic("Can't generate path name string for /sys/class/net device");
50 num = readlink(pathstr, phydev_path, phydev_len);
51 if (num < 0) {
52 if (errno == ENOENT || errno == EINVAL)
53 panic("It's probably not a mac80211 device!\n");
54 panic("Can't readlink %s: %s!\n", pathstr, strerror(errno));
57 xfree(pathstr);
58 phydev_path[min_t(size_t, num, phydev_len - 1)] = 0;
61 static inline struct nl_msg *nl80211_nlmsg_xalloc(void)
63 struct nl_msg *ret = nlmsg_alloc();
64 if (!ret)
65 panic("Cannot allocate nlmsg memory!\n");
66 return ret;
69 static inline struct nl_sock *nl80211_nl_socket_xalloc(void)
71 struct nl_sock *ret = nl_socket_alloc();
72 if (!ret)
73 panic("Cannot allocate nl socket memory!\n");
74 return ret;
77 static void nl80211_init(struct nl80211_state *state)
79 int ret;
81 state->nl_sock = nl80211_nl_socket_xalloc();
83 ret = genl_connect(state->nl_sock);
84 if (ret)
85 panic("Cannot connect generic netlink!\n");
87 ret = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache);
88 if (ret < 0)
89 panic("Failed to allocate generic netlink cache: %s!",
90 nl_geterror(-ret));
92 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
93 if (!state->nl80211)
94 panic("nl80211 not found in netlink cache!\n");
97 static void nl80211_cleanup(struct nl80211_state *state)
99 genl_family_put(state->nl80211);
101 nl_cache_free(state->nl_cache);
102 nl_socket_free(state->nl_sock);
105 static int nl80211_wait_handler(struct nl_msg *msg __maybe_unused, void *arg)
107 int *finished = arg;
109 *finished = 1;
111 return NL_STOP;
114 static int nl80211_error_handler(struct sockaddr_nl *nla __maybe_unused,
115 struct nlmsgerr *err,
116 void *arg __maybe_unused)
118 panic("nl80211 returned with error (%d): %s\n", err->error,
119 nl_geterror(err->error));
122 static int nl80211_add_mon_if(struct nl80211_state *state, const char *device,
123 const char *mondevice)
125 int ifindex, ret;
126 struct nl_msg *msg;
127 struct nl_cb *cb = NULL;
128 int finished = 0;
130 ifindex = device_ifindex(device);
132 msg = nl80211_nlmsg_xalloc();
134 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
135 0, NL80211_CMD_NEW_INTERFACE, 0);
137 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
138 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice);
139 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
141 ret = nl_send_auto_complete(state->nl_sock, msg);
142 if (ret < 0) {
143 if (ret == -ENFILE) {
144 nlmsg_free(msg);
145 return -EBUSY;
148 panic("Cannot send_auto_complete!\n");
151 cb = nl_cb_alloc(NL_CB_CUSTOM);
152 if (!cb)
153 panic("Cannot alloc nl_cb!\n");
155 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_wait_handler, &finished);
156 nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_handler, NULL);
158 nl_recvmsgs(state->nl_sock, cb);
160 if (!finished) {
161 ret = nl_wait_for_ack(state->nl_sock);
162 if (ret < 0) {
163 if (ret == -ENFILE) {
164 nlmsg_free(msg);
165 return -EBUSY;
168 panic("Waiting for netlink ack failed!\n");
172 nl_cb_put(cb);
173 nlmsg_free(msg);
174 return 0;
176 nla_put_failure:
177 panic("nla put failure!\n");
178 return -EIO; /* dummy */
181 static int nl80211_del_mon_if(struct nl80211_state *state,
182 const char *mondevice)
184 int ifindex, ret;
185 struct nl_msg *msg;
187 ifindex = device_ifindex(mondevice);
189 msg = nl80211_nlmsg_xalloc();
191 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
192 0, NL80211_CMD_DEL_INTERFACE, 0);
194 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
196 ret = nl_send_auto_complete(state->nl_sock, msg);
197 if (ret < 0)
198 panic("Cannot send_auto_complete!\n");
200 ret = nl_wait_for_ack(state->nl_sock);
201 if (ret < 0)
202 panic("Waiting for netlink ack failed!\n");
204 nlmsg_free(msg);
205 return 0;
207 nla_put_failure:
208 panic("nla put failure!\n");
209 return -EIO; /* dummy */
212 void enter_rfmon_mac80211(const char *device, char **mondev)
214 int ret;
215 short flags;
216 uint32_t n;
217 char phydev_path[256];
218 struct nl80211_state nlstate;
220 /* XXX: is this already a monN device? */
221 get_mac80211_phydev(device, phydev_path, sizeof(phydev_path));
222 nl80211_init(&nlstate);
224 for (n = 0; n < UINT_MAX; n++) {
225 char mondevice[32];
227 slprintf(mondevice, sizeof(mondevice), "mon%u", n);
229 if (__device_ifindex(mondevice) > 0)
230 continue;
232 ret = nl80211_add_mon_if(&nlstate, device, mondevice);
233 if (ret == 0) {
234 *mondev = xstrdup(mondevice);
236 flags = device_get_flags(*mondev);
237 flags |= IFF_UP | IFF_RUNNING;
238 device_set_flags(*mondev, flags);
240 nl80211_cleanup(&nlstate);
241 return;
245 panic("No free monN interfaces!\n");
248 void leave_rfmon_mac80211(const char *mondev)
250 short flags;
251 struct nl80211_state nlstate;
253 flags = device_get_flags(mondev);
254 flags &= ~(IFF_UP | IFF_RUNNING);
255 device_set_flags(mondev, flags);
257 nl80211_init(&nlstate);
258 nl80211_del_mon_if(&nlstate, mondev);
259 nl80211_cleanup(&nlstate);