X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=hostapd%2Fdriver_nl80211.c;h=78b9a55ae84fc99bc0c08f480ea80883953f4146;hb=f82ef4d8dba197a96592fcf30da62606becdf18a;hp=ff59ac87fcba43b9113390c729e61130b390b62b;hpb=f72750896c714cb8c06d82f9038f23295b8a30d5;p=wpasupplicant diff --git a/hostapd/driver_nl80211.c b/hostapd/driver_nl80211.c index ff59ac8..78b9a55 100644 --- a/hostapd/driver_nl80211.c +++ b/hostapd/driver_nl80211.c @@ -31,6 +31,7 @@ #include #include "hostapd.h" +#include "config.h" #include "driver.h" #include "eloop.h" #include "hw_features.h" @@ -54,6 +55,12 @@ enum ieee80211_msg_type { ieee80211_msg_tx_callback_fail = 2, }; +struct i802_bss { + struct i802_bss *next; + char iface[IFNAMSIZ + 1]; + unsigned int beacon_set:1; +}; + struct i802_driver_data { struct hostapd_data *hapd; @@ -74,9 +81,8 @@ struct i802_driver_data { 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 beacon_int; + struct i802_bss bss; unsigned int ht_40mhz_scan:1; int last_freq; @@ -90,6 +96,20 @@ static int i802_sta_deauth(void *priv, const u8 *addr, int reason); static int i802_sta_disassoc(void *priv, const u8 *addr, int reason); +static struct i802_bss * get_bss(struct i802_driver_data *drv, + const char *iface) +{ + struct i802_bss *bss = &drv->bss; + while (bss) { + if (os_strncmp(iface, bss->iface, IFNAMSIZ) == 0) + return bss; + bss = bss->next; + } + wpa_printf(MSG_DEBUG, "nl80211: get_bss(%s) failed", iface); + return NULL; +} + + static void add_ifidx(struct i802_driver_data *drv, int ifidx) { int i; @@ -242,7 +262,7 @@ static int hostapd_set_iface_flags(struct i802_driver_data *drv, static int nl_set_encr(int ifindex, struct i802_driver_data *drv, - const char *alg, const u8 *addr, int idx, const u8 *key, + wpa_alg alg, const u8 *addr, int idx, const u8 *key, size_t key_len, int txkey) { struct nl_msg *msg; @@ -252,29 +272,34 @@ static int nl_set_encr(int ifindex, struct i802_driver_data *drv, if (!msg) return -ENOMEM; - if (strcmp(alg, "none") == 0) { + if (alg == WPA_ALG_NONE) { 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) { + switch (alg) { + case WPA_ALG_WEP: 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) + break; + case WPA_ALG_TKIP: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); - else if (strcmp(alg, "CCMP") == 0) + break; + case WPA_ALG_CCMP: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); - else if (strcmp(alg, "IGTK") == 0) + break; + case WPA_ALG_IGTK: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06); - else { + break; + default: wpa_printf(MSG_ERROR, "%s: Unsupported encryption " - "algorithm '%s'", __func__, alg); + "algorithm %d", __func__, alg); nlmsg_free(msg); return -1; } @@ -304,7 +329,7 @@ static int nl_set_encr(int ifindex, struct i802_driver_data *drv, 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) + if (alg == WPA_ALG_IGTK) NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); else NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); @@ -318,15 +343,15 @@ static int nl_set_encr(int ifindex, struct i802_driver_data *drv, } -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) +static int i802_set_key(const char *iface, void *priv, wpa_alg alg, + const u8 *addr, int key_idx, int set_tx, const u8 *seq, + size_t seq_len, const u8 *key, size_t key_len) { struct i802_driver_data *drv = priv; int ret; - ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, idx, key, - key_len, txkey); + ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, key_idx, key, + key_len, set_tx); if (ret < 0) return ret; @@ -487,7 +512,7 @@ static int i802_send_mgmt_frame(void *priv, const void *data, size_t len, } /* Set kernel driver on given frequency (MHz) */ -static int i802_set_freq2(void *priv, struct hostapd_freq_params *freq) +static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) { struct i802_driver_data *drv = priv; struct nl_msg *msg; @@ -547,25 +572,6 @@ static int i802_set_rts(void *priv, int rts) } -static int i802_get_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->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) { - perror("ioctl[SIOCGIWRTS]"); - return -1; - } - - *rts = iwr.u.rts.value; - - return 0; -} - - static int i802_set_frag(void *priv, int frag) { struct i802_driver_data *drv = priv; @@ -585,25 +591,6 @@ static int i802_set_frag(void *priv, int frag) } -static int i802_get_frag(void *priv, int *frag) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG]"); - return -1; - } - - *frag = iwr.u.frag.value; - - return 0; -} - - static int i802_set_retry(void *priv, int short_retry, int long_retry) { struct i802_driver_data *drv = priv; @@ -630,32 +617,6 @@ static int i802_set_retry(void *priv, int short_retry, int long_retry) } -static int i802_get_retry(void *priv, int *short_retry, int *long_retry) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; - if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG(short)]"); - return -1; - } - *short_retry = iwr.u.retry.value; - - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG(long)]"); - return -1; - } - *long_retry = iwr.u.retry.value; - - return 0; -} - - static int i802_flush(void *priv) { struct i802_driver_data *drv = priv; @@ -822,8 +783,8 @@ static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data, } -static int i802_sta_add2(const char *ifname, void *priv, - struct hostapd_sta_add_params *params) +static int i802_sta_add(const char *ifname, void *priv, + struct hostapd_sta_add_params *params) { struct i802_driver_data *drv = priv; struct nl_msg *msg; @@ -913,7 +874,7 @@ static int i802_sta_set_flags(void *priv, const u8 *addr, if_nametoindex(drv->iface)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active) + if (total_flags & WLAN_STA_AUTHORIZED) NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); if (total_flags & WLAN_STA_WMM) @@ -1088,47 +1049,72 @@ static int nl80211_create_iface(struct i802_driver_data *drv, static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid) { + struct i802_driver_data *drv = priv; int ifidx; + struct i802_bss *bss; - /* - * The kernel supports that when the low-level driver does, - * but we currently don't because we need per-BSS data that - * currently we can't handle easily. - */ - return -1; + bss = os_zalloc(sizeof(*bss)); + if (bss == NULL) + return -1; + os_strlcpy(bss->iface, ifname, IFNAMSIZ); ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid); - if (ifidx < 0) + if (ifidx < 0) { + os_free(bss); return -1; + } if (hostapd_set_iface_flags(priv, ifname, 1)) { nl80211_remove_iface(priv, ifidx); + os_free(bss); return -1; } + bss->next = drv->bss.next; + drv->bss.next = bss; return 0; } static int i802_bss_remove(void *priv, const char *ifname) { + struct i802_driver_data *drv = priv; + struct i802_bss *bss, *prev; nl80211_remove_iface(priv, if_nametoindex(ifname)); + prev = &drv->bss; + bss = drv->bss.next; + while (bss) { + if (os_strncmp(ifname, bss->iface, IFNAMSIZ) == 0) { + prev->next = bss->next; + os_free(bss); + break; + } + prev = bss; + bss = bss->next; + } return 0; } static int i802_set_beacon(const char *iface, void *priv, - u8 *head, size_t head_len, - u8 *tail, size_t tail_len) + const u8 *head, size_t head_len, + const u8 *tail, size_t tail_len, int dtim_period) { struct i802_driver_data *drv = priv; struct nl_msg *msg; u8 cmd = NL80211_CMD_NEW_BEACON; int ret; + struct i802_bss *bss; + + bss = get_bss(drv, iface); + if (bss == NULL) + return -ENOENT; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; - if (drv->beacon_set) + wpa_printf(MSG_DEBUG, "nl80211: Set beacon (iface=%s beacon_set=%d)", + iface, bss->beacon_set); + if (bss->beacon_set) cmd = NL80211_CMD_SET_BEACON; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, @@ -1137,14 +1123,11 @@ static int i802_set_beacon(const char *iface, void *priv, NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int); - - if (!drv->dtim_period) - drv->dtim_period = 2; - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); + NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (!ret) - drv->beacon_set = 1; + bss->beacon_set = 1; return ret; nla_put_failure: return -ENOBUFS; @@ -1169,42 +1152,6 @@ static int i802_del_beacon(struct i802_driver_data *drv) } -static int i802_set_ieee8021x(const char *ifname, void *priv, int enabled) -{ - struct i802_driver_data *drv = priv; - - /* - * FIXME: This needs to be per interface (BSS) - */ - drv->ieee802_1x_active = enabled; - return 0; -} - - -static int i802_set_privacy(const char *ifname, void *priv, int enabled) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - - os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); - iwr.u.param.flags = IW_AUTH_PRIVACY_INVOKED; - iwr.u.param.value = enabled; - - ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr); - - /* ignore errors, the kernel/driver might not care */ - return 0; -} - - -static int i802_set_internal_bridge(void *priv, int value) -{ - return -1; -} - - static int i802_set_beacon_int(void *priv, int value) { struct i802_driver_data *drv = priv; @@ -1212,13 +1159,15 @@ static int i802_set_beacon_int(void *priv, int value) drv->beacon_int = value; - if (!drv->beacon_set) + if (!drv->bss.beacon_set) return 0; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; + wpa_printf(MSG_DEBUG, "nl80211: Set beacon interval %d " + "(beacon_set=%d)", value, drv->bss.beacon_set); genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_BEACON, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); @@ -1231,28 +1180,6 @@ static int i802_set_beacon_int(void *priv, int value) } -static int i802_set_dtim_period(const char *iface, void *priv, int value) -{ - 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_SET_BEACON, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - - drv->dtim_period = value; - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - static int i802_set_bss(void *priv, int cts, int preamble, int slot) { struct i802_driver_data *drv = priv; @@ -1804,7 +1731,6 @@ static void handle_frame(struct i802_driver_data *drv, static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) { struct i802_driver_data *drv = eloop_ctx; - struct hostapd_data *hapd = drv->hapd; struct sockaddr_ll lladdr; unsigned char buf[3000]; int len; @@ -1817,8 +1743,13 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) return; } - if (have_ifidx(drv, lladdr.sll_ifindex)) + if (have_ifidx(drv, lladdr.sll_ifindex)) { + struct hostapd_data *hapd; + hapd = hostapd_sta_get_bss(drv->hapd, lladdr.sll_addr); + if (!hapd) + return; hostapd_eapol_receive(hapd, lladdr.sll_addr, buf, len); + } } @@ -2506,7 +2437,6 @@ static int i802_ht_scan(struct i802_driver_data *drv) static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid) { struct ifreq ifr; - struct sockaddr_ll addr; drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); if (drv->ioctl_sock < 0) { @@ -2593,12 +2523,6 @@ static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid) if (hostapd_set_iface_flags(drv, drv->iface, 1)) goto fail1; - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); if (drv->eapol_sock < 0) { perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); @@ -2738,7 +2662,7 @@ static void hostapd_wireless_event_rtm_newlink(struct i802_driver_data *drv, struct nlmsghdr *h, int len) { struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; + int attrlen, _nlmsg_len, rta_len; struct rtattr *attr; if (len < (int) sizeof(*ifi)) @@ -2749,13 +2673,13 @@ static void hostapd_wireless_event_rtm_newlink(struct i802_driver_data *drv, /* TODO: use ifi->ifi_index to filter out wireless events from other * interfaces */ - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); + _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - attrlen = h->nlmsg_len - nlmsg_len; + attrlen = h->nlmsg_len - _nlmsg_len; if (attrlen < 0) return; - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); + attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len); rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { @@ -2863,9 +2787,8 @@ static int hostap_get_we_version(struct i802_driver_data *drv) } -static int i802_wireless_event_init(void *priv) +static int i802_wireless_event_init(struct i802_driver_data *drv) { - struct i802_driver_data *drv = priv; int s; struct sockaddr_nl local; @@ -2896,9 +2819,8 @@ static int i802_wireless_event_init(void *priv) } -static void i802_wireless_event_deinit(void *priv) +static void i802_wireless_event_deinit(struct i802_driver_data *drv) { - struct i802_driver_data *drv = priv; if (drv->wext_sock < 0) return; eloop_unregister_read_sock(drv->wext_sock); @@ -2961,6 +2883,7 @@ static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid) drv->hapd = hapd; memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); + memcpy(drv->bss.iface, hapd->conf->iface, sizeof(drv->iface)); drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); drv->if_indices = drv->default_if_indices; @@ -2970,6 +2893,9 @@ static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid) if (i802_init_sockets(drv, bssid)) goto failed; + if (i802_wireless_event_init(drv)) + goto failed; + return drv; failed: @@ -2987,13 +2913,16 @@ static void *i802_init(struct hostapd_data *hapd) static void i802_deinit(void *priv) { struct i802_driver_data *drv = priv; + struct i802_bss *bss, *prev; + + i802_wireless_event_deinit(drv); if (drv->last_freq_ht) { /* Clear HT flags from the driver */ struct hostapd_freq_params freq; os_memset(&freq, 0, sizeof(freq)); freq.freq = drv->last_freq; - i802_set_freq2(priv, &freq); + i802_set_freq(priv, &freq); } i802_del_beacon(drv); @@ -3023,20 +2952,24 @@ static void i802_deinit(void *priv) free(drv->if_indices); os_free(drv->neighbors); + + bss = drv->bss.next; + while (bss) { + prev = bss; + bss = bss->next; + os_free(bss); + } + free(drv); } -const struct wpa_driver_ops wpa_driver_nl80211_ops = { +const struct hapd_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .init = i802_init, .init_bssid = i802_init_bssid, .deinit = i802_deinit, - .wireless_event_init = i802_wireless_event_init, - .wireless_event_deinit = i802_wireless_event_deinit, - .set_ieee8021x = i802_set_ieee8021x, - .set_privacy = i802_set_privacy, - .set_encryption = i802_set_encryption, + .set_key = i802_set_key, .get_seqnum = i802_get_seqnum, .flush = i802_flush, .read_sta_data = i802_read_sta_data, @@ -3046,21 +2979,16 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .sta_disassoc = i802_sta_disassoc, .sta_remove = i802_sta_remove, .send_mgmt_frame = i802_send_mgmt_frame, - .sta_add2 = i802_sta_add2, + .sta_add = i802_sta_add, .get_inact_sec = i802_get_inact_sec, .sta_clear_stats = i802_sta_clear_stats, - .set_freq2 = i802_set_freq2, + .set_freq = i802_set_freq, .set_rts = i802_set_rts, - .get_rts = i802_get_rts, .set_frag = i802_set_frag, - .get_frag = i802_get_frag, .set_retry = i802_set_retry, - .get_retry = i802_get_retry, .set_rate_sets = i802_set_rate_sets, .set_beacon = i802_set_beacon, - .set_internal_bridge = i802_set_internal_bridge, .set_beacon_int = i802_set_beacon_int, - .set_dtim_period = i802_set_dtim_period, .set_cts_protect = i802_set_cts_protect, .set_preamble = i802_set_preamble, .set_short_slot_time = i802_set_short_slot_time,