📄 driver_nl80211.c
字号:
/* * hostapd / Kernel driver communication via nl80211 * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> * Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include <sys/ioctl.h>#include <netlink/genl/genl.h>#include <netlink/genl/family.h>#include <netlink/genl/ctrl.h>#include <netlink/msg.h>#include <netlink/attr.h>#include "nl80211_copy.h"#include <net/if.h>#include <netpacket/packet.h>#include "wireless_copy.h"#include <linux/filter.h>#include <net/if_arp.h>#include "hostapd.h"#include "driver.h"#include "ieee802_1x.h"#include "eloop.h"#include "ieee802_11.h"#include "sta_info.h"#include "hw_features.h"#include "mlme.h"#include "radiotap.h"#include "radiotap_iter.h"#ifdef CONFIG_LIBNL20/* libnl 2.0 compatibility code */#define nl_handle_alloc_cb nl_socket_alloc_cb#define nl_handle_destroy nl_socket_free#endif /* CONFIG_LIBNL20 */enum ieee80211_msg_type { ieee80211_msg_normal = 0, ieee80211_msg_tx_callback_ack = 1, ieee80211_msg_tx_callback_fail = 2,};struct i802_driver_data { struct hostapd_data *hapd; char iface[IFNAMSIZ + 1]; int bridge; int ioctl_sock; /* socket for ioctl() use */ int wext_sock; /* socket for wireless events */ int eapol_sock; /* socket for EAPOL frames */ int monitor_sock; /* socket for monitor */ int monitor_ifidx; int default_if_indices[16]; int *if_indices; int num_if_indices; int we_version; struct nl_handle *nl_handle; struct nl_cache *nl_cache; struct nl_cb *nl_cb; struct genl_family *nl80211; int dtim_period, beacon_int; unsigned int beacon_set:1; unsigned int ieee802_1x_active:1; int last_freq; int last_freq_ht;};static void add_ifidx(struct i802_driver_data *drv, int ifidx){ int i; int *old; for (i = 0; i < drv->num_if_indices; i++) { if (drv->if_indices[i] == 0) { drv->if_indices[i] = ifidx; return; } } if (drv->if_indices != drv->default_if_indices) old = drv->if_indices; else old = NULL; drv->if_indices = realloc(old, sizeof(int) * (drv->num_if_indices + 1)); if (!drv->if_indices) { if (!old) drv->if_indices = drv->default_if_indices; else drv->if_indices = old; wpa_printf(MSG_ERROR, "Failed to reallocate memory for " "interfaces"); wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); return; } drv->if_indices[drv->num_if_indices] = ifidx; drv->num_if_indices++;}static void del_ifidx(struct i802_driver_data *drv, int ifidx){ int i; for (i = 0; i < drv->num_if_indices; i++) { if (drv->if_indices[i] == ifidx) { drv->if_indices[i] = 0; break; } }}static int have_ifidx(struct i802_driver_data *drv, int ifidx){ int i; if (ifidx == drv->bridge) return 1; for (i = 0; i < drv->num_if_indices; i++) if (drv->if_indices[i] == ifidx) return 1; return 0;}/* nl80211 code */static int ack_handler(struct nl_msg *msg, void *arg){ int *err = arg; *err = 0; return NL_STOP;}static int finish_handler(struct nl_msg *msg, void *arg){ int *ret = arg; *ret = 0; return NL_SKIP;}static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg){ int *ret = arg; *ret = err->error; return NL_SKIP;}static int send_and_recv_msgs(struct i802_driver_data *drv, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data){ struct nl_cb *cb; int err = -ENOMEM; cb = nl_cb_clone(drv->nl_cb); if (!cb) goto out; err = nl_send_auto_complete(drv->nl_handle, msg); if (err < 0) goto out; err = 1; nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); if (valid_handler) nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data); while (err > 0) nl_recvmsgs(drv->nl_handle, cb); out: nl_cb_put(cb); nlmsg_free(msg); return err;}static int hostapd_set_iface_flags(struct i802_driver_data *drv, const char *ifname, int dev_up){ struct ifreq ifr; if (drv->ioctl_sock < 0) return -1; memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { perror("ioctl[SIOCGIFFLAGS]"); wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)", drv->iface); return -1; } if (dev_up) ifr.ifr_flags |= IFF_UP; else ifr.ifr_flags &= ~IFF_UP; if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { perror("ioctl[SIOCSIFFLAGS]"); return -1; } return 0;}static int nl_set_encr(int ifindex, struct i802_driver_data *drv, const char *alg, const u8 *addr, int idx, const u8 *key, size_t key_len, int txkey){ struct nl_msg *msg; int ret; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; if (strcmp(alg, "none") == 0) { genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_DEL_KEY, 0); } else { genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_NEW_KEY, 0); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); if (strcmp(alg, "WEP") == 0) { if (key_len == 5) NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC01); else NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC05); } else if (strcmp(alg, "TKIP") == 0) NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); else if (strcmp(alg, "CCMP") == 0) NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); else if (strcmp(alg, "IGTK") == 0) NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06); else { wpa_printf(MSG_ERROR, "%s: Unsupported encryption " "algorithm '%s'", __func__, alg); nlmsg_free(msg); return -1; } } if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret == -ENOENT) ret = 0; /* * If we failed or don't need to set the default TX key (below), * we're done here. */ if (ret || !txkey || addr) return ret; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_KEY, 0); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (strcmp(alg, "IGTK") == 0) NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); else NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret == -ENOENT) ret = 0; return ret; nla_put_failure: return -ENOBUFS;}static int i802_set_encryption(const char *iface, void *priv, const char *alg, const u8 *addr, int idx, const u8 *key, size_t key_len, int txkey){ struct i802_driver_data *drv = priv; int ret; ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, idx, key, key_len, txkey); if (ret < 0) return ret; return ret;}static inline int min_int(int a, int b){ if (a < b) return a; return b;}static int get_key_handler(struct nl_msg *msg, void *arg){ struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); /* * TODO: validate the key index and mac address! * Otherwise, there's a race condition as soon as * the kernel starts sending key notifications. */ if (tb[NL80211_ATTR_KEY_SEQ]) memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); return NL_SKIP;}static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, int idx, u8 *seq){ struct i802_driver_data *drv = priv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_GET_KEY, 0); if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); memset(seq, 0, 6); return send_and_recv_msgs(drv, msg, get_key_handler, seq); nla_put_failure: return -ENOBUFS;}static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, int mode){ struct i802_driver_data *drv = priv; struct nl_msg *msg; u8 rates[NL80211_MAX_SUPP_RATES]; u8 rates_len = 0; int i; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_BSS, 0); for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) rates[rates_len++] = basic_rates[i] / 5; NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); /* TODO: multi-BSS support */ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: return -ENOBUFS;}static int i802_send_frame(void *priv, const void *data, size_t len, int encrypt, int flags){ __u8 rtap_hdr[] = { 0x00, 0x00, /* radiotap version */ 0x0e, 0x00, /* radiotap length */ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ 0x00, /* padding */ 0x00, 0x00, /* RX and TX flags to indicate that */ 0x00, 0x00, /* this is the injected frame directly */ }; struct i802_driver_data *drv = priv; struct iovec iov[2] = { { .iov_base = &rtap_hdr, .iov_len = sizeof(rtap_hdr), }, { .iov_base = (void*)data, .iov_len = len, } }; struct msghdr msg = { .msg_name = NULL, .msg_namelen = 0, .msg_iov = iov, .msg_iovlen = 2, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0, }; if (encrypt) rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; return sendmsg(drv->monitor_sock, &msg, flags);}static int i802_send_mgmt_frame(void *priv, const void *data, size_t len, int flags){ struct ieee80211_mgmt *mgmt; int do_not_encrypt = 0; u16 fc; mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { /* * Only one of the authentication frame types is encrypted. * In order for static WEP encryption to work properly (i.e., * to not encrypt the frame), we need to tell mac80211 about * the frames that must not be encrypted. */ u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); if (auth_alg == WLAN_AUTH_OPEN || (auth_alg == WLAN_AUTH_SHARED_KEY && auth_trans != 3)) do_not_encrypt = 1; } return i802_send_frame(priv, data, len, !do_not_encrypt, flags);}/* Set kernel driver on given frequency (MHz) */static int i802_set_freq2(void *priv, struct hostapd_freq_params *freq){ struct i802_driver_data *drv = priv; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; drv->last_freq = freq->freq; drv->last_freq_ht = freq->ht_enabled; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_WIPHY, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq); if (freq->ht_enabled) { switch (freq->sec_channel_offset) { case -1: NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS); break; case 1: NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS); break; default: NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20); break; } } if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) return 0; nla_put_failure: return -1;}static int i802_set_rts(void *priv, int rts){ struct i802_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); iwr.u.rts.value = rts; iwr.u.rts.fixed = 1; if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) { perror("ioctl[SIOCSIWRTS]"); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -